最近有从图片文件里提取像素值的需求,去搜索了一下,大致通过两种方式:(这里仅以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:
347 UIImage → 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!