我正在编写一个iPhone应用程序,并且需要在photoshop中实现与"eyedropper"工具相当的东西,在那里你可以触摸图像上的一个点并捕获相关像素的RGB值,以确定和匹配它的颜色.获取UIImage是一个简单的部分,但有没有办法将UIImage数据转换为位图表示,我可以在其中提取给定像素的信息?一个工作代码示例将是最受欢迎的,并注意我不关心alpha值.
我今天早些时候发布了一个合并,并在此页面上说了一些小补充 - 可以在这篇文章的底部找到.我正在编辑帖子,但是,发布我的建议(至少对我的要求,包括修改像素数据)一个更好的方法,因为它提供可写数据(而我据了解,提供的方法)通过以前的帖子和这篇文章的底部提供了对数据的只读参考.
方法1:可写像素信息
我定义了常量
#define RGBA 4 #define RGBA_8_BIT 8
在我的UIImage子类中,我声明了实例变量:
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;
像素结构(此版本中带有alpha)
typedef struct RGBAPixel { byte red; byte green; byte blue; byte alpha; } RGBAPixel;
位图功能(返回预先计算的RGBA;将RGB除以A得到未修改的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; }
步骤1.我声明了一个字节类型:
typedef unsigned char byte;
第2步.我声明了一个与像素对应的结构:
typedef struct RGBPixel{ byte red; byte green; byte blue; } RGBPixel;
第3步.我将UIImageView子类化并声明(具有相应的合成属性):
// 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;
步骤4.子类代码我放入一个名为bitmap的方法(返回位图像素数据):
//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;
第5步.我制作了一个访问方法:
-(RGBPixel*)pixelDataForRow:(int)row column:(int)column{ //Return a pointer to the pixel data return &pixelData[row * column]; }
这是我对UIImage采样颜色的解决方案.
此方法将请求的像素渲染为1px大型RGBA缓冲区,并将生成的颜色值作为UIColor对象返回.这比我见过的大多数其他方法快得多,并且只使用很少的内存.
对于像颜色选择器这样的东西,它应该可以很好地工作,在任何给定的时间你通常只需要一个特定像素的值.
的UIImage + Picker.h
#import@interface UIImage (Picker) - (UIColor *)colorAtPosition:(CGPoint)position; @end
的UIImage + Picker.m
#import "UIImage+Picker.h" @implementation UIImage (Picker) - (UIColor *)colorAtPosition:(CGPoint)position { CGRect sourceRect = CGRectMake(position.x, position.y, 1.f, 1.f); CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, sourceRect); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *buffer = malloc(4); CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big; CGContextRef context = CGBitmapContextCreate(buffer, 1, 1, 8, 4, colorSpace, bitmapInfo); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0.f, 0.f, 1.f, 1.f), imageRef); CGImageRelease(imageRef); CGContextRelease(context); CGFloat r = buffer[0] / 255.f; CGFloat g = buffer[1] / 255.f; CGFloat b = buffer[2] / 255.f; CGFloat a = buffer[3] / 255.f; free(buffer); return [UIColor colorWithRed:r green:g blue:b alpha:a]; } @end
您无法直接访问UIImage的位图数据.
您需要获取UIImage的CGImage表示.然后从位图的CFData表示中获取CGImage的数据提供程序.确保在完成后释放CFData.
CGImageRef cgImage = [image CGImage]; CGDataProviderRef provider = CGImageGetDataProvider(cgImage); CFDataRef bitmapData = CGDataProviderCopyData(provider);
您可能希望查看CGImage的位图信息以获取像素顺序,图像尺寸等.
Lajos的回答对我有用.为了将像素数据作为字节数组,我这样做了:
UInt8* data = CFDataGetBytePtr(bitmapData);
更多信息:CFDataRef 文档.
此外,请记住包括 CoreGraphics.framework