Menu

#103 Fixed PNG plugin handling of 24-bit RGB + tRNS chunk images

None
closed
None
5
2015-03-15
2014-12-23
No

Hi Hervé,

This is another small fix to PluginPNG.cpp, to fix handling of 24-bit RGB images with a tRNS chunk. PNG supports images of color type 2 (RGB), with a single color specified as transparent in the tRNS chunk. This format is sometimes used by web developers, to save space over a 32bpp RGBA image if an image's transparency consists of only 0 and 255 values.

The following link provides two examples of PNG images like this, specifically test images T7 and T8:

http://entropymine.com/jason/testbed/pngtrans/

At present, FreeImage ignores the tRNS chunk on these images, and returns a 24bpp image only. This is incorrect.

Here is a 5-line patch that uses libPNG to expand such images to 32bpp. The changes should be applied to lines 365 to 370 of PluginPNG.cpp. (Those line numbers include my previous patch, to fix handling of 16-bit grayscale + 16-bit alpha; for convenience, I have included that code below, as it sits at the same location in the file.)

        // (This is line 339 in the original PluginPNG.cpp file)
        // get image data type (assume standard image type)

        FREE_IMAGE_TYPE image_type = FIT_BITMAP;
        if (bit_depth == 16) {
            if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
                image_type = FIT_UINT16;
            } 
            else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
                image_type = FIT_RGB16;
            } 
            else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
                image_type = FIT_RGBA16;
            }

            //*************************
            //PREVIOUSLY SUBMITTED PATCH TO SUPPORT 16-BIT GRAYSCALE + 16-BIT ALPHA PNGS
            else if ((pixel_depth == 32) && (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
                // tell libpng to expand 16 bit grayscale + 16 bit alpha to 64 bit RGBA
                png_set_gray_to_rgb(png_ptr);
                image_type = FIT_RGBA16;
                pixel_depth = 64;
            }
            //*************************

            else {
                // tell libpng to strip 16 bit/color files down to 8 bits/color
                png_set_strip_16(png_ptr);
                bit_depth = 8;
            }
        }

        //*************************
        //NEW PATCH TO SUPPORT 24BPP PNGS WITH A TRANSPARENT COLOR SPECIFIED BY THE tRNS CHUNK
        if ((color_type == PNG_COLOR_TYPE_RGB) && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_set_tRNS_to_alpha(png_ptr);
            pixel_depth = 32;
            color_type = PNG_COLOR_TYPE_RGB_ALPHA;
        }
        //*************************

In case it is easier, I have also attached the updated PluginPNG.cpp file to this patch. The updated lines are identical to the patch above.

Happy holidays!

1 Attachments

Discussion

  • Tanner Helland

    Tanner Helland - 2014-12-29

    Hi Hervé. The above patch should be expanded slightly, to cover the case of 48-bit RGB images as well. Here's the change:

            //*************************
            //UPDATED PATCH TO SUPPORT BOTH 24 AND 48 BPP PNGS WITH A TRANSPARENT COLOR SPECIFIED BY THE tRNS CHUNK
            if ((color_type == PNG_COLOR_TYPE_RGB) && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                png_set_tRNS_to_alpha(png_ptr);
    
                //If the image is 24bpp RGB, mark it as 32; if it is 48, mark it as 64
                if (pixel_depth == 24) {
                    pixel_depth = 32;
                } 
                else {
                    pixel_depth = 64;
                    image_type = FIT_RGBA16;
                }
                color_type = PNG_COLOR_TYPE_RGB_ALPHA;
            }
            //*************************
    
     
  • Hervé Drolon

    Hervé Drolon - 2015-02-19
    • status: open --> pending
    • assigned_to: Hervé Drolon
    • Group: -->
     
  • Hervé Drolon

    Hervé Drolon - 2015-02-19

    Hi Tanner,

    Thanks for the patch, it is now available in the CVS.

    Hervé

     
  • Hervé Drolon

    Hervé Drolon - 2015-03-08

    Hi Tanner,

    I've added your patch discussed at
    https://sourceforge.net/p/freeimage/discussion/36111/thread/533906f7/
    with also the handling of 1-,4-bit palettized images.

    I've also refactored the PNG plugin so that it should be more easy to understand the conversion commands.

    Hervé

     
  • Tanner Helland

    Tanner Helland - 2015-03-09

    Hi Hervé,

    Thanks very much for your fine work!

    The refactored code looks great. You are right; the use of ConfigureDecoder() makes it much easier to understand how FreeImage converts PNG's various transparency implementations into standard FreeImage formats.

    I really appreciate your help in this matter, and thanks again for the 3.17.0 release.

    Tanner

     
  • Tanner Helland

    Tanner Helland - 2015-03-09

    Hi Hervé,

    I am copying comments here from the 3.17.0 release thread in the discussion forum.

    Unfortunately, the new refactoring broke 16-bit grayscale + tRNS support. 16-bit grayscale images can also contain a tRNS chunk, so under the PNG_COLOR_TYPE_GRAY bit_depth switch, case 16, there needs to be an added check as follows:

        case 16:
            image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN;
    
            // 16-bit grayscale images can contain a transparent value (shade)
            // if found, expand the transparent value to a full alpha channel
            if (bIsTransparent && (image_type != FIT_UNKNOWN)) {
    
                // expand tRNS to a full alpha channel
                png_set_tRNS_to_alpha(png_ptr);
    
                // expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA
                png_set_gray_to_rgb(png_ptr);
    
                image_type = FIT_RGBA16;
    
            }
            break;
    

    Thanks!

     
  • Hervé Drolon

    Hervé Drolon - 2015-03-10

    Hi Tanner,

    The new patch is now in the CVS.
    However, as far as I can see, this is not a regression but a new feature. 16-bit grayscale + tRNS chunk images were not converted with the previous versions of the code.

    Hervé

     
  • Tanner Helland

    Tanner Helland - 2015-03-10

    Hi Hervé,

    You are correct, and I apologize for the confusion. I think I have been staring at too much PNG code lately... :)

    With this commit, I think FreeImage can now load the entire PNG transparency test library at this link correctly. I will do a few additional checks to be sure, but I am really excited for FreeImage to be a best-in-class PNG handler.

    Thank you for tolerating so many PNG patches this release,

    Tanner

     
  • Hervé Drolon

    Hervé Drolon - 2015-03-15
    • status: pending --> closed
     
  • Hervé Drolon

    Hervé Drolon - 2015-03-15

    fixed in release 3.17.0

     

Anonymous
Anonymous

Add attachments
Cancel