How to save a bitmap as a 8-bit gray scale PNG file with Cocoa ?
08/02/06 21:36
When creating a 8-bits gray scale off-screen image by manually drawing in it,
it always turn out to be a 24-bits one when saved to disk using:
- (NSData *)representationUsingType:(NSBitmapImageFileType)storageType properties:(NSDictionary *)properties.
Any clue ?
it always turn out to be a 24-bits one when saved to disk using:
- (NSData *)representationUsingType:(NSBitmapImageFileType)storageType properties:(NSDictionary *)properties.
Any clue ?
When you create an offscreen image, with
image = [[NSImage alloc] initWithSize:imageSize];
followed by
[myImage lockFocus];,
the representation added to the image is a RGB NSCachedImageRep one.
First to get a grayscale NSCachedImageRep, you have to create a grayscale NSBitmapRep with:
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:1 hasAlpha:NO isPlanar:NO colorSpaceName:NSCalibratedWhiteColorSpace bytesPerRow:width bitsPerPixel:8] ;
and add it to the image representation BEFORE calling lockFocus.
This will not prevent the NSBitmapRep to be replaced by a NSCachedImageRep one after lockFocus, but at least this one will be a grayscale one and no more a RGB-one.
Once your drawing is done, after the unlockFocus, you have to create a new graphics context based on the original bitmap:
NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithAttributes:
[NSDictionary dictionaryWithObject:bitmap forKey:NSGraphicsContextDestinationAttributeName]];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:nsContext];
[image drawInRect:spreadRect fromRect:spreadRect operation:NSCompositeSourceOver fraction:1.0];
// Restore the previous NSGraphicsContext.
[NSGraphicsContext restoreGraphicsState];
[image removeRepresentation:[[image representations] objectAtIndex:0]];
[image addRepresentation:bitmap] ;
Now the image contains only one grayscale NSBitmapRep instead of a NSCachedImageRep,
and when calling representationUsingType on it,
the data will be maintained in 8bit grayscale format.
image = [[NSImage alloc] initWithSize:imageSize];
followed by
[myImage lockFocus];,
the representation added to the image is a RGB NSCachedImageRep one.
First to get a grayscale NSCachedImageRep, you have to create a grayscale NSBitmapRep with:
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:1 hasAlpha:NO isPlanar:NO colorSpaceName:NSCalibratedWhiteColorSpace bytesPerRow:width bitsPerPixel:8] ;
and add it to the image representation BEFORE calling lockFocus.
This will not prevent the NSBitmapRep to be replaced by a NSCachedImageRep one after lockFocus, but at least this one will be a grayscale one and no more a RGB-one.
Once your drawing is done, after the unlockFocus, you have to create a new graphics context based on the original bitmap:
NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithAttributes:
[NSDictionary dictionaryWithObject:bitmap forKey:NSGraphicsContextDestinationAttributeName]];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:nsContext];
[image drawInRect:spreadRect fromRect:spreadRect operation:NSCompositeSourceOver fraction:1.0];
// Restore the previous NSGraphicsContext.
[NSGraphicsContext restoreGraphicsState];
[image removeRepresentation:[[image representations] objectAtIndex:0]];
[image addRepresentation:bitmap] ;
Now the image contains only one grayscale NSBitmapRep instead of a NSCachedImageRep,
and when calling representationUsingType on it,
the data will be maintained in 8bit grayscale format.