2009-12-15 3 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 G B? :

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

Но даже при том, что фиксированный есть еще проблема, как выясняется, Apple, byte swaps (большая статья) в R и значения B, когда на устройстве, но не , когда на тренажере.

У меня была аналогичная проблема с симулятором/устройством с пиксельным буфером PNG, возвращаемым CFDataGetBytePtr.

Это решило вопрос для меня:

#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). На устройстве это не случай в моем опыте. Ваш код не должен быть затронут, но в случае, если это поможет кому-то другому, я подумал, что упомянул об этом.

+0

Пришло время, чтобы наконец вернуться к этому, но ваш код был взломан. Комбинация смешивания G и B и не зная об изменении порядка байтов Xcode делает за кулисами, была фатальной комбинацией. –

0

Вы можете попробовать следующий альтернативный подход:

  • создать CGBitmapContext
  • нарисовать изображение в контексте
  • CGBitmapContextGetData вызова от контекста к получить базовые данные
  • выработать свое смещение в ра ш данных (на основе того, как вы создали контекст точечного рисунка)
  • экстракт значение

Этот подход работает для меня на тренажере и устройства.

+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);