Image resized error: CGBitmapContextCreate: unsupported parameter - iphone

I am using the following code (from a blog post) to resize an image
if (inImage.size.width <= inImage.size.height) {
// Portrait
ratio = inImage.size.height / inImage.size.width;
resizedRect = CGRectMake(0, 0, width, width * ratio);
}
else {
// Landscape
ratio = inImage.size.width / inImage.size.height;
resizedRect = CGRectMake(0, 0, height * ratio, height);
}
CGImageRef imageRef = [inImage CGImage];
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
if (alphaInfo == kCGImageAlphaNone)
alphaInfo = kCGImageAlphaNoneSkipLast;
CGContextRef bitmap = CGBitmapContextCreate(
NULL,
resizedRect.size.width, // width
resizedRect.size.height, // height
CGImageGetBitsPerComponent(imageRef), // really needs to always be 8
4 * resizedRect.size.width, // rowbytes
CGImageGetColorSpace(imageRef),
alphaInfo
);
but for some reason depending on the size I am try to resize to I get the following error generated
CGBitmapContextCreate: unsupported
parameter combination: 8 integer
bits/component; 32 bits/pixel;
3-component colorspace;
kCGImageAlphaNoneSkipFirst; XXX
bytes/row.
where XXX differs depending on which image.
The rect I am creating is propotional to the image, I take a ratio from the width/height (depending on aspect) and multiple that be target width/height.
Here are some examples (X errors, / doesnt), the resize size will be 50xX or Xx50 depending on aspect:
Source 50x50 69x69
430x320 / X
240x320 / /
272x320 / /
480x419 / X
426x320 X X
480x256 X X

Where you wrote thumbRect, did you mean resizedRect? thumbRect does not otherwise occur.
I suspect the problem is that resizedRect.size.width is non integral. Note that it's floating point.
The width and bytesPerRow parameters of CGBitmapContextCreate are declared as integers. When you pass a floating point value, such as here, it gets truncated.
Suppose your resizedRect.size.width is 1.25. Then you will end up passing 1 for the width, and floor(1.25 * 4) == 5 as the bytes per row. That's inconsistent. You always want to pass four times whatever you passed for the width for the bytes per row.
You can also just leave bytesPerRow as 0, by the way. Then the system picks the best bytesPerRow (which is often larger than 4 times the width - it pads out for alignment).

Related

How to create a bitmap context for an alpha mask image?

