从 RGBA 像素字节数据重构 UIImage 的问题

Posted

技术标签:

【中文标题】从 RGBA 像素字节数据重构 UIImage 的问题【英文标题】:Problem reconstituting UIImage from RGBA pixel byte data 【发布时间】:2011-08-24 12:56:36 【问题描述】:

我需要从一张灰度图像(红橙黄等)创建 12 张彩色图像

源图片其实是PNG,RGBA:

我正在使用我找到的一个库 (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;

问题是我没有恢复 alpha 通道——它在任何地方都将其设置为不透明。

如果我只是在第一行将源图像传回,它会正确渲染,所以问题不在于源图像。

如果我检查第一个像素的 alpha 分量,我发现它在过程中的所有点都为 0(即透明),这是应该的。如您所见,我什至进行了额外的测试——一旦我有了最终的 UIImage,我再次将其分解为 RGBA 位图并检查相同的元素。还是 0。

看来 convertUIImageToBitmapRGBA8 方法中一定有一些错误。看起来在生成的 UIImage 上必须有一些设置,这使它认为它在任何地方都是不透明的。

但是通过查看这个方法的源代码(https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m——整个库就是这个带有头文件的文件)我看不出问题出在哪里。

这是渲染输出:

如您所见,C 在 G 之前在 F 之前渲染,因此它的两边都被矩形剪裁了。

【问题讨论】:

我在这里把这个问题简化为一个最小的测试用例:***.com/questions/7177685/… 【参考方案1】:

alpha 透明度问题已在最新的 github 推送中得到修复。 https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m

修复方法是在函数的 bitmapInfo 中使用以下代码与 kCGImageAlphaPremultipliedLast 进行逻辑或运算。除了 CGImageRef 之外,还使用 ​​bitmapInfo 来增加 CGContextRef。两个 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);

【讨论】:

【参考方案2】:

我正在尝试使用该库,但在复制图像而不是正确的 Alpha 通道时,我收到一团糟。 broken image

代码:

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];

【讨论】:

以上是关于从 RGBA 像素字节数据重构 UIImage 的问题的主要内容,如果未能解决你的问题,请参考以下文章

具有特定格式 RGB-565 的 UIImage

在 UIImage 中按顺序移动方块

如何将RGBA字节串转换为灰度图像?

从字节文件打开 PIL 图像

常用纹理和纹理压缩格式

从格式不受支持的 UIImage 中获取像素数据?