How to get the RGB values for a pixel on an image on the iphone

时间:2023-02-01 22:18:12

http://*.com/questions/144250/how-to-get-the-rgb-values-for-a-pixel-on-an-image-on-the-iphone

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