FROM : Christian Kaiser
DATE : Thu Apr 03 21:14:15 2008
Thank to all those who tried to help me with my problem.
My gradient color problem is just a simplified version of what I have to
do. I need to do a scientific simulation where I have to set the color
of random pixels to a given color which corresponds to a value inside a
given range. So I really need to compute the gradient color and set each
pixel separately.
Thanks to Eddie Herbert, I was not aware of the existence of the blend
function in the NSColor class.
Finally, I could locate the problem to reside in the NSBitmapImageRep
setColor:atX:y: method. If I understand this method correctly, it is
supposed to do something like this (if the color space of the image rep
and the provided color are the same):
-(void)setColor:(NSColor*)color atX:(NSInteger)x y:(NSInteger)y
{
CGFloat comps[5];
[color getComponents:comps];
NSInteger i;
NSUInteger intComps[5];
for (i = 0; i < [self samplesPerPixel]; i++)
{
intComps[i] = comps[i] * 255;
}
[self setPixel:intComps atX:x y:y];
}
Using this method instead of the one provided by the original
NSBitmapImageRep, the image gets rendered as expected.
I am not understanding correctly the setColor:atX:y: class or it is a
bug... I would be glad to have an advise whether to file a bug report or
not (I have never done this).
Thanks again for your help !
Cheers,
Christian Kaiser
Jean-Daniel Dupas wrote:
> Don't know why you got this problem, but if I had to fill a bitmap
> using a simple gradient, i would probably use either CGGradient
> (Leopard required) or CGShading (if you want a greater control of the
> shading function, etc...).
>
> It can be done like this:
>
> NSGraphicsContext *ctxt = [NSGraphicsContext
> graphicsContextWithBitmapImageRep:imageRep]; /* see doc for details
> about bitmap format supported */
> CGContextRef cgctxt = [ctxt graphicPort];
> CGShadingRef shading = CGShadingCreate(...); /* see Quartz 2D
> programming guide */
> CGContextDrawShading(cgctxt, shading);
> CGShadingRelease(shading);
>
> This will be really faster than creating a NSColor object for each pixel.
>
> In the same way, you can fill it with an uniform color using
> CGContextFillRect() function.
>
> And is you want to use Cocoa drawing function instead, set your new
> context as the current context using -[NSGraphicsContext
> setCurrentContext:] and the you will be able to call NSBezierPath
> function for example.
>
>
> Le 31 mars 08 à 21:30, Christian Kaiser a écrit :
>> I'm struggling with setting color in a NSBitmapImageRep. I'm
>> computing the components of a NSColor according to a numeric value;
>> its basically a linear interpolation between all components of two
>> NSColors. I've got a function which is computing the new NSColor
>> based on a given value. If I call this function repeatedly using the
>> same value and setting the color using NSBitmapImageRep
>> setColor:atX:y:, I expect to have a uniform image if applying to all
>> pixels. But this is not the case...! What am I missing ?
>>
>> As I'm probably a little bit confusing, here the code producing my
>> strange image :
>>
>>
>>
>> // Creating two colors which define a gradient. The color for our image
>> // will be computed using this gradient.
>>
>> NSColor *lightYellow =
>> [NSColor colorWithCalibratedRed:0.97 green:0.93 blue:0.65
>> alpha:1.0];
>> NSColor *darkRed =
>> [NSColor colorWithCalibratedRed:0.69 green:0.09 blue:0.11
>> alpha:1.0];
>>
>>
>> // Creating an empty image with the same color space.
>>
>> NSBitmapImageRep *img = [[NSBitmapImageRep alloc]
>> initWithBitmapDataPlanes:NULL
>> pixelsWide:10
>> pixelsHigh:10
>> bitsPerSample:8
>> samplesPerPixel:3
>> hasAlpha:NO
>> isPlanar:YES
>> colorSpaceName:[lightYellow colorSpaceName]
>> bitmapFormat:0
>> bytesPerRow:0
>> bitsPerPixel:0];
>>
>> // Assigning the same (???) color to all pixels.
>> int x, y;
>> for (y = 0; y < 10; y++)
>> {
>> for (x = 0; x < 10; x++)
>> {
>> NSColor *imgColor = [GradientColor gradientColorWithValue:40.0
>> minColor:lightYellow maxColor:darkRed
>> minValue:30.0 maxValue:60.0];
>> [img setColor:imgColor atX:x y:y];
>> }
>> }
>> [[img TIFFRepresentation]
>> writeToFile:@"/Users/chkaiser/Desktop/img.tif" atomically:YES];
>>
>>
>> And the function computing the gradient color based on our values:
>>
>> +(NSColor*)gradientColorWithValue:(double)value minColor:(NSColor*)c1
>> maxColor:(NSColor*)c2 minValue:(double)v1 maxValue:(double)v2
>> {
>> // Color components.
>> CGFloat comps1[5];
>> [c1 getComponents:comps1];
>> CGFloat comps2[5];
>> [c2 getComponents:comps2];
>> // Compute the multiplication factor for the value. This factor has
>> // a value between 0 and 1.
>> double factor = (value - v1) / (v2 - v1);
>> // Compute the new components.
>> int i;
>> CGFloat newComps[5];
>> for (i = 0; i < [c1 numberOfComponents]; i++)
>> {
>> newComps[i] =
>> (factor * (comps2[i] - comps1[i])) +
>> comps1[i];
>> }
>> // Create the new color with the computed components.
>> NSColor *newColor = [NSColor colorWithColorSpace:[c1 colorSpace]
>> components:newComps count:[c1 numberOfComponents]];
>> return newColor;
>> }
>>
>>
>> What is going wrong here ?
>>
>> I have not found any similar topic on this list until now, even if it
>> seems to me quite strange. Is there something obvious I am missing ?
>>
>> --Christian Kaiser
>>
DATE : Thu Apr 03 21:14:15 2008
Thank to all those who tried to help me with my problem.
My gradient color problem is just a simplified version of what I have to
do. I need to do a scientific simulation where I have to set the color
of random pixels to a given color which corresponds to a value inside a
given range. So I really need to compute the gradient color and set each
pixel separately.
Thanks to Eddie Herbert, I was not aware of the existence of the blend
function in the NSColor class.
Finally, I could locate the problem to reside in the NSBitmapImageRep
setColor:atX:y: method. If I understand this method correctly, it is
supposed to do something like this (if the color space of the image rep
and the provided color are the same):
-(void)setColor:(NSColor*)color atX:(NSInteger)x y:(NSInteger)y
{
CGFloat comps[5];
[color getComponents:comps];
NSInteger i;
NSUInteger intComps[5];
for (i = 0; i < [self samplesPerPixel]; i++)
{
intComps[i] = comps[i] * 255;
}
[self setPixel:intComps atX:x y:y];
}
Using this method instead of the one provided by the original
NSBitmapImageRep, the image gets rendered as expected.
I am not understanding correctly the setColor:atX:y: class or it is a
bug... I would be glad to have an advise whether to file a bug report or
not (I have never done this).
Thanks again for your help !
Cheers,
Christian Kaiser
Jean-Daniel Dupas wrote:
> Don't know why you got this problem, but if I had to fill a bitmap
> using a simple gradient, i would probably use either CGGradient
> (Leopard required) or CGShading (if you want a greater control of the
> shading function, etc...).
>
> It can be done like this:
>
> NSGraphicsContext *ctxt = [NSGraphicsContext
> graphicsContextWithBitmapImageRep:imageRep]; /* see doc for details
> about bitmap format supported */
> CGContextRef cgctxt = [ctxt graphicPort];
> CGShadingRef shading = CGShadingCreate(...); /* see Quartz 2D
> programming guide */
> CGContextDrawShading(cgctxt, shading);
> CGShadingRelease(shading);
>
> This will be really faster than creating a NSColor object for each pixel.
>
> In the same way, you can fill it with an uniform color using
> CGContextFillRect() function.
>
> And is you want to use Cocoa drawing function instead, set your new
> context as the current context using -[NSGraphicsContext
> setCurrentContext:] and the you will be able to call NSBezierPath
> function for example.
>
>
> Le 31 mars 08 à 21:30, Christian Kaiser a écrit :
>> I'm struggling with setting color in a NSBitmapImageRep. I'm
>> computing the components of a NSColor according to a numeric value;
>> its basically a linear interpolation between all components of two
>> NSColors. I've got a function which is computing the new NSColor
>> based on a given value. If I call this function repeatedly using the
>> same value and setting the color using NSBitmapImageRep
>> setColor:atX:y:, I expect to have a uniform image if applying to all
>> pixels. But this is not the case...! What am I missing ?
>>
>> As I'm probably a little bit confusing, here the code producing my
>> strange image :
>>
>>
>>
>> // Creating two colors which define a gradient. The color for our image
>> // will be computed using this gradient.
>>
>> NSColor *lightYellow =
>> [NSColor colorWithCalibratedRed:0.97 green:0.93 blue:0.65
>> alpha:1.0];
>> NSColor *darkRed =
>> [NSColor colorWithCalibratedRed:0.69 green:0.09 blue:0.11
>> alpha:1.0];
>>
>>
>> // Creating an empty image with the same color space.
>>
>> NSBitmapImageRep *img = [[NSBitmapImageRep alloc]
>> initWithBitmapDataPlanes:NULL
>> pixelsWide:10
>> pixelsHigh:10
>> bitsPerSample:8
>> samplesPerPixel:3
>> hasAlpha:NO
>> isPlanar:YES
>> colorSpaceName:[lightYellow colorSpaceName]
>> bitmapFormat:0
>> bytesPerRow:0
>> bitsPerPixel:0];
>>
>> // Assigning the same (???) color to all pixels.
>> int x, y;
>> for (y = 0; y < 10; y++)
>> {
>> for (x = 0; x < 10; x++)
>> {
>> NSColor *imgColor = [GradientColor gradientColorWithValue:40.0
>> minColor:lightYellow maxColor:darkRed
>> minValue:30.0 maxValue:60.0];
>> [img setColor:imgColor atX:x y:y];
>> }
>> }
>> [[img TIFFRepresentation]
>> writeToFile:@"/Users/chkaiser/Desktop/img.tif" atomically:YES];
>>
>>
>> And the function computing the gradient color based on our values:
>>
>> +(NSColor*)gradientColorWithValue:(double)value minColor:(NSColor*)c1
>> maxColor:(NSColor*)c2 minValue:(double)v1 maxValue:(double)v2
>> {
>> // Color components.
>> CGFloat comps1[5];
>> [c1 getComponents:comps1];
>> CGFloat comps2[5];
>> [c2 getComponents:comps2];
>> // Compute the multiplication factor for the value. This factor has
>> // a value between 0 and 1.
>> double factor = (value - v1) / (v2 - v1);
>> // Compute the new components.
>> int i;
>> CGFloat newComps[5];
>> for (i = 0; i < [c1 numberOfComponents]; i++)
>> {
>> newComps[i] =
>> (factor * (comps2[i] - comps1[i])) +
>> comps1[i];
>> }
>> // Create the new color with the computed components.
>> NSColor *newColor = [NSColor colorWithColorSpace:[c1 colorSpace]
>> components:newComps count:[c1 numberOfComponents]];
>> return newColor;
>> }
>>
>>
>> What is going wrong here ?
>>
>> I have not found any similar topic on this list until now, even if it
>> seems to me quite strange. Is there something obvious I am missing ?
>>
>> --Christian Kaiser
>>
| Related mails | Author | Date |
|---|---|---|
| Christian Kaiser | Mar 31, 21:30 | |
| Jean-Daniel Dupas | Mar 31, 23:39 | |
| Christian Kaiser | Apr 3, 21:14 |






Cocoa mail archive

