The quickest way I can think of is to get a pointer to the buffer for each image and combine them in a third buffer looping through all of the pixels, like you mentioned.
Or if the source (color) image has an alpha channel, but it is set to 1 just replace that channel with the alpha from the second image.
Starting in Panther Quartz has an alpha only bitmap context that can be used to mask other images. The excellent book programming with quartz 2d and pdf graphics in mac os x has a section on alpha only bitmap contexts.
To get the alpha from a crunched PNG file you can do something similar to the following:
CGImageRef myImage = [self CGImage];
CGSize newSize = {CGImageGetWidth(myImage), CGImageGetHeight(myImage)};
if(!isPowerOf2(newSize.width))
newSize.width = nextPowerOf2(newSize.width);
if(!isPowerOf2(newSize.height))
newSize.height = nextPowerOf2(newSize.height);
const GLint picSize = newSize.height * newSize.width * 4;
// The bitmapinfo provided by the CGImageRef isn't supported by the bitmap context.
// So I'll make a conforming bitmap info
CGBitmapInfo myInfo = kCGImageAlphaPremultipliedLast;
unsigned char * actual_bytes = new unsigned char[picSize];
CGContextRef imageContext = CGBitmapContextCreate(
actual_bytes,
newSize.width,
newSize.height,
CGImageGetBitsPerComponent(myImage),
newSize.width * 4,
CGImageGetColorSpace(myImage),
myInfo);
CGContextSaveGState(imageContext);
CGContextDrawImage(imageContext, [self bounds], myImage);
CGContextRestoreGState(imageContext);
At this point actual_bytes has the RGBA data. Don't forget to delete the memory for actual_bytes. This is a category on UIImage so self is a UIImage that has already been loaded from a PNG file.