Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save PNG file from NSImage (retina issues)

I'm doing some operations on images and after I'm done, I want to save the image as PNG on disk. I'm doing the following:

+ (void)saveImage:(NSImage *)image atPath:(NSString *)path {      [image lockFocus] ;     NSBitmapImageRep *imageRepresentation = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0.0, 0.0, image.size.width, image.size.height)] ;     [image unlockFocus] ;      NSData *data = [imageRepresentation representationUsingType:NSPNGFileType properties:nil];     [data writeToFile:path atomically:YES]; } 

This code is working, but the problem is with retina mac, if I print the NSBitmapImageRep object I get a different size and pixels rect and when my image is saved on disk, it's twice the size:

$0 = 0x0000000100413890 NSBitmapImageRep 0x100413890 Size={300, 300} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=8 BPP=32 Pixels=600x600 Alpha=YES Planar=NO Format=0 CurrentBacking=<CGImageRef: 0x100414830> 

I tied to force the pixel size to not take care about the retina scale, as I want to preserve the original size:

imageRepresentation.pixelsWide = image.size.width; imageRepresentation.pixelsHigh = image.size.height; 

This time I get the right size when I print the NSBitmapImageRep object, but when I save my file I still get the same issue:

$0 = 0x0000000100413890 NSBitmapImageRep 0x100413890 Size={300, 300} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=8 BPP=32 Pixels=300x300 Alpha=YES Planar=NO Format=0 CurrentBacking=<CGImageRef: 0x100414830> 

Any idea how to fix this, and preserve the original pixel size?

like image 390
Ludovic Landry Avatar asked Jul 06 '13 21:07

Ludovic Landry


1 Answers

If you have an NSImage and want to save it as an image file to the filesystem, you should never use lockFocus! lockFocus creates a new image which is determined for getting shown an the screen and nothing else. Therefore lockFocus uses the properties of the screen: 72 dpi for normal screens and 144 dpi for retina screens. For what you want I propose the following code:

+ (void)saveImage:(NSImage *)image atPath:(NSString *)path {     CGImageRef cgRef = [image CGImageForProposedRect:NULL                                             context:nil                                               hints:nil];    NSBitmapImageRep *newRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];    [newRep setSize:[image size]];   // if you want the same resolution    NSData *pngData = [newRep representationUsingType:NSPNGFileType properties:nil];    [pngData writeToFile:path atomically:YES];    [newRep autorelease]; } 
like image 74
Heinrich Giesen Avatar answered Sep 28 '22 23:09

Heinrich Giesen