3

I am trying to create a PDF from a UIView which may contain images, labels, etc. I have checked the reference ( GeneratingPDF) and I am also aware of the renderInContext: method, which can be used to draw the UIView's content onto the PDF context.

I used renderInContext: to create a PDF. However, the images and the text lost their fidelity. i.e. The images were not selectable individually & the text could not be selected/copied, etc. in the resulting PDF. It was as good/bad as the PDF created from a snapshot of the UIView.

My question is, do I have to draw the texts & images individually to achieve what I want (using CGContextShowTextAtPoint & CGContextDrawImage)?

If yes, then how do I go about scanning the UIView for texts & images? Assume that I receive the UIView from outside & am not aware of its contents.

Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
Akshay
  • 5,747
  • 3
  • 23
  • 35

3 Answers3

2

I've had a moderate amount of luck just walking my view hierarchy, and calling -drawRect: myself. There's a bit of set up that you've got do before each, like translating the ctm and clearing the text matrix, but when you've done that for each view, you can do this:

UIGraphicsPushContext(ctx);
[self drawRect:self.frame];
UIGraphicsPopContext();

The PDF it generates is vector based -- not just a flat bitmap, so it scales nicely and you can select the text in a viewer/browser. This only works on plain vanilla custom drawing and very simple stuff like UILabels. I doubt it would work with more complex UIKit objects (I'm thinking table views and scroll views). Also, you would need extra work for UIImageViews (which I'm guessing set the contents property of the layer with a CGImageRef), and if you've got other layer based attributes and transforms -- even more work.

Hopefully Apple will give us a better solution than maintaining parallel draw code!

joeybladb
  • 227
  • 1
  • 10
  • This UIView category worked well- I believe it uses your strategy: https://github.com/mruegenberg/uiview-hierarchical-drawing. One thing to keep in mind is if you are using CALayers, you will need to add code to write to the context explicitly. See this answer: http://stackoverflow.com/questions/13783971/maintain-vector-graphics-when-rendering-calayer-into-pdf-output – jeffmax Feb 05 '15 at 13:56
1

You do indeed have to draw the texts/images individually into a CGContextRef (look at CGPDFContextCreateWithURL) using functions like CGContextShowTextAtPoint. While you could theoretically scan your UIView for images/labels, it would be better if you just draw the layout from scratch. You must have some way to know what elements should be in the UIView. Although the code will be very different, logically you should approach it the same way you would if you were going to draw the UIView programmatically instead of loading it from a nib.

If you really want to scan your UIView, you could do something like this:

for(UIView *subview in parentView.subviews) {
 if([subview isKindOfClass:[UIImageView class]]) {
  ...
 } else if([subview isKindOfClass:[UITextView class]]) {
  ...
 } else if([subview isKindOfClass:[UILabel class]]) {
  ...
 }
}
Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
  • Thanks Michael! So, are you sure that `renderInContext:` cannot be used in this case? I am thinking about scenarios in which the `UIView` has a fancy multi-colored background or something, which could be difficult to draw. – Akshay Sep 22 '11 at 13:03
  • Yes I am sure. I actually went through this problem not too long ago and my logic started exactly where yours did (renderInContext:) and then I tried searching for some code to draw a UIView into a PDF and in the end the only way to really do it is to use the CGContext methods and go at it from scratch drawing everything in a CGContextRef. – Michael Frederick Sep 22 '11 at 13:47
  • Thanks again Michael! So, how do you draw if the UIView has a background with a gradient? Also, my actual use case is creating a PDF from a `UIWebView` which I am using to display a file (say ppt or doc), for which I found that text & images are not present as subviews (no UILabels or UITextViews). Have you tried this too? Sorry for not specifying this originally. – Akshay Sep 22 '11 at 14:13
  • 1
    So you are really trying to convert a ppt or doc to a PDF? That is an entirely different story. I am not sure what direction to point you in for that. There is no convenient library built to do this in iOS that I am aware of. It would probably be easiest to connect to a web service to allow a server to do the conversion for you, but I don't know if that fits your needs. Good luck! – Michael Frederick Sep 22 '11 at 14:22
  • Hi Michael is it possible to generate a PDF from opengles view.Please lemme know it it is feasible or not so that i can proceed.Thanks in advance. – ravoorinandan Mar 08 '12 at 12:39
0

try,

{
   //read the pdf file

     CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),     CFSTR("iPhoneAppProgrammingGuide.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);
    //CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox),
                                                CGContextGetClipBoundingBox(context));

      // CGContextConcatCTM(context, transform);
         UIGraphicsBeginImageContext(CGSizeMake(self.bounds.size.width, self.bounds.size.height));


}
j0k
  • 22,600
  • 28
  • 79
  • 90
NANNAV
  • 4,875
  • 4
  • 32
  • 50