I am working on an app that will mark up a PDF and export it. I need the user to be able to draw on top of a PDF, and then I will analyze their actions and apply some type of annotation. Ultimately, it will be lines, circles, and text added to the file (so annotations should be sufficient). I'm not certain how I will tackle all that just yet; I am just trying to get the PDF to show up.
I am worried about using UIWebView though. I figured the drawing + applying will all be in Quartz, so the PDF viewing should be too. I'd love to get a professional opinion from anyone out there. Will it be okay to view the PDF in UIWebView, and then load it with Quartz to apply annotations? I remember reading another way somewhere, but I cannot seem to figure out how its done.
There is another way to do it. I wrote up a quick tutorial based on another tutorial I found. If anyone else is trying to do this, I recommend checking this out:
I'm having an issue with it only displaying one defined page. UIWebView works great for displaying pages, but I need more functionality than UIWebView offers.
I'm going to update that tutorial when I figure this out, but I could really use some help. Here is what I have:
// PDFView.m
#import "PDFView.h"
@implementation PDFView
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.backgroundColor = [UIColor clearColor];
CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("MyPDF.pdf"), NULL, NULL);
pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CFRelease(pdfURL);
}
return self;
}
- (void)drawRect:(CGRect)rect {
[self drawInContext:UIGraphicsGetCurrentContext()];
}
-(void)drawInContext:(CGContextRef)context {
// PDF page drawing expects a Lower-Left coordinate system, so we flip the coordinate system
// before we start drawing.
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Grab the first PDF page
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
// We're about to modify the context CTM to draw the PDF page where we want it, so save the graphics state in case we want to do more drawing
CGContextSaveGState(context);
// CGPDFPageGetDrawingTransform provides an easy way to get the transform for a PDF page. It will scale down to fit, including any
// base rotations necessary to display the PDF page correctly.
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, self.bounds, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
// Finally, we draw the page and restore the graphics state for further manipulations!
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
}
- (void)dealloc {
CGPDFDocumentRelease(pdf);
[super dealloc];
}
@end
I'm pretty sure you have to load each page one at a time. CGPDFDocumentGetNumberOfPages will give you the number of pages, and CGPDFPageGetBoxRect will get you the drawing space for each page. But I think it's going to take a lot of experimentation to get it to look right, where you will have to calculate which page should be on the screen at any time and only load that one.
I'm changing up how I am trying to do this. I just realized that I will not want the PDF to be in a scrolling view as people will be drawing on top of it (and therefore, it should not be moving around). I will now display the current page of the PDF with an up and down button that can swap the page with a new one. I suppose it is the same concept though.
I want to load a PDF page into a UIView. The code I posted above works for that. I cannot seem to find a way to define the page number outside of UIView though. I have seriously spent hours trying to pass an integer from the view controller to the view. I suppose I could add the up and down buttons to the view and create an action within the view that changes the page number. That does not sound like good practice to me though.
Is there anyway to pass int currentPage into this from the view controller?
Wow, that would have taken me so long to figure out. Updating the previous tutorial now. Thanks Jason. To think, I spent the whole day on such a silly thing.