Pixel editing is usually done with a CGBitmapContext. In this case, I think you will want to create a grayscale bitmap that represents just the alpha channel of the scratch area. As the user scratches, you will paint in this bitmap.
To use a GCBitmapContext as the mask for an image, you must first create a masking image from the bitmap. Use CGImageMaskCreate and pass in a data provider that points to the same pixels used to create the bitmap. Then use CGImageCreateWithMask with your scratch off image and the mask image that is the bitmap.
You cannot draw directly in the iPhone. Every time the user moves a finger, you will have to modify the mask bitmap then invalidate the UIView that draws the image. You may just be able to draw the same image again, or you may need to reconstruct the mask and masked image each time you draw. As long as the mask image refers directly to the bitmap pixel data, very little memory is actually allocated.
So in psuedocode you want something like this:
scratchableImage = ...
width = CGImageGetWidth( scratchableImage );
height = CGImageGetHeight( scratchableImage );
colorspace = CGColorSpaceCreateDeviceGray();
pixels = CFDataCreateMutable( NULL , width * height );
bitmap = CFBitmapContextCreate( CFDataGetMutableBytePtr( pixels ) , width , height , 8 , width , colorspace , kCGImageAlphaNone );
provider = CGDataProviderCreateWithCFData( pixels );
mask = CGImageMaskCreate( width , height , 8 , 8 , width , provider , NULL , false , kCGRenderingIntentDefault );
scratched = CGImageCreateWithImageInRect( scratchableImage , mask );
At this point, scratched
will have an alpha channel dictated by bitmap
but bitmap
has garbage data. White pixels
in bitmap are opaque, and black pixels are clear. Paint all white pixels in bitmap
then, as the user scratches, paint black pixels. I think that changes to bitmap
will automatically apply every time scratched
is drawn, but if not then just recreate mask
and scratched
every time you draw.
You probably have a custom UIView for tracking user input. You could derive your custom view from UIImageView and let it draw the image or do the following:
-(void) drawRect:(CGRect)inDirty {
// assume scratched is a member
CGContextDrawImage( UIGraphicsGetCurrentContext() , [self bounds] , scratched );
}
Alternately you can skip creating scratched
and instead use CGContextClipToMask
and draw the original scratchableImage
directly. If there is no scratchableImage
and your scratch area is a texture or view hierarchy, take this approach.