Skip navigation.
 
mlSuccess Re: Why does my PDF NSImage print to paper at low res screen resolution? (was Re: how to get a sub piece of an NSImage or make a new NSImage that is a subset of an existing one)
FROM : Chad Leigh
DATE : Sat Aug 12 19:33:27 2006

On Aug 12, 2006, at 2:59 AM, Chad Leigh wrote:

>
> On Aug 12, 2006, at 1:47 AM, Chad Leigh wrote:
>

>>
>> On Aug 12, 2006, at 12:01 AM, Chad Leigh wrote:
>>

>>>
>>> On Aug 11, 2006, at 11:43 PM, Jonathan Grynspan wrote:
>>>

>>>> You can find more information on Cocoa's graphics model at 
>>>> http://developer.apple.com/documentation/Cocoa/Conceptual/
>>>> CocoaDrawingGuide/index.html . Of particular interest to you may 
>>>> be the sections on Graphics Contexts and Images.

>>>
>>> I am reading that now, thanks.
>>>
>>> Unfortunately my new image is a cached screen representation and 
>>> not the hi-res PDF that it was before.  And it appears from the 
>>> CocoaDrawingGuide docs under "Creating Graphics Contexts" that 
>>> you cannot create a new PDF image using the code below.  It 
>>> says :-( "Important:  You cannot create a viable graphics context 
>>> for PDF or PostScript canvases using the 
>>> graphicsContextWithAttributes: method. You must go through the 
>>> Cocoa Printing system instead."  That however, is what I need to 
>>> do, I think.

>>
>> It looks like something like this works:
>>
>>          NSImageView *imageView = [[[NSImageView alloc] 
>> initWithFrame:labelPDFRect] autorelease];
>>          [imageView setImage:newLabel];
>>          [imageView beginDocument];
>>          NSMutableData    *imageData = [NSMutableData data];
>>          NSPrintOperation *pdfOp = [NSPrintOperation 
>> PDFOperationWithView:imageView insideRect:imageRect 
>> toData:imageData];
>>          [pdfOp runOperation];
>>          label = [[NSImage alloc] initWithData:imageData];
>>     //     [pdfOp cleanUpOperation];
>>          [imageView endDocument];
>>
>>
>> I get my image and it is still a PDF based image by looking at the 
>> single NSImageRep (NSPDFImageRep) that it contains, though I have 
>> not yet gotten my printing code to spit out the image as I seem to 
>> have screwed something up and all I get now is a gray box the size 
>> of the page (without margins) so the paper comes out with a gray 
>> box with normal white  margin.  This happens even when I use my 
>> PNG image code so I screwed something up somewhere.

>
> Ok, I fixed my screwed up print code -- I had a blank subview that 
> had been added in one of my dead-end attempts at fixing this.
>
> It appears that I am getting a PDF image from the above code. 
> However, it is either a screen image quality representation or when 
> I draw it to the printer view in my NSPrintOperation, it somehow 
> gets converted to a screen resolution low res.
>
> I capture the PDF to a file when I get it from the wire and I can 
> print that and it is a "high resolution" image just like you would 
> expect the PDF to be.
>
> I have an alternate version of my code that uses PDFPage/PDFView 
> etc with AffineTransforms to print to my page from just a portion 
> of the PDF page.  So I know the original PDF is not a low res 
> bitmap to start
>
> Here is how I create the original NSIMage
>
>    [finalImage appendBytes:(const void *)finalImageBytes length:k];
> //    [finalImage writeToFile:@"express_label.pdf" atomically:YES];
>    newLabel = [[NSImage alloc] initWithData:finalImage];
>
> (gdb) po newLabel
> NSImage 0x1607ba30 Size={612, 792} Reps=(
>    NSPDFImageRep 0x1609ac40 Size={612, 792} 
> ColorSpace=NSCalibratedRGBColorSpace BPS=0 Pixels=612x792 Alpha=NO
> )
> (gdb)
>
> Question on the above -- is the Pixels here a real pixels size or 
> is it like the page -- a coordinate system that does not really 
> relate to actual pixels?  The way the image is drawn it appears to 
> be a real pixel count -- how can I get the NSImage (NSPDFImageRep) 
> to not degrade when I create it?
>
> // (I now calculate some rects to grab the top half of the image 
> and make a new image -- this part is snipped )
>
> // create new image
>
>          NSImageView *imageView = [[[NSImageView alloc] 
> initWithFrame:labelPDFRect] autorelease];
>          [imageView setImage:newLabel];
>          [imageView beginDocument];
>          NSMutableData    *imageData = [NSMutableData data];
>          NSPrintOperation *pdfOp = [NSPrintOperation 
> PDFOperationWithView:imageView insideRect:imageRect toData:imageData];
>          [pdfOp runOperation];
>          label = [[NSImage alloc] initWithData:imageData];
>     //     [pdfOp cleanUpOperation];
>          [imageView endDocument];
>
> (gdb) po label
> NSImage 0x1685f80 Size={612, 416} Reps=(
>    NSPDFImageRep 0x16063a30 Size={612, 416} 
> ColorSpace=NSCalibratedRGBColorSpace BPS=0 Pixels=612x416 Alpha=NO
> )
> (gdb)
>
>
>         return [label autorelease];
>
> // gets saved away
>
> // later in print code
>
> // calculate a new target rect based on the paper size from the 
> NSPrintInfo -- not shown
>
> // print to the print view -- show in gdb the label before it is drawn
>
> (gdb) po label
> NSImage 0x1685f80 Size={612, 416} Reps=(
>    NSPDFImageRep 0x16063a30 Size={612, 416} 
> ColorSpace=NSCalibratedRGBColorSpace BPS=0 Pixels=612x416 Alpha=NO
> )
> (gdb)
>
>     [label drawInRect:labelRect fromRect:imageRect 
> operation:NSCompositeCopy fraction:1.0];
>
>
> // more drawing code for text etc
>
> When this gets printed on paper the PDF is a low-res "screen" type 
> image and not the crisp original PDF image


