2009-12-15 108 views
4

基於對a previous question的響應,我在UIImageView上創建了一個用於提取像素數據的類別。這在模擬器中正常工作,但在部署到設備時不起作用。我應該說不是總是 - 奇怪的是,它確實獲取正確的像素顏色,如果point.x == point.y;否則,它會爲該行另一側的像素提供像素數據,就像鏡像一樣。 (因此,點擊圖像右下角的像素會爲我提供左上角相應像素的像素數據,但是點擊左下角的像素會返回正確的像素顏色)。觸摸座標(CGPoint)是正確的。從UIImageView獲取像素數據 - 在模擬器上工作,不是設備

我在做什麼錯?

這裏是我的代碼:

@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; 
} 
+0

可以檢查self.image.imageOrientation的價值?有可能您使用的圖像位於UIImageOrientationLeftMirrored中,這可能是您看到的反射,但我不知道爲什麼只有在設備上纔會這樣。 –

+0

在模擬器和設備上都是UIImageOrientationUp 。我不確定「左鏡像」是對正在發生的事情的正確解釋,因爲反射(看起來)沿着對角線y = x發生,並且UIImageOrientationLeftMirrored是整個圖像「90度CCW」的簡單旋轉到SDK。 –

+0

更多信息:如果我交換x和y的計算方式,則行爲會相反 - 它在設備上運行,但不在模擬器上運行。 (雖然在設備上的確切位置似乎CCW幾度關閉,但它可能是我的手指與使用鼠標的不精確性) –

回答

5

我認爲R B G是錯誤的。您有:

UInt8 red = data[offset];  
UInt8 blue = data[offset+1]; 
UInt8 green = data[offset+2]; 

但是你不真的是 - [R 摹乙? :

UInt8 red = data[offset];  
UInt8 green = data[offset+1]; 
UInt8 blue = data[offset+2]; 

但即使與固定在那裏仍然是一個問題,因爲事實證明,蘋果byte swaps(大文章)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 

不知道這會解決您的問題,但你的行爲不端的代碼看起來接近到什麼礦看起來像之前我固定它。

最後一件事:我相信即使在CFRelease(bitmapData)被調用後,模擬器也會讓您訪問像素緩衝區data[]。在設備上,這是而不是在我的經驗。你的代碼不應該受到影響,但如果這有助於別人,我想我會提到它。

+0

花了我一些時間終於回到這個,但你的代碼是砰的一聲。混合了G和B,並且不知道字節順序的變化Xcode在幕後做了一個致命的組合。 –

0

你可以試試下面的另一種方法:

  • 創建CGBitmapContext
  • 繪製圖像爲背景
  • 呼叫CGBitmapContextGetData的上下文獲得底層數據
  • 計算出您的偏移量到ra W數據(根據你怎樣創建位圖上下文)
  • 提取物的價值

這種方法適用於我在模擬器和設備。

+0

我試圖避免,因爲涉及的開銷(此功能可能是稱爲多於一秒) –

+0

您可以緩存原始數據,然後將開銷減少爲數組查找,除非圖像不斷變化。 –

+0

的確如此。但是,我仍然想知道上面的代碼中的底層問題。 –

0

它看起來像在貼在原來的問題,而不是代碼:

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); 
相關問題