How to draw a PDF to a CGContext with a higher resolution? - iphone

I wrote a view to render a PDF Page:
-(UIPDFRenderView*) initWithFrame:(CGRect)frame withDocument:(CGPDFDocumentRef*)document withPageNumber:(int)pageNumber
{
if (self)
{
page = CGPDFDocumentGetPage (*document, pageNumber);
pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
pdfScale = (CGRectGetWidth(frame)/pageRect.size.width);
rect = frame;
self = [super initWithFrame:CGRectMake(CGRectGetMinX(frame),
CGRectGetMinY(frame),
CGRectGetWidth(frame),
CGRectGetHeight(pageRect) * pdfScale)];
}
return self;
}
-(void) drawRect:(CGRect)rect
{
[self displayPDFPageWithContext:UIGraphicsGetCurrentContext()];
}
-(void) displayPDFPageWithContext:(CGContextRef)context
{
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context, self.bounds);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, pdfScale,-1*pdfScale);
CGContextDrawPDFPage (context, page);
}
I use one of that view for every page of a pdf document and add them to a acrollview.
The problem is if i zoom in, the page is pixelig. No surprise because i am using the screen context to render the pdf. Is there any posibility to render that pdf with the double resolution to enable zoomin to a factor of 2?

Okay i got the solution, i render it in original size and initiate the scollview with a low scale that the width of the pdf fits with the width of the scrollview. With that methode i can zoom till original size (scale of 1).

Related

pdf generated upside down

I am creating pdf using below code
UIImage *CurImage=[UIImage imageWithContentsOfFile:[ImageArr objectAtIndex:i]];
UIView *ViewDraw=[[UIView alloc]initWithFrame:CGRectMake(0,10, pageSize, pageSize)];
ViewDraw.backgroundColor=[UIColor clearColor];
CGContextBeginPage (pdfContext,nil);
//turn PDF upsidedown
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0,CurImage.size.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(pdfContext, transform);
int y = (pageSize - CurImage.size.height)/2;
int x = (pageSize - CurImage.size.width)/2;
[CurImage drawInRect:CGRectMake( (ViewDraw.frame.width - curImage.frame.width)/2, 24, size.width, curImage.frame.height)];
// CGContextDrawImage(pdfContext, CGRectMake(x,-y, CurImage.size.width, CurImage.size.height), CurImage.CGImage);
CGContextEndPage (pdfContext);
CurImage=nil;
but it is generating upside down i.e.180 degree with mirror image.
What is wrong here?
Turn PDF upside-down:
CGAffineTransform aCgAffTrans = CGAffineTransformMakeTranslation(0,892); //here the whole PDF page height should be given
aCgAffTrans = CGAffineTransformScale(aCgAffTrans, 1.0, -1.0);
CGContextConcatCTM(aCgPDFContextRef, aCgAffTrans);
Your are providing some random height while some part gets turned down and others remains the same. So a mirror like effect appears.

Crash on rendering pdf page in CA Tiled layer

I am trying to render pdf pages on CGContext by converting them into images and then rendering them in tiled layer. The application runs well on simulator but crashes on device for particular pdf page. On running the app on istruments, it seems to consume a lot of memory.
There have been many questions on this before on this platform and have tried all the solution but the problem persists. Please find the code below. It always crashes on calling CGContextDrawPDFPage
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
pdfScale = self.frame.size.width/pageRect.size.width;
originalPdfScale = 2 * pdfScale;
//pdfScale = 1.39444;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
//---Create a low res image representation of the PDF page to display before the TiledPDFView renders its content---
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//---First fill the background with white---
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
NSLog(#"context = %# :::: pdfScale = %f ::::: page=%# ", context, pdfScale, page );
CGContextSaveGState(context);
//---Flip the context so that the PDF page is rendered right side up---
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
//---Scale the context so that the PDF page is rendered at the correct size for the zoom level---
CGContextScaleCTM(context, pdfScale,pdfScale);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (backgroundImageView) {
[backgroundImageView removeFromSuperview];
[backgroundImageView release];
backgroundImageView = nil;
}
backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
backgroundImageView.frame = pageRect;
backgroundImageView.userInteractionEnabled =YES;
backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:backgroundImageView];
[self sendSubviewToBack:backgroundImageView];
// Create the TiledPDFView based on the size of the PDF page and scale it to fit the view.
if (pdfView) {
[pdfView removeFromSuperview];
[pdfView release];
pdfView = nil;
}
pdfView = [[ProM_TiledPDFView alloc] initWithFrame:pageRect andScale:pdfScale];
[pdfView setPage:page];
[self addSubview:pdfView];
[backgroundImage release];

