• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Drawing NSImage in grayscale
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Drawing NSImage in grayscale


  • Subject: Re: Drawing NSImage in grayscale
  • From: Peter Ammon <email@hidden>
  • Date: Sun, 2 Dec 2001 16:08:35 -0500

On Sunday, December 2, 2001, at 03:21 PM, Tom Waters wrote:

gray = .56g + .33r + .11b as i recall.

On Saturday, December 1, 2001, at 01:33 PM, John C. Randolph wrote:

On Saturday, December 1, 2001, at 10:35 AM, Peter Ammon wrote:

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.

Peter,

Your code will give a good approximation, but I suggest that you
have a look in Newman & Sproul for the standard RGB weighting
function. Basically, we're much more sensitive to light in the
green band than the blue, and there is a formula that accounts
for this.

-jcr

Hi, and thanks for the help Tom and John. Indeed, changing with the weights really improved the appearance of the grayscale image. According to the good folks on comp.graphics.algorithms, there's not a standard set of weights. The right thing to do seems to be to play around with it until you get results that look the way you want them to. I found that NTSC (r*0.299 + g*0.587 + b*0.114) looks good for my particular images.

I made a small change in my previous method before I posted it which caused it to break, so somewhat guiltily, I repost a fixed version of the entire thing here:

- (NSImage*)grayscale {
const double conversionWeights[3]={.299, .587, .111};
NSArray* currentReps=[self representations];
NSData* tiffData=[NSBitmapImageRep TIFFRepresentationOfImageRepsInArray:currentReps
usingCompression:NSTIFFCompressionNone
factor:0.0];
NSBitmapImageRep* bitmap=[NSBitmapImageRep imageRepWithData: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];
NSBitmapImageRep* grayBitmap=[[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
pixelsWide:[bitmap pixelsWide]
pixelsHigh:[bitmap pixelsHigh]
bitsPerSample:8
samplesPerPixel: hasAlpha ? 2 : 1
hasAlpha: hasAlpha
isPlanar:YES
colorSpaceName:NSCalibratedWhiteColorSpace
bytesPerRow:0
bitsPerPixel:0] autorelease];
if (! grayBitmap) return nil;
unsigned char* destDataPlanes[2];
[grayBitmap getBitmapDataPlanes:destDataPlanes];
unsigned char* grayData=destDataPlanes[0];
unsigned char* alphaData=destDataPlanes[1];
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;
double average=0;
if (sampleCounter==3 || (sampleCounter==4 && hasAlpha)) {
average+=conversionWeights[0]**pos++;
average+=conversionWeights[1]**pos++;
average+=conversionWeights[2]**pos++;
if (hasAlpha) *alpha++=*pos++;
*writer++=(unsigned char)average;
}
else {
if (hasAlpha) {
while (--sampleCounter) average+=*pos++;
*writer++=(unsigned char)(average/(samples-1));
*alpha++=*pos++;
}
else {
while (sampleCounter--) average+=*pos++;
*writer++=(unsigned char)(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;
double average=0;
if (sampleCounter==3 || (sampleCounter==4 && hasAlpha)) {
average+=conversionWeights[0]*planes[0][i+offset];
average+=conversionWeights[1]*planes[1][i+offset];
average+=conversionWeights[2]*planes[2][i+offset];
if (hasAlpha) *alpha++=planes[3][i+offset];
*writer++=(unsigned char)average;
}
else {
if (hasAlpha) {
*alpha++=planes[--sampleCounter][i+offset];
while (sampleCounter--) average+=planes[sampleCounter][i+offset];
*writer++=(unsigned char)(average/(samples-1));
}
else {
while (sampleCounter--) average+=planes[sampleCounter][i+offset];
*writer++=(unsigned char)(average/samples);
}
}
}
}
}
NSImage* newImage=[[[NSImage alloc] initWithSize:[self size]] autorelease];
[newImage addRepresentation:grayBitmap];
return newImage;
}


References: 
 >Re: Drawing NSImage in grayscale (From: Tom Waters <email@hidden>)

  • Prev by Date: Re: Creating a thumbnail without Photshop. How?
  • Next by Date: Quartz documentation
  • Previous by thread: Re: Drawing NSImage in grayscale
  • Next by thread: Re: Number Formatting
  • Index(es):
    • Date
    • Thread