Art Gillespie

November 3, 2009 at 8:40pm
home

Getting a UIImage’s raw pixel data.

Getting at a UIImage’s raw pixel data so you can process it is trickier than you might first think—it’s certainly trickier than I expected—and neither Apple’s documentation nor Google are much help. The first challenge is getting a mutable copy of the UIImage’s raw pixel data; the second is making sure that you keep the UIImage’s orientation straight. The former was relatively easy to figure out, the latter took me a few hours.

Here’s my solution in hopes that the next person that Googles ‘UIImage raw pixel data’ saves a little time.

UPDATE: A blog post probably isn’t the best way to put this much code across, so I’ve released the source for an iPhone OS app that makes use of this code under the MIT License over at BitBucket

UIImage * gs_convert_image (UIImage * src_img) {

    [src_img retain];

    CGColorSpaceRef d_colorSpace = CGColorSpaceCreateDeviceRGB();
    /*
     * Note we specify 4 bytes per pixel here even though we ignore the
     * alpha value; you can't specify 3 bytes per-pixel.
     */
    size_t d_bytesPerRow = src_img.size.width * 4; 
    unsigned char * imgData = (unsigned char*)malloc(src_img.size.height*d_bytesPerRow);
    CGContextRef context =  CGBitmapContextCreate(imgData, src_img.size.width, 
                                                  src_img.size.height, 
                                                  8, d_bytesPerRow, 
                                                  d_colorSpace, 
                                                  kCGImageAlphaNoneSkipFirst);

    UIGraphicsPushContext(context);
    // These next two lines 'flip' the drawing so it doesn't appear upside-down.
    CGContextTranslateCTM(context, 0.0, src_img.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    // Use UIImage's drawInRect: instead of the CGContextDrawImage function, otherwise you'll have issues when the source image is in portrait orientation.
    [src_img drawInRect:CGRectMake(0.0, 0.0, src_img.size.width, src_img.size.height)];
    UIGraphicsPopContext();

    /*
     * At this point, we have the raw ARGB pixel data in the imgData buffer, so
     * we can perform whatever image processing here.
     */

    ...

    // After we've processed the raw data, turn it back into a UIImage instance.
    CGImageRef new_img = CGBitmapContextCreateImage(context);
    UIImage * convertedImage = [[[UIImage alloc] initWithCGImage:
                                 new_img] autorelease];

    CGImageRelease(new_img);
    CGContextRelease(context);
    CGColorSpaceRelease(d_colorSpace);
    free(imgData);
    [src_img release];
    return convertedImage;
}

Notes

  1. artgillespie posted this