Get RGBA pixel values from UIImage.

来源:互联网 发布:软件开发资源管理 编辑:程序博客网 时间:2024/05/17 04:47

最近有从图片文件里提取像素值的需求,去搜索了一下,大致通过两种方式:(这里仅以PNG图片为例,其它图片格式没有测试过)

 

1.

- (void)GeneratePixelArray {
   
    UIImage *cImage = [UIImage imageNamed:@"testPNGPiexls-line.PNG"];
    int width = (int)cImage.size.width;
    int height = (int)cImage.size.height;
   
    unsigned char *cMap = (unsigned char *)malloc(width * height);
    memset(cMap, 0, width * height);
   
    CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(cImage.CGImage));
    const UInt32 *pixels = (const UInt32*)CFDataGetBytePtr(imageData);
   
    //0xff 0x00 is guard for this demo
    for (int j = 0; j < (width * height); j++)
    {
        printf("0x%x/n", (unsigned int)pixels[j]);
    }
    CFRelease(imageData);
}

第一种方法好像有点问题。

2.- (void *)GeneratePixelArray//: (UIImage *) image
{
   
    UIImage *cImage = [[UIImage alloc] imageNamed:@"testPNGPiexls-line.PNG"];
    //UIImage *cImage = [UIImage imageNamed:@"ball.png"];
    int pixelsWidth = (int)cImage.size.width;
    int pixelsHeight = (int)cImage.size.height;
    CGRect rect = {{0,0}, {pixelsWidth, pixelsHeight}};
   
    // Use RCG color space without Alpha, just RGB
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();   
    if(colorSpace == NULL)
    {
        NSLog(@"Error allocating color space! /n");
        return NULL;
    }
    unsigned int bitmapBytesPerRow = pixelsWidth*4;
    unsigned int bitmapByteCount = bitmapBytesPerRow*pixelsHeight;
    void * bitmapData = malloc(bitmapByteCount);
    if (bitmapData == NULL) {
        NSLog(@"Memory not allocated!/n");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }
    // create bitmap context ,8 bits per component
    CGContextRef context = CGBitmapContextCreate(bitmapData,
                                                 pixelsWidth,
                                                 pixelsHeight,
                                                 8,//bits per component
                                                 bitmapBytesPerRow,
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast);
   
    // Make sure release colorspace before returning
    CGColorSpaceRelease(colorSpace);
   
    if (context == NULL)
    {
        free(bitmapData);
        NSLog(@"Context not be created!");
        return NULL;
    }
   
   
    // Draw the image to the bitmap context
    CGContextDrawImage(context, rect, cImage.CGImage);
   
    // Now we can get a pointer to the image data associated with context
    unsigned char *bitsData;
    bitsData = CGBitmapContextGetData(context);
    if (!bitsData)
    {
        NSLog(@"Failed");


        return;

   }
    void *data = CGBitmapContextGetData(context);
    unsigned char* bitmapData2 = malloc(bitmapByteCount);
    if (bitmapData2 == NULL)
    {
        NSLog(@"Memory not be allocated!/n");
        return NULL;
    }
    unsigned char* rcdata = (unsigned char *)data;
    unsigned char* wcdata = bitmapData2;


    // remove ARGB's fourth value, it is Alpha
    for (int i = 0; i < bitmapByteCount / 4; ++i, rcdata += 4)
    {
        printf("%x/n", (unsigned int)*(unsigned int*)rcdata);
        *(wcdata + 0) = *(rcdata + 0);
        *(wcdata + 1) = *(rcdata + 1);
        *(wcdata + 2) = *(rcdata + 2);
        *(wcdata + 3) = *(rcdata + 3);
        if (*(wcdata+3)<20) {
            printf("alpha.../n");
        }
        //        if ( (*(wcdata + 0)==255) &&(*(wcdata + 1)==0) && (*(wcdata + 2)==0) ) {
        //            printf("red/n");
        //        }
        wcdata += 4;// skip alpha
    }
    CGContextRelease(context);
    return bitsData;
}

 

方法3:

347UIImage → pixelData → UIImage Rountrip

