Tutorial :How can I obtain clean alpha channel information from an PNG image in iPhone OS?



Question:

I have created an context like this (simplified):

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();    CGContextRef context = CGBitmapContextCreate (bitmapData,    pixWide,    pixHeigh,    8, // bits per component    bitmapBytesPerRow,    colorSpace,    kCGImageAlphaPremultipliedFirst);  

Now, when I try to extract the data for the first pixel in my PNG with Alphatransparency, it has very weird alpha values. I have an simple PNG that's a square. On each edge I cut off 10x10 pixel and made them totally transparent. Alpha shouldn't be something like 153 there.

There's an kCGImageAlphaOnly declared in CGImage.h. The doc says:

kCGImageAlphaOnly There is no color data, only an alpha channel.

Ok, so that actually sounds good, because I only need Alpha data, and nothing else. But this raises some question marks in my head. If I do habe a fully equipped PNG with a bunch of colors + alpha: Would this constant make sure that my PNG is converted to match that color space? Or would I have to provide an PNG that matches that specified color space?

Edit: I tried using kCGImageAlphaOnly, but I get this error:

<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 0-component colorspace; kCGImageAlphaOnly; 55 bytes/row.  

What may be the problem here? I specified this before:

size_t pixelsWide = CGImageGetWidth(inImage);  size_t pixelsHigh = CGImageGetHeight(inImage);  bitmapBytesPerRow = (pixelsWide * 1); // not * 4, because I just want alpha  bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);  

Edit: I've been reading this a minute ago:

PNG's which are added to XCode are optimized by 'pngcrush' during compilation. This does some byte-swapping (from RGBA to BRGA) and pre-multiplication of alpha.

I assume that this pre-multiplication of alpha makes trouble.

Edit: The alpha channel keeps intact after pngcrunch did the byte-swapping stuff to the PNG. Since I don't care about colors, just alpha, that pre-multiplication shouldn't be a too big problem, I think.

My PNG's have been 24bit PNG bevor I added them to Xcode.


Solution:1

You can't do this:

bitmapBytesPerRow = (pixelsWide * 1); // not * 4, because I just want alpha  

The function you're calling will always return all the image data. The kCGImageAlphaOnly constant is used to tell YOU that an image only contains an alpha channel, no colour information.

You'll need to use pixelsWide * 4 for the bytesPerRow. Also note that the bitmapData argument to CGBitmapContextCreate() is used to provide storage space explicitly, rather than having it drawn for you.

Possibly what you want to do is this (untested code, just typed from memory):

CGImageRef image = GetMyImageFromWhereverItIs();  CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();  CGContextRef ctx = CGBitmapContextCreate( NULL, CGImageGetWidth(image),          CGImageGetHeight(image), CGImageGetBitsPerComponent(image),          CGImageGetBytesPerRow(image), space,          kCGBitmapByteOrderDefault | kCGImageAlphaLast );  CGColorSpaceRelease( space );    // now draw the image into the context  CGRect rect = CGRectMake( 0, 0, CGImageGetWidth(image), CGImageGetHeight(image) );  CGContextDrawImage( ctx, rect, image );  UInt32 * pixels = CGBitmapContextGetData( ctx );    // now we can iterate through the data & read the alpha values  int i, count = CGBitmapContextGetBytesPerRow(ctx) * CGBitmapContextGetHeight(ctx);  for ( i = 0; i < count; i++ )  {      UInt8 alpha = pixels[i] & 0x000000ff;      // do with the alpha what you will  }  


Solution:2

Are you sure you're looking only at alpha values?

If you're expecting all the alpha components to come first, then all the red components, etc.: That's planar layout, and I don't think Quartz supports it nativelyâ€"it only supports all the components together in each pixel (ARGBARGBARGBARGB…, not AAAA…RRRR…GGGG…BBBB…). So if you're just marching straight into the data treating every byte as alpha, that's your problem: you're looking at red, green, and blue components and treating them as alpha.

As for premultiplication, that doesn't affect the alpha channel, it affects the color channels. The formula for raster compositing (putting one raster image over another) is:

dst.r = src.r * src.a + dst.r * (1.0 - src.a);  dst.g = src.g * src.a + dst.g * (1.0 - src.a);  dst.b = src.b * src.a + dst.b * (1.0 - src.a);  

Premultiplication cuts out the first multiplication expression:

dst.r = src.r′ + dst.r * (1.0 - src.a);  dst.g = src.g′ + dst.g * (1.0 - src.a);  dst.b = src.b′ + dst.b * (1.0 - src.a);  

This works because the source color components are already multiplied by the alpha componentâ€"hence the name “premultiplied”. It doesn't need to multiply them now, because it already has the results.

It's an optimization, and presumably an important one on the iPhone (all those multiplication operations add up when you do a million or two of them). But it doesn't affect the layout of the components: interleaved remains interleaved, whether the RGB components are premultiplied or not.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »