views:

38

answers:

1

Hello,

I am currently making a basic image editor for iphone.

I take the CGImageRef from a UIImage and create a context for it using the following code

origImage = result.CGImage;

Iheight = CGImageGetHeight(origImage);
Iwidth = CGImageGetWidth(origImage);
IcolorSpace = CGColorSpaceCreateDeviceRGB();
IrawData = malloc(Iheight * Iwidth * 4);
IbytesPerPixel = 4;
IbytesPerRow = IbytesPerPixel * Iwidth;
IbitsPerComponent = 8;
Icontext = CGBitmapContextCreate(IrawData, Iwidth, Iheight, IbitsPerComponent,
                                 IbytesPerRow, IcolorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
                                 );
//[bytesPerRow release];
CGContextSetBlendMode(Icontext, kCGBlendModeCopy);
CGContextDrawImage(Icontext, CGRectMake(0,0,Iwidth,Iheight),  origImage);

I then loop through the pixels

for (int x=0; x<Iwidth; x++) {
    for (int y=0; y<Iheight; y++) {
            //and  set the alpha component to 0
            int byteIndex = (y*IbytesPerRow) + x*IbytesPerPixel;

            IrawData[byteIndex+3] = 0;

            }
}

and then create a CGImageRef from the context with

    CGImageRef imagea = CGBitmapContextCreateImage(Icontext);

and add the CGImage to a UIImage and assign to a UIImageView

The problem is that the change of alpha isn't effecting the resultant image

if I change the colour of the pixels with

IrawData[byteIndex+(0/1/2)]

the colour changes, but I still can't change the alpha of the pixel

Thank you,

nonono

+1  A: 

Don't forget to unpremultiply the colors before changing the alpha, and re-premultiply them afterward.

Premultiplied color (often called “premultiplied alpha”, which is misleading) means that the color components are stored already multiplied by the alpha, to ease compositing. The usual compositing (source-over) operation looks like this:

result = (source.rgb * source.a) + (destination.colors * (1.0 - destination.a));

Premultiplication means that the first multiplication is already done, so it can be skipped:

result =  source.rgb             + (destination.colors * (1.0 - destination.a));

When you change the alpha without changing the premultiplied color components, the result doesn't change—when you draw the image, it will look no different, because the colors are still premultiplied by the old alpha.

So, you need to unpremultiply the colors—that is, divide each one by the alpha (as previously it was multiplied, so you must now do the inverse)—before you change the alpha. Then, after changing the alpha, premultiply the colors by the new alpha.

Of course, this means that when changing the alpha to zero, all the colors will go black (r=g=b=0). So, make sure you keep the original image if the user might want to change it back.

It would probably be more effective, and would certainly be easier, to just draw the original image (without any alpha changes made to it) at whatever alpha the user wants. You can do this by changing your display context's global alpha before you draw the image.

Peter Hosey
thank you for the answer. I understand what your saying, but I'm not sure how to implement this in my code, would you mind please giving a code sample? Thank you
nonono
As I said, the best way is probably just to set your display context's global alpha, then draw the original image. I linked to the function for the first step, and you already know how to do the second step.
Peter Hosey