Ok, even though my NSImage only has 1 representation, the 
NSPDFImageRep, it draws a low-res screen copy.  But Andrew Stone to 
the rescue!

I found on this page <http://stone.com/The_Cocoa_Files/
Cocoamotion.html
> the answer (look for PDF Optimization).  He says 
that you must take the actual NSPDFImageRep out and cause it to draw 
itself.  His code looks like

if (needToUseRealPDFData) {
          // grab the image's best representation, the actual 
NSPDFImageRep:
NSPDFImageRep *rep = [_image bestRepresentationForDevice:nil];
            // ask it to draw within our bounds:
[rep drawInRect:NSMakeRect
(0.0,0.0,_bounds.size.width,_bounds.size.height)];
} else
[image drawInRect:NSMakeRect
(0.0,0.0,_bounds.size.width,_bounds.size.height) fromRect:NSZeroRect 
operation:NSCompositeSourceOver fraction:1.0 - _dissolve];

which for testing purposes in my code looks like (I'll clean it up 
and set up a pref so I can use PNG or PDF depending on what the user 
wants and what comes over the wire, etc)

   if (1) {
                      // grab the image's best representation, the actual 
NSPDFImageRep:
           NSPDFImageRep *rep = [label bestRepresentationForDevice:nil];
                        // ask it to draw within our bounds:
           [rep drawInRect:labelRect];
         }
           else
                  [label drawInRect:labelRect fromRect:imageRect 
operation:NSCompositeCopy fraction:1.0];


Thanks Andy!

I've also modified my code for extracting the piece of PDF I need to 
use the NSView helper routine - dataWithPDFInsideRect:aRect; since it 
seemed easier and I let it set up the print op etc.


Chad    


>
> What have I done wrong?
>
> Thanks
> Chad
>
>

>>
>> Chad
>>
>>

>>>
>>> Thanks
>>> Chad
>>>

>>>>
>>>> -Jonathan Grynspan
>>>>
>>>> On 12-Aug-06, at 1:34 AM, Chad Leigh wrote:
>>>>

>>>>>
>>>>> On Aug 11, 2006, at 11:28 PM, Jonathan Grynspan wrote:
>>>>>

>>>>>> Try the following:
>>>>>>
>>>>>> NSImage *partOfImage(NSImage *input, NSRect targetRect) {
>>>>>>     if (input) {
>>>>>>         NSImage *output = [[NSImage alloc] initWithSize: 
>>>>>> targetRect.size];
>>>>>>         [output lockFocus];
>>>>>>         [input
>>>>>>             drawAtPoint:    NSZeroPoint
>>>>>>             fromRect:    targetRect
>>>>>>             operation:    NSCompositeCopy
>>>>>>             fraction:        1.0f];
>>>>>>         [output unlockFocus];
>>>>>>         return [output autorelease];
>>>>>>     } else {
>>>>>>         return nil;
>>>>>>     }
>>>>>> }

>>>>>
>>>>> Thanks, I will.  I've been reading the lockFocus and the 
>>>>> drawAtPoint stuff since I posted the first request, trying to 
>>>>> put my brain around it.  This helps immensely!
>>>>>
>>>>> Thanks
>>>>> Chad
>>>>>

>>>>>>
>>>>>> -Jonathan Grynspan
>>>>>>
>>>>>> On 12-Aug-06, at 1:17 AM, Chad Leigh wrote:
>>>>>>

>>>>>>> I have a Cocoa app and I get a PDF image over the internet 
>>>>>>> that I store in an NSImage using
>>>>>>>
>>>>>>>    label = [[NSImage alloc] initWithData:finalImage];
>>>>>>>
>>>>>>>
>>>>>>> The image previously was a PNG image and was exactly the 
>>>>>>> image needed.  Now that they pass a PDF image, they pass an 
>>>>>>> image that is an image of a complete piece of paper with the 
>>>>>>> image I am interested in placed on the upper half of this 
>>>>>>> virtual paper (the rest is just blank).  The image is always 
>>>>>>> in the same place and the same size so I can determine a Rect 
>>>>>>> that will always work to select it.  I want to extract this 
>>>>>>> image out of the PDF and create a new NSImage (or overwrite 
>>>>>>> the old one, I don't care) that I can use later on to print 
>>>>>>> in my own existing print routine and to display thumbnails of 
>>>>>>> it.
>>>>>>>
>>>>>>> I do not see how to go about it.  Most of the draw/composite 
>>>>>>> routines I see in NSImage rely on an existing userspace to 
>>>>>>> draw into.  I want to "draw" into a new NSImage.  My brain is 
>>>>>>> having a hard time adjusting to think about how to do this.
>>>>>>>
>>>>>>> Ideally I want something like
>>>>>>>
>>>>>>>     NSImage *newImage = [[NSImage alloc] initFromImage:oldImage 
>>>>>>> usingRect:targetRect];
>>>>>>>
>>>>>>> I expect what I want to do is very easy but if someone could 
>>>>>>> point me on the way I should be exploring I would appreciate it.
>>>>>>>
>>>>>>>
>>>>>>> Thanks
>>>>>>> Chad
>>>>>>>