如何从UIImage(Cocoa Touch)或CGImage(Core Graphics)获取像素数据?

我有一个UIImage(cocoa触摸)。 从那里,我很高兴得到一个CGImage或任何你想要的东西。 我想写这个函数:

- (int)getRGBAFromImage:(UIImage *)image atX:(int)xx andY:(int)yy { // [...] // What do I want to read about to help // me fill in this bit, here? // [...] int result = (red << 24) | (green << 16) | (blue << 8) | alpha; return result; } 

谢谢!

仅供参考,我将Keremk的回答与我的原始大纲相结合,清理了错别字,将其归纳为返回一系列颜色,并将整个事物编译。 结果如下:

 + (NSArray*)getRGBAsFromImage:(UIImage*)image atX:(int)x andY:(int)y count:(int)count { NSMutableArray *result = [NSMutableArray arrayWithCapacity:count]; // First get the image into your data buffer CGImageRef imageRef = [image CGImage]; NSUInteger width = CGImageGetWidth(imageRef); NSUInteger height = CGImageGetHeight(imageRef); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char)); NSUInteger bytesPerPixel = 4; NSUInteger bytesPerRow = bytesPerPixel * width; NSUInteger bitsPerComponent = 8; CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); CGContextRelease(context); // Now your rawData contains the image data in the RGBA8888 pixel format. NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel; for (int i = 0 ; i < count ; ++i) { CGFloat alpha = ((CGFloat) rawData[byteIndex + 3] ) / 255.0f; CGFloat red = ((CGFloat) rawData[byteIndex] ) / alpha; CGFloat green = ((CGFloat) rawData[byteIndex + 1] ) / alpha; CGFloat blue = ((CGFloat) rawData[byteIndex + 2] ) / alpha; byteIndex += bytesPerPixel; UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; [result addObject:acolor]; } free(rawData); return result; } 

其中一种方法是将图像绘制到位图上下文中,该位图上下文由给定的色彩空间(在本例中为RGB)支持:(请注意,这会将图像数据复制到该缓冲区,所以您可以想要caching它,而不是每次需要获取像素值时都要执行此操作)

看下面的例子:

 // First get the image into your data buffer CGImageRef image = [myUIImage CGImage]; NSUInteger width = CGImageGetWidth(image); NSUInteger height = CGImageGetHeight(image); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = malloc(height * width * 4); NSUInteger bytesPerPixel = 4; NSUInteger bytesPerRow = bytesPerPixel * width; NSUInteger bitsPerComponent = 8; CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0, 0, width, height)); CGContextRelease(context); // Now your rawData contains the image data in the RGBA8888 pixel format. int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel; red = rawData[byteIndex]; green = rawData[byteIndex + 1]; blue = rawData[byteIndex + 2]; alpha = rawData[byteIndex + 3]; 

苹果的技术问答QA1509显示了以下简单的方法:

 CFDataRef CopyImagePixels(CGImageRef inImage) { return CGDataProviderCopyData(CGImageGetDataProvider(inImage)); } 

使用CFDataGetBytePtr来获取实际的字节(和各种CGImageGet*方法来理解如何解释它们)。

这是一个SO 线程 ,其中@Matt通过移动图像将所需像素渲染到1×1上下文中,以便所需像素与上下文中的一个像素alignment。

 NSString * path = [[NSBundle mainBundle] pathForResource:@"filename" ofType:@"jpg"]; UIImage * img = [[UIImage alloc]initWithContentsOfFile:path]; CGImageRef image = [img CGImage]; CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image)); const unsigned char * buffer = CFDataGetBytePtr(data); 

UIImage是一个包装的字节是CGImage或CIImage

根据UIImage上的Apple参考资料,该对象是不可变的,您无法访问后备字节。 如果用CGImage (显式或隐式)填充UIImage ,则可以访问CGImage数据,但如果UIImageCIImage支持,则它将返回NULL ,反之亦然。

图像对象不能直接访问其底层图像数据。 不过,您可以检索其他格式的图片数据,以便在您的应用中使用。 具体而言,可以使用cgImage和ciImage属性分别检索与Core Graphics和Core Image兼容的图像版本。 您还可以使用UIImagePNGRepresentation( :)和UIImageJPEGRepresentation( :_ :)函数生成包含PNG或JPEG格式的图像数据的NSData对象。

解决这个问题的常用技巧

如上所述你的select是

  • UIImagePNGRepresentation或JPEG
  • 确定图像是否有CGImage或CIImage的支持数据,并在那里

如果您希望不是ARGB,PNG或JPEG数据的输出,并且数据尚未由CIImage支持,则这两种方法都不是特别好用的技巧。

我的build议,尝试CIImage

在开发你的项目的时候,你可能更愿意避免使用UIImage,并select其他的东西。 UIImage作为一个Obj-C图像包装器,经常被CGImage支持,我们认为这是理所当然的。 CIImage往往是一个更好的包装格式,因为你可以使用CIContext来获得你想要的格式,而不需要知道它是如何创build的。 在你的情况下,获取位图将是一个调用的问题

– render:toBitmap:rowBytes:bounds:format:colorSpace:

作为一个额外的奖励,你可以通过链接滤镜到图像上来开始对图像进行很好的操作。 这解决了很多图像颠倒或需要旋转/缩放等问题。

基于Olie和Algal的回答,下面是Swift 3的一个更新的答案

 public func getRGBAs(fromImage image: UIImage, x: Int, y: Int, count: Int) -> [UIColor] { var result = [UIColor]() // First get the image into your data buffer guard let cgImage = image.cgImage else { print("CGContext creation failed") return [] } let width = cgImage.width let height = cgImage.height let colorSpace = CGColorSpaceCreateDeviceRGB() let rawdata = calloc(height*width*4, MemoryLayout<CUnsignedChar>.size) let bytesPerPixel = 4 let bytesPerRow = bytesPerPixel * width let bitsPerComponent = 8 let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue guard let context = CGContext(data: rawdata, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { print("CGContext creation failed") return result } context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height)) // Now your rawData contains the image data in the RGBA8888 pixel format. var byteIndex = bytesPerRow * y + bytesPerPixel * x for _ in 0..<count { let alpha = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 3, as: UInt8.self)) / 255.0 let red = CGFloat(rawdata!.load(fromByteOffset: byteIndex, as: UInt8.self)) / alpha let green = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 1, as: UInt8.self)) / alpha let blue = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 2, as: UInt8.self)) / alpha byteIndex += bytesPerPixel let aColor = UIColor(red: red, green: green, blue: blue, alpha: alpha) result.append(aColor) } free(rawdata) return result } 

迅速

根据不同的答案,但主要是这个 ,这对我所需要的工作:

 UIImage *image1 = ...; // The image from where you want a pixel data int pixelX = ...; // The X coordinate of the pixel you want to retrieve int pixelY = ...; // The Y coordinate of the pixel you want to retrieve uint32_t pixel1; // Where the pixel data is to be stored CGContextRef context1 = CGBitmapContextCreate(&pixel1, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst); CGContextDrawImage(context1, CGRectMake(-pixelX, -pixelY, CGImageGetWidth(image1.CGImage), CGImageGetHeight(image1.CGImage)), image1.CGImage); CGContextRelease(context1); 

作为这一行的结果,您将有一个AARRGGBB格式的像素,在4个字节的无符号整数像素1中alpha始终设置为FF。