Iphone 从UIImageView获取像素数据——在模拟器上工作,而不是在设备上

Iphone 从UIImageView获取像素数据——在模拟器上工作,而不是在设备上,iphone,uiimageview,pixel,Iphone,Uiimageview,Pixel,根据对的响应,我在UIImageView上创建了一个类别,用于提取像素数据。这在模拟器中可以正常工作,但在部署到设备时则不行。我应该说,不总是这样——奇怪的是,如果point.x==point.y,它确实能获得正确的像素颜色;否则,它会为该行另一侧的像素提供像素数据,就像镜像一样。(因此,点击图像右下角的一个像素可以得到左上角对应像素的像素数据,但点击左下角的一个像素可以返回正确的像素颜色)。触摸坐标(CGPoint)正确 我做错了什么 这是我的密码: @interface UIImageVie

根据对的响应,我在UIImageView上创建了一个类别,用于提取像素数据。这在模拟器中可以正常工作,但在部署到设备时则不行。我应该说,不总是这样——奇怪的是,如果point.x==point.y,它确实能获得正确的像素颜色;否则,它会为该行另一侧的像素提供像素数据,就像镜像一样。(因此,点击图像右下角的一个像素可以得到左上角对应像素的像素数据,但点击左下角的一个像素可以返回正确的像素颜色)。触摸坐标(CGPoint)正确

我做错了什么

这是我的密码:

@interface UIImageView (PixelColor)
- (UIColor*)getRGBPixelColorAtPoint:(CGPoint)point;
@end

@implementation UIImageView (PixelColor)

- (UIColor*)getRGBPixelColorAtPoint:(CGPoint)point
{
    UIColor* color = nil;

    CGImageRef cgImage = [self.image CGImage];
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    NSUInteger x = (NSUInteger)floor(point.x);
    NSUInteger y = height - (NSUInteger)floor(point.y);

    if ((x < width) && (y < height))
    {
        CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
        CFDataRef bitmapData = CGDataProviderCopyData(provider);
        const UInt8* data = CFDataGetBytePtr(bitmapData);
        size_t offset = ((width * y) + x) * 4;
        UInt8 red = data[offset];
        UInt8 blue = data[offset+1];
        UInt8 green = data[offset+2];
        UInt8 alpha = data[offset+3];
        CFRelease(bitmapData);
        color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
    }

    return color;
}
界面UIImageView(PixelColor) -(UIColor*)getRGBPixelColorAtPoint:(CGPoint)点; @结束 @实现UIImageView(像素颜色) -(UIColor*)getRGBPixelColorAtPoint:(CGPoint)点 { UIColor*color=nil; CGImageRef cgImage=[self.image cgImage]; 大小\u t宽度=CGImageGetWidth(cgImage); 尺寸高度=CGImageGetHeight(cgImage); NSUInteger x=(NSUInteger)楼层(点x); NSU整数y=高度-(NSU整数)楼层(点y); 如果((x<宽度)和(y<高度)) { CGDataProviderRef provider=CGImageGetDataProvider(cgImage); CFDataRef bitmapData=CGDataProviderCopyData(提供程序); const UInt8*data=CFDataGetBytePtr(位图数据); 尺寸t偏移=((宽度*y)+x)*4; UInt8红色=数据[偏移]; UInt8蓝色=数据[偏移量+1]; UInt8绿色=数据[偏移量+2]; UInt8 alpha=数据[偏移量+3]; CFRelease(位图数据); 颜色=[UIColor color WITH red:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f]; } 返回颜色; }
您可以尝试以下替代方法:

  • 创建CGBitmapContext
  • 将图像绘制到上下文中
  • 在上下文上调用CGBitmapContextGetData以获取基础数据
  • 计算原始数据中的偏移量(基于创建位图上下文的方式)
  • 提取值

这种方法适用于我在模拟器和设备上使用。

我认为Rbg是错误的。你有:

UInt8 red =   data[offset];     
UInt8 blue =  data[offset+1];
UInt8 green = data[offset+2];
但你不是真的指Rgb

UInt8 red =   data[offset];     
UInt8 green = data[offset+1];
UInt8 blue =  data[offset+2];
但即使修复了这个问题,仍然存在一个问题,因为苹果(伟大的文章)在设备上显示R和B值,但在模拟器上显示的是而不是

我遇到了类似的模拟器/设备问题,CFDataGetBytePtr返回了PNG的像素缓冲区

这为我解决了问题:

#if TARGET_IPHONE_SIMULATOR
        UInt8 red =   data[offset];
        UInt8 green = data[offset + 1];
        UInt8 blue =  data[offset + 2];
#else
        //on device
        UInt8 blue =  data[offset];       //notice red and blue are swapped
        UInt8 green = data[offset + 1];
        UInt8 red =   data[offset + 2];
#endif
不确定这是否能解决您的问题,但您的行为不端的代码看起来与我修复之前的代码非常接近


最后一件事:我相信模拟器将允许您访问像素缓冲区
data[]
,即使在调用
CFRelease(bitmapData)
之后。根据我的经验,在设备上这是而不是。您的代码不应该受到影响,但如果这对其他人有帮助,我想我会提到它。

在原始问题中发布的代码中,它看起来是这样的,而不是:

NSUInteger x = (NSUInteger)floor(point.x);
NSUInteger y = height - (NSUInteger)floor(point.y);
应该是:

NSUInteger x = (NSUInteger)floor(point.x);
NSUInteger y = (NSUInteger)floor(point.y);

你能检查self.image.imageOrientation的值吗?您使用的图像可能是UIImageOrientationReftMirror中的图像,这可能是您看到的反射,尽管我不知道为什么只有在设备上才会是这样……模拟器和设备上都是UIImageOrientationUp。我不确定“左镜像”是对正在发生的事情的正确解释,因为反射(似乎)是沿着对角线y=x发生的,而UIImageOrientationLeftMirrored是根据SDK对整个图像“逆时针90度”的简单旋转。更多信息:如果我交换x和y的计算方式,行为是相反的——它在设备上工作,但在模拟器上不工作。(虽然设备上的精确定位似乎与逆时针方向相差几度,但可能是我的手指与使用鼠标相比不精确)我正试图避免这种情况,因为涉及的开销(此函数可能每秒调用一次以上)您可以缓存原始数据,然后将开销减少到数组查找,除非图像在不断变化,这是真的。然而,我仍然想知道我上面的代码中的潜在问题是什么。我花了一些时间才最终回到这个问题上来,但是你的代码非常棒。把G和B混在一起,不知道Xcode在幕后的字节顺序变化,这是一个致命的组合。