Проблема восстановления UIImage из пиксельных байтовых данных RGBA - PullRequest
0 голосов
/ 24 августа 2011

Мне нужно создать 12 цветных изображений из одного изображения в оттенках серого (красный, оранжевый, желтый и т. Д.)

Исходное изображение на самом деле представляет собой PNG, RGBA:

enter image description here

Я использую найденную библиотеку (https://github.com/PaulSolt/UIImage-Conversion/), чтобы разбить UIImage на байтовый массив RGBA, который я затем обрабатываю попиксельно, и использую ту же библиотеку для воссоздания нового UIImage.

Это мой код:

- (UIImage*) cloneWithTint3: (CGColorRef) cgTint
{
    enum { R, G, B, A };

    // - - - 

    assert( CGColorGetNumberOfComponents( cgTint ) == 4 );

    const float* tint = CGColorGetComponents( cgTint );

    // - - - 

    int w = self.size.width;
    int h = self.size.height;

    int pixelCount = w * h;


    uint8_t* data = [UIImage convertUIImageToBitmapRGBA8: self];

    for( int i=0; i < pixelCount ; i++ )
    {
        int offset = i << 2; // same as 4 * i but faster

        float in_r = data[ offset + R ];
        float in_g = data[ offset + G ];
        float in_b = data[ offset + B ];
//        float in_a = data[ offset + A ];

        if( i == 0  )
            printf( "ALPHA  %d ", data[ offset + A ] ); // corner pixel has alpha 0

        float greyscale = 0.30 * in_r  +  0.59 * in_g +  0.11 * in_b;

        data[ offset + R ] = (uint8_t) ( greyscale * tint[ R ] );
        data[ offset + G ] = (uint8_t) ( greyscale * tint[ G ] );
        data[ offset + B ] = (uint8_t) ( greyscale * tint[ B ] );
    }

    UIImage* imageNew = [UIImage convertBitmapRGBA8ToUIImage: data
                                                   withWidth: w
                                                  withHeight: h ];

    free( data );

    // test corner pixel
    {
        uint8_t* test = [UIImage convertUIImageToBitmapRGBA8: self];
        for( int i=0; i < 1 ; i++ )
        {
            int offset = i << 2;

            // float in_r = test[ offset + R ];
            // float in_g = test[ offset + G ];
            // float in_b = test[ offset + B ];
            // float in_a = data[ offset + A ];

            printf( "ALPHA  %d ", test[ offset + A ] ); // corner pixel still has alpha 0
        }

        free( test );
    }

    return imageNew;
}

Проблема в том, что я не возвращаю альфа-канал - он устанавливает его непрозрачным везде.

Если я просто передаю исходное изображениеобратно в первую строку, он отображается правильно, поэтому проблема не в исходном изображении.

Если я проверяю альфа-компонент первого пикселя, я обнаруживаю, что он равен 0 (т.е. прозрачен) во всех точкахпроцесс, как и должно быть.Я даже добавил дополнительный тест, как вы можете видеть - как только у меня будет окончательный UIImage, я снова разбиваю его на растровое изображение RGBA и проверяю тот же элемент.Это все еще 0.

Так что, похоже, в методе convertUIImageToBitmapRGBA8 должна быть какая-то ошибка.похоже, что в результирующем UIImage должна быть какая-то настройка, заставляющая его думать, что он непрозрачен везде.

Но при просмотре исходного кода для этого метода (https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m - вся библиотекатолько этот файл с его заголовком) Я не вижу, где может быть проблема.

Это вывод рендеринга:

enter image description here

Как вы можете видеть, Cбыло отрисовано перед G перед F, следовательно, оно обрезано с обеих сторон прямоугольниками.

Ответы [ 2 ]

1 голос
/ 24 августа 2011

Проблема с альфа-прозрачностью была исправлена ​​в последней версии github. https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m

Исправление состояло в том, чтобы использовать следующий код с kCGImageAlphaPremultipliedLast, логически ORed в bitmapInfo в функции. BitmapInfo также использовался для увеличения CGContextRef, в дополнение к CGImageRef. Форматы должны быть одинаковыми для обоих параметров bitmapInfo.

+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer 
                                withWidth:(int) width
                               withHeight:(int) height;

Выдержка из кода:

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    CGImageRef iref = CGImageCreate(width, 
                                    height, 
                                    bitsPerComponent, 
                                    bitsPerPixel, 
                                    bytesPerRow, 
                                    colorSpaceRef, 
                                    bitmapInfo, 
                                    provider,   // data provider
                                    NULL,       // decode
                                    YES,            // should interpolate
                                    renderingIntent);

    uint32_t* pixels = (uint32_t*)malloc(bufferLength);

    if(pixels == NULL) {
        NSLog(@"Error: Memory not allocated for bitmap");
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpaceRef);
        CGImageRelease(iref);       
        return nil;
    }

    CGContextRef context = CGBitmapContextCreate(pixels, 
                                                 width, 
                                                 height, 
                                                 bitsPerComponent, 
                                                 bytesPerRow, 
                                                 colorSpaceRef,
                                                 bitmapInfo);
0 голосов
/ 03 декабря 2011

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

Код:

UIImage *c = [UIImage imageNamed:@"head_diamond_c.png"];
unsigned char * rawData = [ImageHelper convertUIImageToBitmapRGBA8: c];

UIImage *copy = [ImageHelper convertBitmapRGBA8ToUIImage: rawData withWidth:c.size.width withHeight:c.size.height];

free(rawData);

itemImageView setImage:copy];
...