Problem with using quartz 2d to draw a PDF - iphone

I have problem with quartz 2d to draw a pdf, I have it up and running fine
but I am not so sure how to progress to the next page
Here's the code
-(void)drawInContext:(CGContextRef)context{
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
CGContextSaveGState(context);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, self.bounds, 0, true);
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
}
I know that I can change 1 to x for to get the page but how do i redraw the frame??
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);

To make view redraw call
[view setNeedsDisplay];

Related

How to convert a pdf file to image through coding in objective c

How to convert a pdf file to image through coding in objective c
I have a pdf file, but i want to save it into photo album of iPhone, So that's why i want to convert it. If there is another way then please suggest me.
Thanks in advance.
CGPDFDocumentRef PDFfile;
CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("iPhone Sample apps.pdf"), NULL, NULL);
PDFfile = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CFRelease(pdfURL);
CGPDFPageRef page = CGPDFDocumentGetPage(PDFfile,currentpage);
context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context,self.bounds);
CGContextTranslateCTM(context, -1.0, [self bounds].size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFArtBox, [self bounds], 0, true));
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
CGImageRef imgref;
imgref=CGBitmapContextCreateImage(context);
image= [[UIImage alloc]initWithCGImage:imgref ];

Blurry PDF Drawing compared to CATiledLayer

In my application I'm creating a PDF reader. To cater for performance, I draw a view at default scale. This view is not CATiledLayer based. When user zooms in a bit, I overlay this view with a CATiledLayer one which gives much crisper image and low memory usage in normal use cases.
Now the problem is that in default state (when CALayer view is being shown) the image is coming out a bit blurry. When I try to zoom in just a wee bit and CATiledLayer kicks in, the same text and everything becomes sharp.
Here's the code for the CATiledLayer view (which shows crisp image and text as it should be):
- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)context{
CGPDFPageRef drawPDFPageRef = NULL;
CGPDFDocumentRef drawPDFDocRef = NULL;
#synchronized(self) {
if (_PDFDocRef==nil) {
NSLog(#"PDF NIL");
_PDFDocRef = [SharedPDFDocRef sharedInstanceForUrl:_fileURL andPhrase:_password];
_PDFPageRef = CGPDFDocumentGetPage(_PDFDocRef, _page);
}
drawPDFDocRef = _PDFDocRef;
drawPDFPageRef = _PDFPageRef;
}
if (drawPDFPageRef != NULL) {
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
CGAffineTransform transform =
CGPDFPageGetDrawingTransform(drawPDFPageRef, kCGPDFCropBox, layer.bounds, 0, true);
CGContextConcatCTM(context, transform);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextSetInterpolationQuality(context, kCGInterpolationDefault);
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f);
CGContextFillRect(context, CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFBleedBox));
CGContextDrawPDFPage(context, drawPDFPageRef);
}
//CGPDFPageRelease(drawPDFPageRef); CGPDFDocumentRelease(drawPDFDocRef);
}
Here's the code for the Normal view (shows okay but image is not in the same quality as CATiledLayer one):
- (void) drawRect:(CGRect)rect {
[super drawRect:rect];
CGPDFPageRef drawPDFPageRef = NULL;
CGPDFDocumentRef drawPDFDocRef = NULL;
#synchronized(self) {
drawPDFDocRef = CGPDFDocumentRetain(_PDFDocRef);
drawPDFPageRef = CGPDFPageRetain(_PDFPageRef);
}
// get the page reference
CGPDFPageRef page = drawPDFPageRef;
CGContextRef context = UIGraphicsGetCurrentContext();
// white background
// transformation/-lation
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.00f, -1.00f);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page,
kCGPDFCropBox, self.bounds, 0, true));
CGContextSetInterpolationQuality(context, kCGInterpolationDefault);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f);
CGContextFillRect(context, CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFBleedBox));
CGContextDrawPDFPage(context, page);
CGPDFPageRelease(drawPDFPageRef);
CGPDFDocumentRelease(drawPDFDocRef);
}
Have you tried to set the content scale factor of the view after the zoom was performed?
In your UIScrollViewDelegate you would do:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
[view setContentScaleFactor:scale];
}

White border when rendering PDF when scale > 1

