Re: Drawing NSImage in grayscale
Re: Drawing NSImage in grayscale
- Subject: Re: Drawing NSImage in grayscale
- From: Peter Ammon <email@hidden>
- Date: Sat, 1 Dec 2001 13:35:48 -0500
On Friday, November 30, 2001, at 05:13 PM, Peter Ammon wrote:
Are there any easy techniques (e.g. compositing operations, perhaps in
several passes) for drawing a color NSImage instantiated from a tiff
file in grayscale?
The only way I can think of would be to create an NSBitmapImageRep with
one data plane and draw into that.
Thanks for any ideas!
-Peter
I went ahead and implemented my idea, so here it is in case someone else
can get use out of it. It seems to work for the meshed images I've
tried; I haven't tested it with planar images.
Here it is, to be implemented as a category on NSImage (I declare
identifiers everywhere, so you have to compile it as Objective-C++ or
C99):
//returns an image that is self, only grayscale
- (NSImage*)grayscale {
NSArray* currentReps=[self representations];
NSData* tiffData=[NSBitmapImageRep
TIFFRepresentationOfImageRepsInArray:currentReps
usingCompression:NSTIFFCompressionNone
factor:0.0];
NSBitmapImageRep* bitmap=[NSBitmapImageRep
imageRepWith
Data:tiffData];
//we don't know how to handle anything but CHAR_BIT bits per sample
NSAssert1([bitmap bitsPerSample]==CHAR_BIT, @"bitsPerSample is %d in
grayscale method", [bitmap bitsPerSample]);
unsigned char* planes[5];
[bitmap getBitmapDataPlanes:planes];
int numberPlanes=0;
while (numberPlanes < 5 && planes[numberPlanes]) numberPlanes++;
const BOOL hasAlpha=[bitmap hasAlpha];
const int samples=[bitmap samplesPerPixel];
unsigned char* grayData=malloc([bitmap pixelsWide]*[bitmap
pixelsHigh]);
if (! grayData) return nil;
unsigned char* alphaData;
if (hasAlpha) {
alphaData=malloc([bitmap pixelsWide]*[bitmap pixelsHigh]);
if (! alphaData) {
free(grayData);
return nil;
}
}
if (! [bitmap isPlanar]) {
int height, maxHeight=[bitmap pixelsHigh], bytesPerRow=[bitmap
bytesPerRow], rowLength=[bitmap pixelsWide]*samples;
unsigned char* writer=grayData;
unsigned char* alpha=alphaData;
for (height=0; height<maxHeight; height++) {
unsigned char* start=planes[0]+height*bytesPerRow;
unsigned char* pos=start;
while (pos-start < rowLength) {
int sampleCounter=samples;
unsigned average=0;
if (hasAlpha) {
while (--sampleCounter) average+=*pos++;
*writer++=average/(samples-1);
*alpha++=*pos++;
}
else {
while (sampleCounter--) average+=*pos++;
*writer++=average/samples;
}
}
}
}
else { //bitmap is planar
int height, maxHeight=[bitmap pixelsHigh], bytesPerRow=[bitmap
bytesPerRow], rowLength=[bitmap pixelsWide]*samples;
unsigned char* writer=grayData;
unsigned char* alpha=alphaData;
for (height=0; height<maxHeight; height++) {
int offset=height*bytesPerRow;
int i;
for (i=0; i<rowLength; i++) {
int sampleCounter=samples;
unsigned average=0;
if (hasAlpha) {
*alpha++=planes[--sampleCounter][i+offset];
while (sampleCounter--)
average+=planes[sampleCounter][i+offset];
*writer++=average/(samples-1);
}
else {
while (sampleCounter--)
average+=planes[sampleCounter][i+offset];
*writer++=average/samples;
}
}
}
}
unsigned char* myPlanes[]={grayData, alphaData};
NSBitmapImageRep* grayBitmap=[[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:myPlanes
pixelsWide:[bitmap pixelsWide]
pixelsHigh:[bitmap pixelsHigh]
bitsPerSample:CHAR_BIT
samplesPerPixel: hasAlpha ? 2 : 1
hasAlpha:
hasAlpha
isPlanar:YES
colorSpaceName:NSCalibratedWhiteColorSpace
bytesPerRow:0
bitsPerPixel:0] autorelease];
NSImage* newImage=[[[NSImage alloc] initWithSize:[self size]]
autorelease];
[newImage addRepresentation:grayBitmap];
free(grayData);
if (hasAlpha) free(alphaData);
return newImage;
}