Contex Drawing + Pagination

I am trying to draw contents of scrollview into a PDF context & I am facing problem with pagination.
Following Code I have used:
- (void)renderTheView:(UIView *)view inPDFContext:(CGContextRef)pdfContext
{
// Creating frame.
CGFloat heightOfPdf = [[[self attributes] objectForKey:SRCPdfHeight] floatValue];
CGFloat widthOfPdf = [[[self attributes] objectForKey:SRCPdfWidth] floatValue];
CGRect pdfFrame = CGRectMake(0, 0, widthOfPdf, heightOfPdf);
CGRect viewFrame = [view frame];
if ([view isKindOfClass:[UIScrollView class]])
{
viewFrame.size.height = ((UIScrollView *)view).contentSize.height;
[view setFrame:viewFrame];
}
// Calculates number of pages.
NSUInteger totalNumberOfPages = ceil(viewFrame.size.height/heightOfPdf);
// Start rendering.
for (NSUInteger pageNumber = 0; pageNumber<totalNumberOfPages; pageNumber++)
{
// Starts our first page.
CGContextBeginPage (pdfContext, &pdfFrame);
// Turn PDF upsidedown
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0,view.bounds.size.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(pdfContext, transform);
// Calculate amount of y to be displace.
CGFloat ty = (heightOfPdf*(pageNumber));
CGContextTranslateCTM(pdfContext,0,-ty);
[view.layer renderInContext:pdfContext];
// We are done drawing to this page, let's end it.
CGContextEndPage (pdfContext);
}
}
It creates required number of pages but places the content wrongly. Following figure explains it.
Is there anything wrong in my code?
I don't think you need the code which flips the PDF upside down. I've done this before (manual pagination, but without a scroll view) and never had to flip the context vertically. My main concern is that you are doing it on every iteration - if you have a valid reason for flipping it, you probably don't need it in the loop, but just once before the loop begins. Also the code CGContextTranslateCTM(pdfContext,0,-ty); might need to be replaced with CGContextTranslateCTM(pdfContext,0,heightOfPdf);
If that doesn't work, try UIGraphicsBeginPDFPage(); instead of CGContextBeginPage(), that's the only major difference between your code and mine.
This github project can definitely help you.
- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx {
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index + 1);
CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox),
CGContextGetClipBoundingBox(ctx));
CGContextConcatCTM(ctx, transform);
CGContextDrawPDFPage(ctx, page);
}
Found this link to render a PDF, it says about multiple pages but haven't shown an implementation. It doesnt straight away answer to your question but it tells a simpler method to render a pdf with much less translation and transforms.
Render PDF
Generate Multipage PDF
-anoop
You could consider using a UIScrollView to layout your separate PDF pages. The following method loads each PDF page in a view (PDFView) and adds it to the scroll view content in a centered fashion:
- (void) loadPDFAtPath:(NSString *)path
{
NSURL *pdfUrl = [NSURL fileURLWithPath:path];
CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfUrl);
float height = 0.0;
for(int i = 0; i < CGPDFDocumentGetNumberOfPages(document); i++) {
CGPDFPageRef page = CGPDFDocumentGetPage(document, i + 1);
PDFView *pdfView = [[PDFView alloc] initPdfViewWithPageRef:page];
CGRect pageSize = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
pv.frame = CGRectMake((self.frame.size.width / 2.0) - pageSize.size.width / 2.0, height, pageSize.size.width, pageSize.size.height);
height += pageSize.size.height + SOME_SPACE_IN_BETWEEN_PAGES;
// self is a subclass of UIScrollView
[self addSubview:pdfView];
[pdfView setNeedsDisplay];
}
CGPDFDocumentRelease(document);
[self setContentSize:CGSizeMake(self.frame.size.width, height)];
}
In this case, PDFView is responsible for rendering a single CGPDFPageRef in its drawRect or drawLayer implementation.
The portions you need to add to pdf pages put in seperate views inside the scroll and render tht view to the pdf context
OR
Just find the correct dimensions and draw using the CG method:
UIImage *Logo=[UIImage imageNamed:#"small-logo-left-top130_133.png"];
CGPoint drawingLogoOrgin = CGPointMake(5,5);
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[Logo drawAtPoint:drawingLogoOrgin];
There are a lot of drawing methods to draw pdf. You can use that to draw all the contents.
this might help you.
- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx
{
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index + 1);
CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox),
CGContextGetClipBoundingBox(ctx));
CGContextConcatCTM(ctx, transform);
CGContextDrawPDFPage(ctx, page);
}

