Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 659
Thanks Avatar asked Jan 23 '23 14:01

Thanks


1 Answers

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
}
like image 103
Jim Dovey Avatar answered Jan 29 '23 08:01

Jim Dovey