Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

KnightWRX

macrumors Pentium
Original poster
Jan 28, 2009
15,046
4
Quebec, Canada
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 :

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 :

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, 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).
 
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.
 
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.
 
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.
 
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.
 
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.
 
If you want to fill your context with a color then you should fill your context with a color.

Code:
CGContextSetFillColorWithColor(context, backgroundColor);
CGContextFillRect(context, bounds);
 
If you want to fill your context with a color then you should fill your context with a color.

Code:
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.