Problem reconstituting UIImage from RGBA pixel byte data

与世无争的帅哥 提交于 2019-12-20 07:08:33

问题


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

Source image is actually a PNG, RGBA:

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:

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


回答1:


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



回答2:


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


来源:https://stackoverflow.com/questions/7175786/problem-reconstituting-uiimage-from-rgba-pixel-byte-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!