iosobjective-cuigraphicscontextuiprintpagerenderer

Is there an equivalent of "renderInContext" for UIPrintPageRenderer


You can call renderInContext on a layer. Is there something like that for UIPrintPageRenderer? I basically want to create a UIImage out of the first page of a PDF document of a UIPrintPageRenderer. I have the rest of the code except for the actual rendering in context part.

Edit: Am I misunderstanding some basic underlying concept here? If so, please feel free to give me a quick lesson.


Solution

  • Getting most of my information from Vel Genov in this post, here is what you should do:

    The example code below adds a Category to UIPrintPageRenderer to create the actual PDF data.

    @interface UIPrintPageRenderer (PDF)
    - (NSData*) createPDF;
    @end
    
    @implementation UIPrintPageRenderer (PDF)
    - (NSData*) createPDF
    {
        NSMutableData *pdfData = [NSMutableData data];
        UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, nil );
        [self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
        CGRect bounds = UIGraphicsGetPDFContextBounds();
        for ( int i = 0 ; i < self.numberOfPages ; i++ )
        {
            UIGraphicsBeginPDFPage();
            [self drawPageAtIndex: i inRect: bounds];
        }
        UIGraphicsEndPDFContext();
        return pdfData;
    }
    @end
    

    Then, this goes in the webViewDidFinishLoad()

    - (void)webViewDidFinishLoad:(UIWebView *)webViewIn {
        NSLog(@"web view did finish loading");
    
        // webViewDidFinishLoad() could get called multiple times before
        // the page is 100% loaded. That's why we check if the page is still loading
        if (webViewIn.isLoading)
            return;
    
        UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
        [render addPrintFormatter:webViewIn.viewPrintFormatter startingAtPageAtIndex:0];
    
        // Padding is desirable, but optional
        float padding = 10.0f;
    
        // Define the printableRect and paperRect
        // If the printableRect defines the printable area of the page
        CGRect paperRect = CGRectMake(0, 0, PDFSize.width, PDFSize.height);
        CGRect printableRect = CGRectMake(padding, padding, PDFSize.width-(padding * 2), PDFSize.height-(padding * 2));
    
        [render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
        [render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];
    
        // Call the printToPDF helper method that will do the actual PDF creation using values set above
        NSData *pdfData = [render createPDF];
    
        // Save the PDF to a file, if creating one is successful
        if (pdfData) {
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *path = [paths objectAtIndex:0];
    
            NSString *pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"Purchase Order.pdf"]];
    
            [pdfData writeToFile:pdfPath atomically:YES];
        }
        else
        {
            NSLog(@"error creating PDF");
        }
    }
    

    PDFSize is defined as a constant, set to a standard A4 page size. It can be edited to meet your needs.

    #define PDFSize CGSizeMake(595.2,841.8)
    

    Here is what Val says about the code:

    When webViewDidFinishLoad() gets called, the view might not be 100% loaded. A check is necessary, to see if the view is still loading. This is important, as it might be the source of your problem. If it's not, then we are good to go. There is a very important note here. Some web pages are loaded dynamically (defined in the page itself). Take youtube.com for example. The page displays almost immediately, with a "loading" screen. This will trick our web view, and it's "isLoading" property will be set to "false", while the web page is still loading content dynamically. This is a pretty rare case though, and in the general case this solution will work well. If you need to generate a PDF file from such a dynamic loading web page, you might need to move the actual generation to a different spot. Even with a dynamic loading web page, you will end up with a PDF showing the loading screen, and not an empty PDF file.

    Another key aspect is setting the printableRect and pageRect. Note that those are set separately. If the printableRect is smaller than the paperRect, you will end up with some padding around the content - see code for example. Here is a link to Apple's API doc with some short descriptions for both.