Как я могу получить чистую информацию альфа-канала из изображения PNG в iPhone OS? - PullRequest
4 голосов
/ 15 мая 2009

Я создал такой контекст (упрощенно):

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate (bitmapData,
  pixWide,
  pixHeigh,
  8, // bits per component
  bitmapBytesPerRow,
  colorSpace,
  kCGImageAlphaPremultipliedFirst);

Теперь, когда я пытаюсь извлечь данные для первого пикселя в моем PNG с помощью Alphatransparency, он имеет очень странные альфа-значения. У меня есть простой PNG, это квадрат. На каждом краю я обрезал 10х10 пикселей и сделал их полностью прозрачными. Альфа там не должна быть чем-то вроде 153.

В CGImage.h объявлен kCGImageAlphaOnly. Док говорит:

kCGImageAlphaOnly Нет цвета данные, только альфа-канал.

Хорошо, так что на самом деле это звучит хорошо, потому что мне нужны только альфа-данные, и ничего больше. Но это вызывает некоторые вопросы в моей голове. Если у меня есть полностью оборудованный PNG с кучей цветов + альфа: будет ли эта константа обеспечивать преобразование моего PNG в соответствии с этим цветовым пространством? Или мне нужно предоставить PNG, который соответствует указанному цветовому пространству?

Редактировать: я пытался использовать kCGImageAlphaOnly, но я получаю эту ошибку:

<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 0-component colorspace; kCGImageAlphaOnly; 55 bytes/row.

В чем здесь проблема? Я уточнил это раньше:

size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage);
bitmapBytesPerRow = (pixelsWide * 1); // not * 4, because I just want alpha
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);

Редактировать: я читал это минуту назад:

PNG, которые добавляются в XCode, оптимизировано pngcrush во время сборник. Это делает некоторые обмен байтами (от RGBA к BRGA) и предварительное умножение альфа.

Я предполагаю, что это предварительное умножение альфа создает проблемы.

Редактировать: альфа-канал остается неизменным после того, как pngcrunch сделал замену байтов в PNG. Так как мне не важны цвета, только альфа, то предварительное умножение не должно быть слишком большой проблемой, я думаю.

Мои PNG были 24-битными PNG, я добавил их в Xcode.

Ответы [ 2 ]

5 голосов
/ 15 мая 2009

Вы не можете сделать это:

bitmapBytesPerRow = (pixelsWide * 1); // not * 4, because I just want alpha

Функция, которую вы вызываете, всегда возвращает все данные изображения. Константа kCGImageAlphaOnly используется для сообщения ВАМ, что изображение содержит только альфа-канал, а информация о цвете отсутствует.

Вам нужно будет использовать pixelsWide * 4 для bytesPerRow. Также обратите внимание, что аргумент bitmapData для CGBitmapContextCreate () используется для предоставления пространства хранения явно, а не для его рисования за вас.

Возможно, что вы хотите сделать, это (непроверенный код, только что набранный из памяти):

CGImageRef image = GetMyImageFromWhereverItIs();
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate( NULL, CGImageGetWidth(image),
        CGImageGetHeight(image), CGImageGetBitsPerComponent(image),
        CGImageGetBytesPerRow(image), space,
        kCGBitmapByteOrderDefault | kCGImageAlphaLast );
CGColorSpaceRelease( space );

// now draw the image into the context
CGRect rect = CGRectMake( 0, 0, CGImageGetWidth(image), CGImageGetHeight(image) );
CGContextDrawImage( ctx, rect, image );
UInt32 * pixels = CGBitmapContextGetData( ctx );

// now we can iterate through the data & read the alpha values
int i, count = CGBitmapContextGetBytesPerRow(ctx) * CGBitmapContextGetHeight(ctx);
for ( i = 0; i < count; i++ )
{
    UInt8 alpha = pixels[i] & 0x000000ff;
    // do with the alpha what you will
}
4 голосов
/ 15 мая 2009

Вы уверены, что смотрите только на альфа-значения?

Если вы ожидаете, что все альфа-компоненты появятся первыми, то все красные компоненты и т. Д. Это планарная компоновка, и я не думаю, что Quartz поддерживает ее изначально - она ​​поддерживает только все компоненты вместе в каждом пикселе. (ARGBARGBARGBARGB…, а не AAAA…RRRR…GGGG…BBBB…). Так что, если вы просто идете прямо в данные, рассматривая каждый байт как альфа, это ваша проблема: вы смотрите на красный, зеленый и синий компоненты и рассматриваете их как альфа.

Что касается предварительного умножения, то оно не влияет на альфа-канал, оно влияет на цветовые каналы. Формула для растрового композитинга (наложение одного растрового изображения поверх другого):

dst.r = src.r * src.a + dst.r * (1.0 - src.a);
dst.g = src.g * src.a + dst.g * (1.0 - src.a);
dst.b = src.b * src.a + dst.b * (1.0 - src.a);

Предварительное умножение обрезает первое выражение умножения:

dst.r = src.r′ + dst.r * (1.0 - src.a);
dst.g = src.g′ + dst.g * (1.0 - src.a);
dst.b = src.b′ + dst.b * (1.0 - src.a);

Это работает, потому что исходные компоненты цвета уже умножены на альфа-компонент - отсюда и название «предварительно умножено». Теперь не нужно их умножать, потому что у него уже есть результаты.

Это оптимизация, и, по-видимому, важная для iPhone (все эти операции умножения складываются, когда вы выполняете миллион или два из них). Но это не влияет на расположение компонентов: чередование остается чередованным, независимо от того, предварительно ли умножены компоненты RGB.

...