PDA

View Full Version : Initializing a pixel array from a CGBitmapContext




KnightWRX
Jul 23, 2011, 09:23 AM
Hi!

Ran into an issue with PNGs having transparent backgrounds and applying them into a pixel array using a CGBitmapContext. This was the "faulty" code :


-(id) initWithCGImage: (CGImageRef) image
{
NSInteger bytes;
self = [super init];

CGColorSpaceRef colorSpace;

width = CGImageGetWidth(image);
height = CGImageGetHeight(image);
bytesPerChannel = 4;

colorSpace = CGColorSpaceCreateDeviceRGB();
bytes = width * height * sizeof(BRUnifiedPixelRGBA);
imagePixels = malloc(bytes);
//[self resetToSolidColor: 0x00000000];
CGContextRef context = CGBitmapContextCreate(imagePixels,
width,
height,
8,
width * bytesPerChannel,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextDrawImage(context,
CGRectMake(0.0f, 0.0f, width, height),
image);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);

return self;
}


This ended up giving artifacts (from previously used and discarded memory regions in all probability) that basically looked like this :

http://i174.photobucket.com/albums/w114/redkteg97/iPhone%20Programming/Screenshot2011-07-23at101633AM.png

(Please save the laughter and comments about my graphical skills for yourselves. Consider it an honor to have seen a very, very early screenshot).

Now, my question, short of resetting the entire pixel buffer memory after allocation (either with memcpy() or with a for loop, which [-(void) resetToSolidColor basically is), is there some parameters I can pass to CGBitmapContextCreate to tell it to not do alpha blending and just squash whatever is there ?

Reading through CGImageAlphaInfo (http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGImage/Reference/reference.html#//apple_ref/doc/c_ref/CGBitmapInfo), I'm not quite sure I understand the Premultiplied vs well... not premultiplied bit. Is that what I'm looking for or really is there just no way to do this short of resetting memory myself ?

(BTW, yes, I realise the BytesPerChannel variable is very poorly named. There is only 1 byte per channel, 4 channels per pixel... whatever, call it lazyness on my part, this code was written a very long time ago and I'm just now using it with transparent PNGs).



chown33
Jul 23, 2011, 12:04 PM
Call calloc() instead of malloc() and the memory will be returned zeroed. See the man page for calloc.

Otherwise you'll have to zero it yourself. Assuming zeroing is the desired state for the pixel format.

KnightWRX
Jul 23, 2011, 03:47 PM
Call calloc() instead of malloc() and the memory will be returned zeroed. See the man page for calloc.

Otherwise you'll have to zero it yourself. Assuming zeroing is the desired state for the pixel format.

Yes 0 is fine since this is a transparent png the alpha channel needs to be set to 0 or otherwise it would mess up when I merge 2 images.

Hum... calloc has a bit of a different calling convention than malloc, dunno if I want to mess with that. The resetToSolidColor function is actually quite useful in initializing flat color surfaces, which I use a lot. I think I'll just keep that and make the 0x0 value a constant like my other color constants and clean up the code a bit.

But can someone still explain what the Alpha premultiplied vs not pre-multiplied means ? The documentation isn't quite clear there.

chown33
Jul 23, 2011, 04:16 PM
Hum... calloc has a bit of a different calling convention than malloc, dunno if I want to mess with that.

It's simple C. You'll have to read the man page, but it's not hard.

The resetToSolidColor function is actually quite useful in initializing flat color surfaces, which I use a lot. I think I'll just keep that and make the 0x0 value a constant like my other color constants and clean up the code a bit.

No harm in that.

But can someone still explain what the Alpha premultiplied vs not pre-multiplied means ? The documentation isn't quite clear there.

Did google stop working?

If I start typing "premult", the first suggestion is "premultiplied alpha".
If I choose that, the first result is a Wikipedia article:
http://en.wikipedia.org/wiki/Alpha_compositing

If I find "premult" on the page, an explanation and example moves into view.

firewood
Jul 23, 2011, 11:20 PM
non-premultiplied means your 8-bit RGB values are full scaled to go from 0 to 255

premultiplied means your 8-bit RGB values are scaled to go from 0 to Alpha,
where Alpha can be less than 255.

KnightWRX
Jul 24, 2011, 11:59 AM
It's simple C. You'll have to read the man page, but it's not hard.

I'm sure it's not, but allocating a sized object and then a count of those means I need to sit down and read it, when basically, I already wrote the "zeroing" code which also serves another purpose on top of it.


Did google stop working?

If I start typing "premult", the first suggestion is "premultiplied alpha".
If I choose that, the first result is a Wikipedia article:
http://en.wikipedia.org/wiki/Alpha_compositing

If I find "premult" on the page, an explanation and example moves into view.

Sorry, I was stuck on Apple's documentation and didn't think this was a broader concept concerning Alpha blending. The wikipedia page was quite clear and it has nothing to do with what I wanted. I really guess calloc() or malloc() plus a full buffer initalization is the only way to not screw up the transparent background when copying the PNG using a CGBitmapContext. Anyway, the code works great now.

PhoneyDeveloper
Jul 24, 2011, 06:27 PM
If you want to fill your context with a color then you should fill your context with a color.

CGContextSetFillColorWithColor(context, backgroundColor);
CGContextFillRect(context, bounds);

KnightWRX
Jul 25, 2011, 12:11 PM
If you want to fill your context with a color then you should fill your context with a color.

CGContextSetFillColorWithColor(context, backgroundColor);
CGContextFillRect(context, bounds);


That actually wouldn't work at all in my case. I'll leave you to think on why not. ;) Hint: It would result in the same broken behavior with artifacts.