我有一个UIImage(Cocoa Touch).从那以后,我很高兴得到一个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):(请注意,这会将图像数据复制到该缓冲区,因此您可以想要缓存它而不是每次需要获取像素值时执行此操作)
见下面的样本:
// 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];
Apple的技术问答QA1509展示了以下简单方法:
CFDataRef CopyImagePixels(CGImageRef inImage) { return CGDataProviderCopyData(CGImageGetDataProvider(inImage)); }
使用CFDataGetBytePtr
去实际字节(和各种CGImageGet*
方法来了解如何对其进行解释).
无法相信这里没有一个正确答案.无需分配指针,仍然需要对未经过相乘的值进行规范化.为了切入追逐,这里是Swift 4的正确版本.仅供UIImage
使用.cgImage
.
extension CGImage { func colors(at: [CGPoint]) -> [UIColor]? { let colorSpace = CGColorSpaceCreateDeviceRGB() let bytesPerPixel = 4 let bytesPerRow = bytesPerPixel * width let bitsPerComponent = 8 let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo), let ptr = context.data?.assumingMemoryBound(to: UInt8.self) else { return nil } context.draw(self, in: CGRect(x: 0, y: 0, width: width, height: height)) return at.map { p in let i = bytesPerRow * Int(p.y) + bytesPerPixel * Int(p.x) let a = CGFloat(ptr[i + 3]) / 255.0 let r = (CGFloat(ptr[i]) / a) / 255.0 let g = (CGFloat(ptr[i + 1]) / a) / 255.0 let b = (CGFloat(ptr[i + 2]) / a) / 255.0 return UIColor(red: r, green: g, blue: b, alpha: a) } } }
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);
这是一个SO 线程,其中@Matt通过移动图像将所需像素仅渲染到1x1上下文中,以使所需像素与上下文中的一个像素对齐.
根据UIImage上的Apple Reference,对象是不可变的,你无法访问后备字节.而如果你填充这是事实,你可以访问CGImage数据UIImage
与CGImage
(显式或隐式),它将返回NULL
如果UIImage
通过支持CIImage
,反之亦然.
图像对象不提供对其底层图像数据的直接访问.但是,您可以检索其他格式的图像数据,以便在您的应用中使用.具体来说,您可以使用cgImage和ciImage属性分别检索与Core Graphics和Core Image兼容的图像版本.您还可以使用UIImagePNGRepresentation(:)和UIImageJPEGRepresentation(:_ :)函数生成包含PNG或JPEG格式的图像数据的NSData对象.
如上所述,您的选择是
UIImagePNGRepresentation或JPEG
确定图像是否具有CGImage或CIImage支持数据并将其获取
如果您希望输出不是ARGB,PNG或JPEG数据并且数据尚未由CIImage支持,则这些都不是特别好的技巧.
在开发项目时,您可能更有意义地完全避免使用UIImage并选择其他内容.作为Obj-C图像包装器的UIImage通常由CGImage支持,我们认为它是理所当然的.CIImage往往是一种更好的包装器格式,因为您可以使用CIContext来获取所需的格式,而无需知道它是如何创建的.在您的情况下,获取位图将是一个调用的问题
- 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.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.. 迅速