检索UIImage的像素alpha值

时间:2009-06-25 09:18:09

标签: iphone uikit core-graphics quartz-graphics

我目前正在尝试获取UIImageView中像素的alpha值。我从[UIImageView image]中获取了CGImage,并从中创建了一个RGBA字节数组。 Alpha是预乘的。

CGImageRef image = uiImage.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
rawData = malloc(height * width * 4);
bytesPerPixel = 4;
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), image);
CGContextRelease(context);
然后,我使用UIImageView中的坐标计算给定alpha通道的数组索引。

int byteIndex = (bytesPerRow * uiViewPoint.y) + uiViewPoint.x * bytesPerPixel;
unsigned char alpha = rawData[byteIndex + 3];

但是我没有得到我期望的价值。对于图像的完全黑色透明区域,我得到alpha通道的非零值。我是否需要翻译UIKit和Core Graphics之间的坐标 - 即:y轴是倒置的吗?或者我误解了预乘的α值?

更新

@Nikolai Ruhe的建议是关键。我实际上并不需要在UIKit坐标和Core Graphics坐标之间进行转换。但是,在设置混合模式后,我的alpha值就是我的预期:

CGContextSetBlendMode(context, kCGBlendModeCopy);

4 个答案:

答案 0 :(得分:36)

如果你想要的只是单个点的alpha值,你只需要一个只有alpha的单点缓冲区。我相信这应该足够了:

// assume im is a UIImage, point is the CGPoint to test
CGImageRef cgim = im.CGImage;
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel, 
                                         1, 1, 8, 1, NULL,
                                         kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(-point.x, 
                                   -point.y, 
                                   CGImageGetWidth(cgim), 
                                   CGImageGetHeight(cgim)), 
               cgim);
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;

如果不必每次都重新创建UIImage,这非常有效。

2011年12月8日编辑:

评论者指出,在某些情况下,图像可能会被翻转。我一直在考虑这个问题,我有点遗憾,我没有直接使用UIImage编写代码,就像这样(我认为原因是当时我不了解{{1} }):

UIGraphicsPushContext

我认为这样可以解决翻转问题。

答案 1 :(得分:10)

是的,CGContexts的y轴向上,而在UIKit中,它指向下方。 See the docs

阅读代码后编辑:

您还希望在绘制图像之前将混合模式设置为替换,因为您需要图像的alpha值,而不是之前上下文缓冲区中的值:

CGContextSetBlendMode(context, kCGBlendModeCopy);

思考后编辑:

您可以通过构建尽可能小的CGBitmapContext(1x1像素?可能是8x8?试一试)并在绘制之前将上下文转换为所需位置来更有效地查找更多

CGContextTranslateCTM(context, xOffset, yOffset);

答案 2 :(得分:3)

  

我是否需要翻译UIKit和Core Graphics之间的坐标 - 即:是否反转y轴?

这是可能的。在CGImage中,像素数据采用英语阅读顺序:从左到右,从上到下。所以,阵列中的第一个像素是左上角;第二个像素是从顶行左侧开始的一个像素;等

假设你有这个权利,你还应该确保你正在查看像素中正确的组件。也许你期待RGBA但要求ARGB,反之亦然。或者,也许您的字节顺序错误(我不知道iPhone的字节顺序是什么)。

  

或者我误解了预乘alpha值?

听起来不像。

对于那些不知道的人:预乘意味着颜色成分被alpha预乘;无论颜色分量是否被预乘,alpha分量都是相同的。您可以通过将颜色分量除以alpha来反转此(非预数乘法)。

答案 3 :(得分:3)

我在研究如何使用图像数据的alpha值而不是矩形边界框进行精灵之间的碰撞检测时发现了这个问题/答案。上下文是一个iPhone应用程序...我试图做上面建议的1像素绘制,我仍然有问题让这个工作,但我发现一个更简单的方法来创建一个CGContextRef使用图像本身的数据,和辅助函数在这里:

CGContextRef context = CGBitmapContextCreate(
                 rawData, 
                 CGImageGetWidth(cgiRef), 
                 CGImageGetHeight(cgiRef), 
                 CGImageGetBitsPerComponent(cgiRef), 
                 CGImageGetBytesPerRow(cgiRef), 
                 CGImageGetColorSpace(cgiRef),
                 kCGImageAlphaPremultipliedLast     
    );

这绕过了上面示例中所有丑陋的硬编码。可以通过调用CGImageGetBitmapInfo()来检索最后一个值,但在我的情况下,它会从图像中返回一个导致ContextCreate函数出错的值。只有某些组合有效,如下所示:http://developer.apple.com/qa/qa2001/qa1037.html

希望这有用!