Тестовый шаблон CGImageCreate не работает (iOS)

Я пытаюсь создать тестовый шаблон UIImage для устройства iOS 5.1. Целевой UIImageView имеет размер 320x240, но я пытался создать тестовый шаблон UIImage 160x120 (будущие изображения нетестовых шаблонов будут такого размера). Я хотел, чтобы верхняя половина поля была синей, а нижняя красной, но я получаю то, что выглядит как неинициализированная память, искажающая нижнюю часть изображения. Код выглядит следующим образом:

int width = 160;
int height = 120;
unsigned int testData[width * height];
for(int k = 0; k < (width * height) / 2; k++)
    testData[k] = 0xFF0000FF;   // BGRA (Blue)
for(int k = (width * height) / 2; k < width * height; k++)
    testData[k] = 0x0000FFFF;   // BGRA (Red)

int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, &testData, (width * height * 4), NULL);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();      
CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipFirst;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, 
                                    colorSpaceRef, bitmapInfo, provider, NULL, NO,renderingIntent);

UIImage *myTestImage = [UIImage imageWithCGImage:imageRef];

Это должно выглядеть как другой пример переполнения стека. Во всяком случае, я обнаружил, что по мере уменьшения размера тестового шаблона увеличивается «поврежденная» часть изображения. Что также странно, так это то, что я вижу красные линии в «поврежденной» части, поэтому не похоже, что я просто путаю размеры компонентов. Что мне не хватает? Чувствуется что-то в провайдере, но я его не вижу.

Спасибо!

Добавлены скриншоты. Вот как это выглядит с набором kCGImageAlphaNoneSkipFirst:

AlphaSkipFirst

А вот как это выглядит с kCGImageAlphaFirst:

введите здесь описание изображения


person GrandAdmiral    schedule 25.03.2012    source источник


Ответы (2)


Ваши пиксельные данные находятся в автоматической переменной, поэтому они хранятся в стеке:

unsigned int testData[width * height];

Вы должны возвращаться из функции, в которой объявлены эти данные. Это заставляет фрейм стека функции извлекаться и повторно использоваться другими функциями, что приводит к перезаписи данных.

Однако ваше изображение по-прежнему ссылается на эти пиксельные данные по тому же адресу в стеке. (CGDataProviderCreateWithData не копирует данные, а просто ссылается на них.)

Чтобы исправить: используйте malloc или CFMutableData или NSMutableData, чтобы выделить место для ваших пиксельных данных в куче.

person Kurt Revis    schedule 26.03.2012
comment
Ах, держу пари, что это оно. Я должен был понять, что происходит, но я был слишком сосредоточен на правильной работе функций CGx. Я постараюсь проверить ответ сегодня вечером (Windows и C/C# на работе, но Mac и iOS дома). Спасибо! - person GrandAdmiral; 26.03.2012

Ваше изображение включает альфу, которую вы затем указываете системе игнорировать, пропуская наиболее значимые биты (т. Е. Часть «B» вашего изображения). Вместо этого попробуйте установить kCGImageAlphaPremultipliedLast.

ИЗМЕНИТЬ:

Теперь, когда я вспомнил порядок байтов, я понимаю, что программа, вероятно, считывает ваши значения в обратном порядке, поэтому на самом деле вам может понадобиться kCGImageAlphaPremultipliedFirst

person borrrden    schedule 25.03.2012
comment
Я попробовал ваше предложение, но я все еще вижу искажение внизу изображения. С kCGImageAlphaPremultipliedFirst больше плохих пикселей имеют белый цвет, а с kCGImageAlphaNoneSkipFirst больше плохих пикселей имеют черный цвет, если это помогает. Я также пробовал kCGImageAlphaFirst, но там та же история. Мое намерение - 32-битные пиксели (целые) с 8 битами на цвет и 8-битным альфа-каналом, который можно или нельзя использовать. - person GrandAdmiral; 26.03.2012
comment
не могли бы вы показать фото результата? Я уверен, что вы хотите, чтобы предварительное умножение было последним, поэтому, если это не вызывает проблем сейчас, это будет позже, поэтому лучше оставить его таким. Ваше изображение BGRA, и вам может понадобиться сделать его RGBA, чтобы получить правильные цвета позже, но обе версии имеют свою альфа ПОСЛЕДНЮЮ, а не первую. - person borrrden; 26.03.2012
comment
PS у вас либо есть альфа, либо нет, вы не можете смешивать и сочетать. - person borrrden; 26.03.2012
comment
Я поиграл с First и Last, и, похоже, это изменило порядок байтов ввода. Я возьму альфа-смешивание, если смогу его получить, настоящий ключ — это возможность указать, что 24-битная информация о цвете находится в 32-битном пространстве памяти. - person GrandAdmiral; 26.03.2012
comment
Команда S сохранит снимок из симулятора на рабочий стол. Вы упоминаете endian, но эти константы не имеют к этому никакого отношения. Однако вы заставили меня кое-что понять, поскольку вы напрямую создаете данные, возможно, вы создаете их не с правильным порядком байтов. Попробуйте добавить kCGBitmapByteOrder32Little или kCGBitmapByteOrder32Big к информации о растровом изображении (побитовое ИЛИ с предварительным умножением альфа-канала последним). - person borrrden; 26.03.2012
comment
Скриншоты получил сейчас. Спасибо за подсказку о константах Endian, мне нужно будет установить это в будущем, когда у меня будут данные нетестового шаблона в любом формате. Все это говорит о том, что это не похоже на проблему Endian. Я мог бы установить тестовый шаблон на 0x00FF0000 и 0x0000FF00, и я должен просто увидеть красное/зеленое разделение в некотором порядке. К сожалению, коррупция осталась. - person GrandAdmiral; 26.03.2012
comment
Ну, я слышал слухи об этом раньше, попробуйте просто произвольно увеличить размер вашего буфера testData до чего-то вроде [ширина * высота + 5]. - person borrrden; 26.03.2012
comment
Да, я видел то же самое в своей отладке. Если я сделаю буфер тестового шаблона больше, чем нужно, растровое изображение будет выглядеть нормально. К сожалению, это, вероятно, не сработает, когда у меня будут фактические данные. - person GrandAdmiral; 26.03.2012