I have a method that return an UIImage from a CGPDFPageRef. You can specify a width for the image.
The problem is that when pdfScale is > 1, a white border appears in the image. So the PDF is always drawn at scale 1 with a border instead of a bigger scale. Smaller scales are OK.
I've tried to change the type of PDFBox but that doesn't seems to change anything and the documentation is not really clear.
Does somebody sees the error?
- (UIImage*) PDFImageForWidth:(CGFloat) width {
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
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();
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context, pageRect);
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, pageRect, 0, true));
CGContextDrawPDFPage(context, page);
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
The problem was that CGPDFPageGetDrawingTransform doesn't scale the PDF when scale > 1. You have to do it yourself.
Also, the method is thread safe now.
- (UIImage*) PDFImageForWidth:(CGFloat) width {
CGRect smallPageRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
CGFloat pdfScale = width/smallPageRect.size.width;
CGRect pageRect;
pageRect.size = CGSizeMake(smallPageRect.size.width*pdfScale, smallPageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;
__block CGContextRef context;
dispatch_sync(dispatch_get_main_queue(), ^{
UIGraphicsBeginImageContext(pageRect.size);
context = UIGraphicsGetCurrentContext();
});
if (context != nil) {
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context, pageRect);
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGAffineTransform transform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, pageRect, 0, true);
if (pdfScale > 1) {
transform = CGAffineTransformScale(transform, pdfScale, pdfScale);
transform.tx = 0;
transform.ty = 0;
}
CGContextConcatCTM(context, transform);
CGContextDrawPDFPage(context, page);
__block UIImage* image;
dispatch_sync(dispatch_get_main_queue(), ^{
image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
});
return [image autorelease];
}
else return nil;
}
I was having the same problem and the answer before did help me in some parts but it didn't solve the whole problem.
This is the how I solved my problem.
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
NSLog(#"pdfQuartzViewViewController - drawLayer");
CGPDFDocumentRef myDocumentRef = CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:self.strFilename]);
CGPDFPageRef pageReference = CGPDFDocumentGetPage(myDocumentRef, 1);
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // White
CGContextFillRect(context, CGContextGetClipBoundingBox(context)); // Fill
CGContextTranslateCTM(context, 0.0f, layer.bounds.size.height);
// Scaling the pdf page a little big bigger than the view so we can cover the white borders on the page
CGContextScaleCTM(context, 1.0015f, -1.0015f);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(pageReference, kCGPDFCropBox, layer.bounds, 0, true);
pdfTransform.tx = pdfTransform.tx - 0.25f;
pdfTransform.ty = pdfTransform.ty - 0.40f;
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, pageReference); // Render the PDF page into the context
CGPDFDocumentRelease(myDocumentRef);
myDocumentRef = NULL;
}
Here there is a good link where you can find more information about it. The post explains how to use all this methods.
http://iphonedevelopment.blogspot.ch/2008/10/demystifying-cgaffinetransform.html

how to go to next page of pdf in objective-c if pdf have multi pages

i have multi pages pdf,i want to go to the next page of pdf,
how to go this.
(page -> the page you want to display, pdfReference: a reference to a CGPDFDocumentRef)
pageReference = CGPDFDocumentGetPage(pdfReference, page);
CGContextRef context = UIGraphicsGetCurrentContext();
#try {
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, scale, -scale);
CGContextSaveGState(context);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(pageReference, kCGPDFCropBox, self.bounds, 0, true);
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, pageReference);
CGContextRestoreGState(context);
}
#finally {
UIGraphicsEndImageContext();
}
insert this into a drawRect:(CGRect) and you are fine to go

Drawing a PDF Right-Side-Up in CGContext

I'm overriding the drawRect: method in a custom UIView, and I'm doing some custom drawing. All was going well, until I needed to draw a PDF resource (a vector glyph, to be precise) into the context. First I retrieve the PDF from a file:
NSURL *pdfURL = [NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"CardKit.bundle/A.pdf"]];
CGPDFDocumentRef pdfDoc = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDoc, 1);
Then I create a box with the same dimensions as the loaded PDF:
CGRect box = CGPDFPageGetBoxRect(pdfPage, kCGPDFArtBox);
Then I save my graphics state, so that I don't screw anything up:
CGContextSaveGState(context);
And then I perform a scale+translate of the CTM, theoretically flipping the whole context:
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, rect.size.height);
I then scale the PDF so that it fits into the view properly:
CGContextScaleCTM(context, rect.size.width/box.size.width, rect.size.height/box.size.height);
And finally, I draw the PDF and restore the graphics state:
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
The issue is that there is nothing visible drawn. All this code should theoretically draw the PDF glyph into the view, right?
If I remove the scale+translate used to flip the context, it draws perfectly: it just draws upside-down.
Any ideas?
Try doing the translate before the scale:
CGContextTranslateCTM(context, 0.0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, currentPage);
CGContextSaveGState(context);
CGRect box = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGContextScaleCTM(context, self.bounds.size.width/box.size.width, self.bounds.size.height/box.size.height);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
This is the right answer to your question
To scale before translate, I think we can put minus when translate.
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -rect.size.height);
This flips everything right side up for me:
pdfDisplayView.layer.geometryFlipped = YES; //(NO)