从 RGBA 像素字节数据重建 UIImage 时出现问题

发布于 2024-12-01 04:48:46 字数 2870 浏览 3 评论 0原文

我需要从单个灰度图像(红色、橙色、黄色等)创建 12 个彩色图像

源图像实际上是 PNG、RGBA:

enter此处的图像描述

我正在使用我找到的库(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 之前渲染,因此它的两侧都被矩形剪掉了。

I need to create 12 coloured images from a single greyscale image ( red orange yellow etc )

Source image is actually a PNG, RGBA:

enter image description here

I'm using a library I found ( https://github.com/PaulSolt/UIImage-Conversion/ ) to break the UIImage into a RGBA byte array which I then process pixel by pixel, and use the same library to reconstitute a new UIImage.

This is my code:

- (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;
}

Problem is that I'm not getting the alpha channel back -- it is setting it to opaque everywhere.

If I simply pass the source image back on the first line, it renders correctly, so the problem is not with the source image.

If I inspect the alpha component of the first pixel, I find it is 0 (ie transparent) at all points in the process, as it should be. I even put in an extra test as you can see -- once I have my final UIImage I again break it into a RGBA bitmap and inspect the same element. It is still 0.

So it seems there must be some bug in the convertUIImageToBitmapRGBA8 method. it looks like there must be some setting on the resultant UIImage which is making it think it is opaque everywhere.

But looking through the source code for this method ( https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m -- the whole library is just this file with its header ) I cannot see where the problem might be.

This is the rendering output:

enter image description here

As you can see, the C was rendered before the G before the F, hence it is clipped on both sides by the rectangles.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甚是思念 2024-12-08 04:48:46

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

The alpha transparency problem has been fixed on the latest github push. https://github.com/PaulSolt/UIImage-Conversion/blob/master/ImageHelper.m

The fix was to use the following code with kCGImageAlphaPremultipliedLast logically ORed in the bitmapInfo in the function. The bitmapInfo was also used increasing the CGContextRef, in addition to the CGImageRef. The formats should be the same for both bitmapInfo parameters.

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

Code excerpt:

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);
却一份温柔 2024-12-08 04:48:46

我正在尝试使用该库,但在复制图像而不是正确的 Alpha 通道中,我收到了混乱。 损坏的图像

代码:

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

I'm trying to use that library, but in copy image instead of correct alpha channel i receive a mess. broken image

Code:

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];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文