I want to draw an alpha mask image in code. Right now I do:
1) Create a bitmap context using CGBitmapContextCreate with options CGColorSpaceCreateDeviceRGB and kCGImageAlphaPremultipliedFirst.
2) Then I draw into this context, using only grayscale colors like white and black.
3) Then I create a mask image from that context, using CGImageMaskCreate.
Conclusion: I waste a lot of memory! Because from my understanding, a mask image is grayscale only, right? So why create a context in ARGB in the first place.
How can I create a CGContextRef that is intended to be used for drawing a mask image? My thoughts are to use CGColorSpaceCreateDeviceGray, but here the problems start. This is the exact code how I create my ARGB bitmap context:
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
uint32_t * bitmapData;
int imageWidth = round(size.width);
int imageHeight = round(size.height);
int bitmapBytesPerRow = (imageWidth * 4);
int bitmapByteCount = (bitmapBytesPerRow * imageHeight);
colorSpace = CGColorSpaceCreateDeviceRGB();
bitmapData = malloc(bitmapByteCount);
context = CGBitmapContextCreate(bitmapData,
imageWidth,
imageHeight,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
I am not sure how to compute the bitmapBytesPerRow for such a context. I assume it would be just imageWidth? And what must I supply for bits per component in CGBitmapContextCreate?
There is CGColorSpaceGetNumberOfComponents() but it reports only the number of components. This does not tell me how many bytes a component has.
Also what makes me nervous is that the 4 and 8 are hard-coded in my code above. Who says it's always 4 bytes per component, and who says it's 8 bits per component? I just took this from various sample codes out there. Everyone seems to do it this way. It works. But future proof? Probably not.
You would make my day with some great answers. Thanks.
Edit: I found a code-snippet, but it is confusing:
CGColorSpaceRef colorSpace2 = CGColorSpaceCreateDeviceGray();
CGContextRef gradientBitmapContext = CGBitmapContextCreate (NULL, 1, reflectRect.size.height,8, 0, colorSpace2, kCGImageAlphaNone);
Why 0 for bytes per row? The documentation does not say you can pass 0. Looks wrong.
Those parameters are telling the system how to treat the data or memory you supply. You have created that yourself, so you know what layout you intend. What, if anything, the system might want to do with it behind the scenes is not your immediate problem.
In this case, you'll provide 8 bits per sample, with just the 1 component, and probably not want to use any row padding, in which case your bytesPerRow should indeed be the same as the image width.

iPhone SDK - Optimize a for loop

I'm developing an image processing application and I'm looking for an advise to tune my code.
My need is to split the image into blocs (80x80), and for each blocs, calculate the average color.
My first method contains the main loops where the second method is called :
- (NSArray*)getRGBAsFromImage:(UIImage *)image {
int width = image.size.width;
int height = image.size.height;
int blocPerRow = 80;
int blocPerCol = 80;
int pixelPerRowBloc = width / blocPerRow;
int pixelPerColBloc = height / blocPerCol;
int xx,yy;
// Row loop
for (int i=0; i<blocPerRow; i++) {
xx = (i * pixelPerRowBloc) + 1;
// Colon loop
for (int j=0; j<blocPerCol; j++) {
yy = (j * pixelPerColBloc) +1;
[self getRGBAsFromImageBloc:image
atX:xx
andY:yy
withPixelPerRow:pixelPerRowBloc
AndPixelPerCol:pixelPerColBloc];
}
}
// return my NSArray not done yet !
}
My second method browses the pixel bloc and returns a ColorStruct :
- (ColorStruct*)getRGBAsFromImageBloc:(UIImage*)image
atX:(int)xx
andY:(int)yy
withPixelPerRow:(int)pixelPerRow
AndPixelPerCol:(int)pixelPerCol {
// First get the image into your data buffer
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
// Now your rawData contains the image data in the RGBA8888 pixel format.
int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
int currentAlpha;
// bloc loop
for (int i = 0 ; i < (pixelPerRow*pixelPerCol) ; ++i) {
currentAlpha = rawData[byteIndex + 3];
red += (rawData[byteIndex] ) * currentAlpha;
green += (rawData[byteIndex + 1]) * currentAlpha;
blue += (rawData[byteIndex + 2]) * currentAlpha;
alpha += currentAlpha;
byteIndex += 4;
if ( i == pixelPerRow ) {
byteIndex += (width-pixelPerRow) * 4;
}
}
red /= alpha;
green /= alpha;
blue /= alpha;
ColorStruct *bColorStruct = newColorStruct(red, blue, green);
free(rawData);
return bColorStruct;
}
ColorStruct :
typedef struct {
int red;
int blue;
int green;
} ColorStruct;
with constructor :
ColorStruct *newColorStruct(int red, int blue, int green) {
ColorStruct *ret = malloc(sizeof(ColorStruct));
ret->red = red;
ret->blue = blue;
ret->green = green;
return ret;
}
As you can see, I have three level of loop : the row loop, the colon loop, and the bloc loop.
I have tested my code and it takes about 5 to 6 seconds for an 320x480 pictures.
Any help is welcomed.
Thanks,
Bahaaldine
Seem like a perfect problem to give it the Grand Central Dispatch ?
I think the main problem in this code is there are too many image reads. The entire image is loaded to memory for every(!) block (malloc is expensive too). You should preload image data once (cache it) and then use that memory in getRGBAsFromImageBloc(). Now for 320x480 picture you have 4 x 6 = 24 blocks. So you can speed up you app manyfold by only using caching.
At the end of the day taking an image and performing three multiplies and five additions on each pixel sequentially is always going to be relatively slow.
Luckily, what you're doing can be thought of as a special case of interpolating an image from one size to another - i.e. the average pixel of an image is the same as that image resized to a size of 1x1 (assuming the resizing is using some form of linear interpolation, but that's usually the standard way to do it) and there's a few highly optimized (or at least more optimized than you're likely to get without enormous effort) options for doing that that are part of the iPhone's graphics libraries. At first I'd try using the Quartz methods to resize an image:
CGImageRef sourceImage = yourImage;
int numBytesPerPixel = 4;
u_char* scaledImageData = (u_char*)malloc(numBytesPerPixel);
CGColorSpaceRef colorspace = CGImageGetColorSpace(sourceImage);
CGContextRef context = CGBitmapContextCreate (scaledImageData, 1, 1, 8, numBytesPerPixel, colorspace, kCGImageAlphaNoneSkipFirst);
CGColorSpaceRelease(colorspace);
CGContextDrawImage(context, CGRectMake(0,0,1,1), sourceImage);
int a = scaledImageData[0];
int r = scaledImageData[1];
int g = scaledImageData[2];
int b = scaledImageData[3];
(this just scales the original image down to 1 pixel and doesn't show the cropping of the sub regions but unfortunately I don't have time for that code right now - if you try to implement it and get stuck add a comment and I can show you how you would do that).
If that doesn't work you could always try using OpenGL ES to do this (create a texture out of the part of your image you need to scale, render it to a 1x1 buffer, and test the result from the buffer). This is a lot more complicated but might have some advantages in that it gives you access to the GPU, which might be a lot faster for large images.
Hope that makes sense and helps...
P.S. - Definitely follow y0prst's suggestion and only read the image in once - that is an easy fix that is going to buy you a ton of performance.
P.P.S - I haven't tested the code so usual caveats apply.
You're inspecting every single pixel - something that, it would seem, is going to take roughly the same amount of time no matter how you loop through it (provided you only inspect each pixel once).
I would suggest using a random sampling within the bloc - every "n'th" pixel, which would reduce the loop time (and the accuracy), or allow for an adjustable granularity.
Now, if there is an existing algorithm for computing the average of a group of pixels - that would be something to consider as an alternative.
You can speed things up by not calling a method in the middle of your loop. Just include the code inline.
ADDED: Also, you might try doing the draw image only once, not repeated in a loop, if you have enough memory.
After you do that, you can try hoisting some of the multiplies out of the inner loop as well for a little additional performance (although the Compiler may optimize some of this for you).