Rendering a CGPDFPage into a UIImage

I'm trying to render a CGPDFPage (selected from a CGPDFDocument) into a UIImage to display on a view.
I have the following code in MonoTouch which gets me part way there.
RectangleF PDFRectangle = new RectangleF(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height);
public override void ViewDidLoad ()
{
UIGraphics.BeginImageContext(new SizeF(PDFRectangle.Width, PDFRectangle.Height));
CGContext context = UIGraphics.GetCurrentContext();
context.SaveState();
CGPDFDocument pdfDoc = CGPDFDocument.FromFile("test.pdf");
CGPDFPage pdfPage = pdfDoc.GetPage(1);
context.DrawPDFPage(pdfPage);
UIImage testImage = UIGraphics.GetImageFromCurrentImageContext();
pdfDoc.Dispose();
context.RestoreState();
UIImageView imageView = new UIImageView(testImage);
UIGraphics.EndImageContext();
View.AddSubview(imageView);
}
A section of the CGPDFPage is displayed but rotated back-to-front and upside down. My question is, how do I select the full pdf page and flip it round to display correctly. I have seen a few examples using ScaleCTM and TranslateCTM but couldn't seem to get them working.
Any examples in ObjectiveC are fine, I'll take all the help I can get :)
Thanks
I haven't worked with MonoTouch. However, in objective-C you would get an image for a PDF page like this (notice the CTM transforms):
-(UIImage *)getThumbForPage:(int)page_number{
CGFloat width = 60.0;
// Get the page
CGPDFPageRef myPageRef = CGPDFDocumentGetPage(myDocumentRef, page);
// Changed this line for the line above which is a generic line
//CGPDFPageRef page = [self getPage:page_number];
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGFloat pdfScale = width/pageRect.size.width;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// White BG
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
// ***********
// Next 3 lines makes the rotations so that the page look in the right direction
// ***********
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, pageRect, 0, true));
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *thm = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return thm;
}

iPhone: CoreGraphics and memory management

Can someone tell me what I am doing wrong here? I use this method to flip through pages in a PDF. But something in the code seems to not be released properly because every-time I pull a PDF page that contains an image my memory footprint increases. I am fairly new to CoreGraphics, and can't for the life of me figure out where this method would leak memory.
-(UIImage *)pageAtIndex:(NSInteger)pageNumber withWidth:(CGFloat)width andHeight:(CGFloat)height {
if((pageNumber>0) && (pageNumber<=pageCount)) {
CGFloat scaleRatio; // multiplier by which the PDF Page will be scaled
UIGraphicsBeginImageContext(CGSizeMake(width, height));
CGContextRef context = UIGraphicsGetCurrentContext();
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, pageNumber);
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFBleedBox);
//Figure out the orientation of the PDF page and set the scaleRatio accordingly
if(pageRect.size.width/pageRect.size.height < 1.0) {
scaleRatio = height/pageRect.size.height;
}
else {
scaleRatio = width/pageRect.size.width;
}
//Calculate the offset to center the image
CGFloat xOffset = 0.0;
CGFloat yOffset = height;
if(pageRect.size.width*scaleRatio<width) {
xOffset = (width/2)-(pageRect.size.width*scaleRatio/2);
}
else {
yOffset = height-((height/2)-(pageRect.size.height*scaleRatio/2));
}
CGContextTranslateCTM(context, xOffset, yOffset);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSaveGState(context);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFBleedBox, CGRectMake(0, 0, pageRect.size.width, pageRect.size.height), 0, true);
pdfTransform = CGAffineTransformScale(pdfTransform, scaleRatio, scaleRatio);
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
UIImage *tempImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndPDFContext();
UIGraphicsEndImageContext();
return tempImage;
}
return nil;
}
I think I resolved the problem thanks to the people on the apple core graphics mailing list. It seems that CGPDFDocument caches data between calls but never releases it. This appears to be a bug in CoreGraphics. I was told that the only real way around this is to load and unload the PDF every time I pull a page.
You probably weren't releasing something. Gotta check for things like CGPDFPageRetain(<CGPDFPageRef page>) and CGPDFPageRelease(<CGPDFPageRef page>).