Compositing NSViews for print

  • Ive got this code in my app to generate a PDF of a web page.

    - (IBAction)PDFpage:(id)sender
    {
    NSString *path = @"~/Desktop/Page.pdf";
    path = [path stringByExpandingTildeInPath];
    WebFrameView *dv = [[[myWebView mainFrame] frameView] documentView];
    NSPrintInfo *info = [NSPrintInfo sharedPrintInfo];
    NSMutableData *data = [NSMutableData dataWithCapacity:1024];
    //relevant stuff
    id op = [NSPrintOperation PDFOperationWithView:dv insideRect:[dv
    bounds] toData:data printInfo:info]
    [op runOperation];
    [op deliverResult];
    if([data length]) [data writeToFile:path atomically:YES];
    }

    This only gives a PDF of the uppermost layer, ie some backgrounds dont
    appear in the PDF. How can I composite the view and its subviews into
    one layer so that I get a true snapshot of the page. I dont want it
    ripped to pixels either as I want the text info intact.
  • It's a bit (okay, more than a bit) of a hack, but I ran into a similar
    problem and solved it with the following method:

    - (IBAction)webViewPrint:(id)sender
    {
    NSPrintOperation *op;
    NSView    *documentView;
    NSImage    *image;
    NSImageView  *imageView;
    NSSize    imageSize;
    NSRect    originalWebViewFrame, webViewFrame, documentViewFrame,
    imageViewFrame;
    NSPrintInfo  *sharedPrintInfo = [NSPrintInfo sharedPrintInfo];

    //Calculate the page height in points
        NSSize paperSize = [sharedPrintInfo paperSize];
        float pageWidth = paperSize.width - [sharedPrintInfo leftMargin] -
    [sharedPrintInfo rightMargin];

        //Convert height to the scaled view
    float scale = [[[sharedPrintInfo dictionary]
    objectForKey:NSPrintScalingFactor] floatValue];
    if(!scale) scale = 1.0;
        pageWidth = pageWidth / scale;

    //Get the HTMLDocumentView which has all the content we want
    documentView = [[[webView mainFrame] frameView] documentView];

    //Get initial frames
    originalWebViewFrame = [webView frame];
    documentViewFrame = [documentView frame];

    //Make the webView the same size as we will be printing so any CSS
    elements resize themselves properly
    webViewFrame = originalWebViewFrame;
    webViewFrame.size.width = pageWidth;
    webViewFrame.size.height = documentViewFrame.size.height;
    [webView setFrame:webViewFrame];

    //Ensure the documentView is constrained to the pageWidth
    documentViewFrame.size.width = pageWidth;

    //Set up our image
    image = [[[NSImage alloc] initWithSize:documentViewFrame.size]
    autorelease];
    [image setFlipped:YES];

    //Draw
    [image lockFocus];
    [documentView drawRect:documentViewFrame];
    [image unlockFocus];

    //Restore the webView's frame to its original state
    [webView setFrame:originalWebViewFrame];

    //Create an NSImageView to hold our image
    imageSize = [image size];
    imageViewFrame = NSMakeRect(0,0,imageSize.width,imageSize.height);
    imageView = [[[NSImageView alloc] initWithFrame:imageViewFrame]
    autorelease];
    [imageView setImageAlignment:NSImageAlignTop];
    [imageView setAnimates:NO];
    [imageView setImageScaling:NSScaleProportionally];
    [imageView setImage:image];

    //Pass it to NSPrintOperation
    op = [NSPrintOperation printOperationWithView:imageView];
    [op setCanSpawnSeparateThread:YES];

    #warning documentView creates a visual glitch which disappears when the
    scrollbar or window is changed. odd.
    [op runOperationModalForWindow:[webView window]
                             delegate:self
        didRunSelector:@selector(printOperationDidRun:success:contextInfo:)
                         contextInfo:NULL];
    }

    Use the PDFOperationWithView lines you've written instead of the bottom
    part of the method above and hopefully you'll be good to go.

    Obviously this method isn't what -should- be necessary... if someone
    has a way to get the background and layout elements to print without
    this sort of hackery I'd be excited to see it :)

    Hope that helps,
    Evan
    www.adiumx.com

    On Jan 12, 2005, at 6:38 AM, Warren Burton wrote:

    > Ive got this code in my app to generate a PDF of a web page.
    >
    > - (IBAction)PDFpage:(id)sender
    > {
    > NSString *path = @"~/Desktop/Page.pdf";
    > path = [path stringByExpandingTildeInPath];
    > WebFrameView *dv = [[[myWebView mainFrame] frameView] documentView];
    > NSPrintInfo *info = [NSPrintInfo sharedPrintInfo];
    > NSMutableData *data = [NSMutableData dataWithCapacity:1024];
    > //relevant stuff
    > id op = [NSPrintOperation PDFOperationWithView:dv insideRect:[dv
    > bounds] toData:data printInfo:info]
    > [op runOperation];
    > [op deliverResult];
    > if([data length]) [data writeToFile:path atomically:YES];
    > }
    >
    > This only gives a PDF of the uppermost layer, ie some backgrounds dont
    > appear in the PDF. How can I composite the view and its subviews into
    > one layer so that I get a true snapshot of the page. I dont want it
    > ripped to pixels either as I want the text info intact.
    >
    >
    >
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<evan.s...>
    >
    > This email sent to <evan.s...>