From d6201fc32d8f035f165bf4798359fb1928a1808a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 19 Feb 2021 16:51:46 +0000 Subject: [PATCH] note PNG background colour in metadata see https://github.com/libvips/libvips/issues/2111 --- ChangeLog | 1 + libvips/foreign/spngload.c | 45 +++++++++++++++++++++++++++++++++- libvips/foreign/vipspng.c | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5e6ed5d1..2609a35c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ - fix ref leaks in mosaicing package - run libvips leak test in CI - add vips_fitsload_source()m vips_niftiload_source() +- png load notes background colour as metadata [781545872] 22/12/20 start 8.10.6 - don't seek on bad file descriptors [kleisauke] diff --git a/libvips/foreign/spngload.c b/libvips/foreign/spngload.c index 83340f6b..0357498b 100644 --- a/libvips/foreign/spngload.c +++ b/libvips/foreign/spngload.c @@ -2,6 +2,8 @@ * * 1/5/20 * - from pngload.c + * 19/2/21 781545872 + * - read out background, if we can */ /* @@ -199,6 +201,7 @@ vips_foreign_load_png_set_header( VipsForeignLoadPng *png, VipsImage *image ) struct spng_iccp iccp; struct spng_exif exif; struct spng_phys phys; + struct spng_bkgd bkgd; guint32 n_text; /* Get resolution. Default to 72 pixels per inch. @@ -267,6 +270,47 @@ vips_foreign_load_png_set_header( VipsForeignLoadPng *png, VipsImage *image ) */ if( png->ihdr.interlace_method != SPNG_INTERLACE_NONE ) vips_image_set_int( image, "interlaced", 1 ); + + if( !spng_get_bkgd( png->ctx, &bkgd ) ) { + const int scale = image->BandFmt == + VIPS_FORMAT_UCHAR ? 1 : 256; + + double array[3]; + int n; + + switch( png->ihdr.color_type ) { + case SPNG_COLOR_TYPE_GRAYSCALE: + case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: + array[0] = bkgd.gray / scale; + n = 1; + break; + + case SPNG_COLOR_TYPE_TRUECOLOR: + case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: + array[0] = bkgd.red / scale; + array[1] = bkgd.green / scale; + array[2] = bkgd.blue / scale; + n = 3; + break; + + case SPNG_COLOR_TYPE_INDEXED: + default: + /* Not sure what to do here. I suppose we should read + * the palette. + */ + n = 0; + break; + } + + if( n > 0 ) { + GValue value = { 0 }; + + g_value_init( &value, VIPS_TYPE_ARRAY_DOUBLE ); + vips_value_set_array_double( &value, array, n ); + vips_image_set( image, "background", &value ); + g_value_unset( &value ); + } + } } static int @@ -308,7 +352,6 @@ vips_foreign_load_png_header( VipsForeignLoad *load ) return( -1 ); } - #ifdef DEBUG printf( "width: %d\nheight: %d\nbit depth: %d\ncolor type: %d\n", png->ihdr.width, png->ihdr.height, diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index a730b659..4540a69a 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -79,6 +79,8 @@ * - revise for connection IO * 11/5/20 * - only warn for saving bad profiles, don't fail + * 19/2/21 781545872 + * - read out background, if we can */ /* @@ -559,6 +561,54 @@ png2vips_header( Read *read, VipsImage *out ) if( color_type == PNG_COLOR_TYPE_PALETTE ) vips_image_set_int( out, "palette-bit-depth", bitdepth ); + /* Note the PNG background colour, if any. + */ +#ifdef PNG_bKGD_SUPPORTED +{ + png_color_16 *background; + + if( png_get_bKGD( read->pPng, read->pInfo, &background ) ) { + const int scale = out->BandFmt == VIPS_FORMAT_UCHAR ? 1 : 256; + + double array[3]; + int n; + + switch( color_type ) { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + array[0] = background->gray / scale; + n = 1; + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + array[0] = background->red / scale; + array[1] = background->green / scale; + array[2] = background->blue / scale; + n = 3; + break; + + case PNG_COLOR_TYPE_PALETTE: + default: + /* Not sure what to do here. I suppose we should read + * the palette. + */ + n = 0; + break; + } + + if( n > 0 ) { + GValue value = { 0 }; + + g_value_init( &value, VIPS_TYPE_ARRAY_DOUBLE ); + vips_value_set_array_double( &value, array, n ); + vips_image_set( out, "background", &value ); + g_value_unset( &value ); + } + } +} +#endif + return( 0 ); }