The questions is rather simple: How to manipulate single pixels of an UIImage?
The answer is rather long; but includes a joyful trip into Quartz 2D Graphic land…

// load image, convert to CGImageRef
UIImage *c = [UIImage imageNamed:@"c.png"];
CGImageRef cRef = CGImageRetain(c.CGImage);
 
// png alpha to mask
NSData* pixelData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(cRef));
// image raw data
 
//NSData* pixelDataRep = UIImagePNGRepresentation(c);
// compressed png data
 
//NSLog(@"pixelData %i", [pixelData length]);
//NSLog(@"pixelDataRep %i", [pixelDataRep length]);
//NSLog(@"pixelDataRep equal to pixelData: %@", [pixelData isEqualToData:pixelDataRep] ? @"YES" : @"NO");
 
//UIImage* newImage = [UIImage imageWithData:pixelData];
//[newImage drawInRect:CGRectMake(10, 340, 65, 65)];
 
 
//NSLog(@"pixelData %@", pixelData);
 
 
unsigned char* pixelBytes = (unsigned char *)[pixelData bytes];
// return pointer to data
 
// step through char data
for(int i = 0; i < [pixelData length]; i += 4) {
// change accordingly
pixelBytes[i] = pixelBytes[i];
pixelBytes[i+1] = pixelBytes[i+1];
pixelBytes[i+2] = pixelBytes[i+2];
pixelBytes[i+3] = 255;
}
//1ms in Simulator , 5ms on iPhone 3GS , 65x65 pixel
 
// copy bytes in new NSData
NSData* newPixelData = [NSData dataWithBytes:pixelBytes length:[pixelData length]];
//NSLog(@"newPixelData %@", newPixelData);
//NSLog(@"newPixelData: %@", newPixelData ? @"ok" : @"nil");
//NSLog(@"newPixelData equal to pixelData: %@", [pixelData isEqualToData:newPixelData] ? @"YES" : @"NO");
 
// cast NSData as CFDataRef
CFDataRef imgData = (CFDataRef)pixelData;
 
//NSLog(@"CFDataGetLength %i", CFDataGetLength(imgData) );
 
// Make a data provider from CFData
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData(imgData);
 
// testing... create data provider from file.... works
//NSString* imageFileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"c.png"];
//CGDataProviderRef imgDataProvider = CGDataProviderCreateWithFilename([imageFileName UTF8String]);
 
// does not work like that
// new image needs to get PNG properties
//CGImageRef throughCGImage = CGImageCreateWithPNGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
 
// get PNG properties from cRef
size_t width = CGImageGetWidth(cRef);
size_t height = CGImageGetHeight(cRef);
size_t bitsPerComponent = CGImageGetBitsPerComponent(cRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel(cRef);
size_t bytesPerRow = CGImageGetBytesPerRow(cRef);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(cRef);
CGBitmapInfo info = CGImageGetBitmapInfo(cRef);
CGFloat *decode = NULL;
BOOL shouldInteroplate = NO;
CGColorRenderingIntent intent = CGImageGetRenderingIntent(cRef);
 
// cRef PNG properties + imgDataProvider's data
CGImageRef throughCGImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, info, imgDataProvider, decode, shouldInteroplate, intent);
CGDataProviderRelease(imgDataProvider);
 
//NSLog(@"c %i, throughCGImage: %i", CGImageGetHeight(cRef), CGImageGetHeight(throughCGImage) );
CGImageRelease(throughCGImage);

From: http://www.trembl.org/codec/tag/NSData/

 
// make UIImage with CGImage
UIImage* newImage = [UIImage imageWithCGImage:throughCGImage];
//NSLog(@"newImage: %@", newImage);
 
// draw UIImage
[newImage drawInRect:CGRectMake(10, 340, 65, 65)];

示例所有图片如附件,

 

  printf("%x/n", (unsigned int)*(unsigned int*)rcdata); I saved output and method1 & method2 differs!

 

I'm a  beginner. 

why? I confused.  And metod2 should be right, so what's wrong with method 1.

 

Thanks!

原创粉丝点击