Using image created with CGBitmapContextCreate as an opengl texture

I'm generating an image using quartz2d and I want to use it as an opengl texture.
The tricky part is that I want to use as few bits per pixel as possible, so I'm creating cgContext as following:
int bitsPerComponent = 5;
int bytesPerPixel = 2;
int width = 1024;
int height = 1024;
void* imageData = malloc(width * height * bytesPerPixel);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageContext context = CGBitmapContextCreate(imageData, width, height, bitsPerComponent, width * bytesPerPixel, colorSpace, kCGImageAlphaNoneSkipFirst);
//draw things into context, release memory, etc.
As stated in the documentation here, this is the only supported RGB pixel format for CGBitmapContextCreate which uses 16 bits per pixel.
So now I want to upload this imageData which looks like "1 bit skipped - 5 bits red - 5 bits green - 5 bits blue" into an opengl texture. So I should do something like this:
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, imageData);
That won't work because in this call I've specified pixel format as 5 red - 5 green - 5 blue - 1 alpha. That is wrong, but it appears that there is no format that would match core graphics output.
There are some other options like GL_UNSIGNED_SHORT_1_5_5_5_REV, but those wont work on the iphone.
I need some way to use this imageData as a texture, but I really don't want to swap bytes around manually using memset or such, because that seems terribly inefficient.
You do need to swap bits around to get it into a denser format like RGBA551 or RGB565, since as you note, CGBitmapContext does not support these formats for drawing (for simplicity and efficency's sake).
memset isn't going to do the trick, but there are "fast" conversion routines in Accelerate.framework.
See vImageConvert_ARGB8888toRGB565(…) and vImageConvert_ARGB8888toARGB1555(…), available on iOS 5 and later.
For iOS 7.0, OS X.9 and later:
vImage_CGImageFormat fmt = {
.bitsPerComponent = 5,
.bitsPerPixel = 16,
.colorSpace = NULL, // faster with CGImageGetColorSpace(cgImage) if known to be RGB
.bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Little // ARGB1555 little endian
};
vImage_Buffer buf;
vImageBuffer_InitWithCGImage( &buf, &fmt, NULL, cgImage, kvImageNoFlags );
...
free(buf.data);
Data is in buf.data, along with image height, width and rowBytes info. I don't recall what GL's requirements are for whether row padding is allowed. You can control that by preallocating the buf.data and buf.rowBytes fields and passing kvImageDoNotAllocate in the flags.
565_REV is kCGImageAlphaNone | kCGBitmapByteOrder16Little.
5551_REV is kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder16Little

CGPathRef intersection

Is there a way to find out whether two CGPathRefs are intersected or not. In my case all the CGPaths are having closePath.
For example, I am having two paths. One path is the rectangle which is rotated with some angle and the other path is curved path. Two paths origin will be changing frequently. At some point they may intersect. I want to know when they are intersected. Please let me know if you have any solution.
Thanks in advance
Make one path the clipping path, draw the other path, then search for pixels that survived the clipping process:
// initialise and erase context
CGContextAddPath(context, path1);
CGContextClip(context);
// set fill colour to intersection colour
CGContextAddPath(context, path2);
CGContextFillPath(context);
// search for pixels that match intersection colour
This works because clipping = intersecting.
Don't forget that intersection depends on the definition of interiority, of which there are several. This code uses the winding-number fill rule, you might want the even odd rule or something else again. If interiority doesn't keep you up at night, then this code should be fine.
My previous answer involved drawing transparent curves to an RGBA context. This solution is superior to the old one because it is
simpler
uses a quarter of the memory as an 8bit greyscale context suffices
obviates the need for hairy, difficult-to-debug transparency code
Who could ask for more?
I guess you could ask for a complete implementation, ready to cut'n'paste, but that would spoil the fun and obfuscate an otherwise simple answer.
OLDER, HARDER TO UNDERSTAND AND LESS EFFICIENT ANSWER
Draw both CGPathRefs separately at 50% transparency into a zeroed, CGBitmapContextCreate-ed RGBA memory buffer and check for any pixel values > 128. This works on any platform that supports CoreGraphics (i.e. iOS and OSX).
In pseudocode
// zero memory
CGContextRef context;
context = CGBitmapContextCreate(memory, wide, high, 8, wide*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
CGContextSetRGBFillColor(context, 1, 1, 1, 0.5); // now everything you draw will be at 50%
// draw your path 1 to context
// draw your path 2 to context
// for each pixel in memory buffer
if(*p > 128) return true; // curves intersect
else p+= 4; // keep looking
Let the resolution of the rasterised versions be your precision and choose the precision to suit your performance needs.
1) There isn't any CGPath API to do this. But, you can do the math to figure it out. Take a look at this wikipedia article on Bezier curves to see how the curves in CGPath are implemented.
2) This is going to be slow on the iPhone I would expect but you could fill both paths into a buffer in difference colors (say, red and blue, with alpha=0.5) and then iterate through the buffer to find any pixels that occur at intersections. This will be extremely slow.
For iOS, the alpha blend seems to be ignored.
Instead, you can do a color blend, which will achieve the same effect, but doesn't need alpha:
CGContextSetBlendMode(context, kCGBlendModeColorDodge);
CGFloat semiTransparent[] = { .5,.5,.5,1};
Pixels in output Image will be:
RGB = 0,0,0 = (0.0f) ... no path
RGB = 64,64,64 = (0.25f) ... one path, no intersection
RGB = 128,128,128 = (0.5f) ... two paths, intersection found
Complete code for drawing:
-(void) drawFirst:(CGPathRef) first second:(CGPathRef) second into:(CGContextRef)context
{
/** setup the context for DODGE (everything gets lighter if it overlaps) */
CGContextSetBlendMode(context, kCGBlendModeColorDodge);
CGFloat semiTransparent[] = { .5,.5,.5,1};
CGContextSetStrokeColor(context, semiTransparent);
CGContextSetFillColor(context, semiTransparent);
CGContextAddPath(context, first);
CGContextFillPath(context);
CGContextStrokePath(context);
CGContextAddPath(context, second);
CGContextFillPath(context);
CGContextStrokePath(context);
}
Complete code for checking output:
[self drawFirst:YOUR_FIRST_PATH second:YOUR_SECOND_PATH into:context];
// Now we can get a pointer to the image data associated with the bitmap
// context.
BOOL result = FALSE;
unsigned char* data = CGBitmapContextGetData (context);
if (data != NULL) {
for( int i=0; i<width; i++ )
for( int k=0; k<width; k++ )
{
//offset locates the pixel in the data from x,y.
//4 for 4 bytes of data per pixel, w is width of one row of data.
int offset = 4*((width*round(k))+round(i));
int alpha = data[offset];
int red = data[offset+1];
int green = data[offset+2];
int blue = data[offset+3];
if( red > 254 )
{
result = TRUE;
break;
}
}
And, finally, here's a slightly modified code from another SO answer ... complete code for creating an RGB space on iOS 4, iOS 5, that will support the above functions:
- (CGContextRef) createARGBBitmapContextWithFrame:(CGRect) frame
{
/** NB: this requires iOS 4 or above - it uses the auto-allocating behaviour of Apple's method, to reduce a potential memory leak in the original StackOverflow version */
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
// Get image width, height. We'll use the entire image.
size_t pixelsWide = frame.size.width;
size_t pixelsHigh = frame.size.height;
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
// Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return NULL;
}
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (NULL,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst
//kCGImageAlphaFirst
);
if (context == NULL)
{
fprintf (stderr, "Context not created!");
}
// Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );
return context;
}

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.
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
}
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.