Method 1: Writable Pixel Information
I defined constants
#define RGBA 4 #define RGBA_8_BIT 8
In my UIImage subclass I declared instance variables:
size_t bytesPerRow; size_t byteCount; size_t pixelCount; CGContextRef context; CGColorSpaceRef colorSpace; UInt8 *pixelByteData; // A pointer to an array of RGBA bytes in memory RPVW_RGBAPixel *pixelData;
The pixel struct (with alpha in this version)
typedef struct RGBAPixel { byte red; byte green; byte blue; byte alpha; } RGBAPixel;
Bitmap function (returns pre-calculated RGBA; divide RGB by A to get unmodified RGB):
-(RGBAPixel*) bitmap { NSLog( @"Returning bitmap representation of UIImage." ); // 8 bits each of red, green, blue, and alpha. [self setBytesPerRow:self.size.width * RGBA]; [self setByteCount:bytesPerRow * self.size.height]; [self setPixelCount:self.size.width * self.size.height]; // Create RGB color space [self setColorSpace:CGColorSpaceCreateDeviceRGB()]; if (!colorSpace) { NSLog(@"Error allocating color space."); return nil; } [self setPixelData:malloc(byteCount)]; if (!pixelData) { NSLog(@"Error allocating bitmap memory. Releasing color space."); CGColorSpaceRelease(colorSpace); return nil; } // Create the bitmap context. // Pre-multiplied RGBA, 8-bits per component. // The source image format will be converted to the format specified here by CGBitmapContextCreate. [self setContext:CGBitmapContextCreate( (void*)pixelData, self.size.width, self.size.height, RGBA_8_BIT, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast )]; // Make sure we have our context if (!context) { free(pixelData); NSLog(@"Context not created!"); } // Draw the image to the bitmap context. // The memory allocated for the context for rendering will then contain the raw image pixelData in the specified color space. CGRect rect = { { 0 , 0 }, { self.size.width, self.size.height } }; CGContextDrawImage( context, rect, self.CGImage ); // Now we can get a pointer to the image pixelData associated with the bitmap context. pixelData = (RGBAPixel*) CGBitmapContextGetData(context); return pixelData; }
Read-Only Data (Previous information) - method 2:
Step 1. I declared a type for byte:
typedef unsigned char byte;
Step 2. I declared a struct to correspond to a pixel:
typedef struct RGBPixel { byte red; byte green; byte blue; } RGBPixel;
Step 3. I subclassed UIImageView and declared (with corresponding synthesized properties):
// Reference to Quartz CGImage for receiver (self) CFDataRef bitmapData; // Buffer holding raw pixel data copied from Quartz CGImage held in receiver (self) UInt8* pixelByteData; // A pointer to the first pixel element in an array RGBPixel* pixelData;
Step 4. Subclass code I put in a method named bitmap (to return the bitmap pixel data):
// Get the bitmap data from the receiver's CGImage (see UIImage docs) [self setBitmapData: CGDataProviderCopyData( CGImageGetDataProvider( [self CGImage] ) )]; // Create a buffer to store bitmap data (unitialized memory as long as the data) [self setPixelBitData: malloc( CFDataGetLength( bitmapData ) )]; // Copy image data into allocated buffer CFDataGetBytes( bitmapData, CFRangeMake( 0, CFDataGetLength( bitmapData ) ), pixelByteData ); // Cast a pointer to the first element of pixelByteData // Essentially what we're doing is making a second pointer that divides the byteData's units differently - instead of dividing each unit as 1 byte we will divide each unit as 3 bytes (1 pixel). pixelData = (RGBPixel*) pixelByteData; // Now you can access pixels by index: pixelData[ index ] NSLog( @"Pixel data one red (%i), green (%i), blue (%i).", pixelData[0].red, pixelData[0].green, pixelData[0].blue ); // You can determine the desired index by multiplying row * column. return pixelData;
Step 5. I made an accessor method:
- (RGBPixel*) pixelDataForRow: (int) row column: (int) column { // Return a pointer to the pixel data return &pixelData[ row * column ]; }
another answer:
You can't access the bitmap data of a UIImage directly.
You need to get the CGImage representation of the UIImage. Then get the CGImage's data provider, from that a CFData representation of the bitmap. Make sure to release the CFData when done.
CGImageRef cgImage = [image CGImage]; CGDataProviderRef provider = CGImageGetDataProvider(cgImage); CFDataRef bitmapData = CGDataProviderCopyData(provider);
You will probably want to look at the bitmap info of the CGImage to get pixel order, image dimensions, etc.
To get the pixel data as an array of bytes, I did this:
UInt8* data = CFDataGetBytePtr(bitmapData);
More info: CFDataRef documentation.
Also, remember to include CoreGraphics.framework