fix low bitdepth PNG save of high bitdepth images

SOme combinations of high bitdepth images with low bitdepth PNG save could
produce incorrect images, for example saving a 16-bit fourier image as 1-bit.
This commit is contained in:
John Cupitt 2022-08-14 12:14:55 +01:00
parent 94d3f93a46
commit 1989203985
3 changed files with 43 additions and 34 deletions

View File

@ -5,6 +5,7 @@
- add "unlimited" to jpegload
- better 0 detection in unpremultiply
- fix low bitdepth spng save [jeffska]
- fix PNG low bitdepth save of high bitdepth images
21/11/21 started 8.13
- configure fails for requested but unmet dependencies [remicollet]

View File

@ -112,12 +112,22 @@ vips_foreign_save_png_build( VipsObject *object )
in = save->ready;
g_object_ref( in );
/* save->ready will have been converted to uint16 for high-bitdepth
* formats (eg. float) ... we need to check Type to see if we want
* to save as 8 or 16-bits. Eg. imagine a float image tagged as sRGB.
/* If no output bitdepth has been specified, use input Type to pick.
*/
if( in->Type == VIPS_INTERPRETATION_sRGB ||
in->Type == VIPS_INTERPRETATION_B_W ) {
if( !vips_object_argument_isset( object, "bitdepth" ) )
png->bitdepth =
in->Type == VIPS_INTERPRETATION_RGB16 ||
in->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8;
/* Deprecated "colours" arg just sets bitdepth large enough to hold
* that many colours.
*/
if( vips_object_argument_isset( object, "colours" ) )
png->bitdepth = ceil( log2( png->colours ) );
/* Cast in down to 8 bit if we can.
*/
if( png->bitdepth <= 8 ) {
VipsImage *x;
if( vips_cast( in, &x, VIPS_FORMAT_UCHAR, NULL ) ) {
@ -128,15 +138,6 @@ vips_foreign_save_png_build( VipsObject *object )
in = x;
}
/* Deprecated "colours" arg just sets bitdepth large enough to hold
* that many colours.
*/
if( vips_object_argument_isset( object, "colours" ) )
png->bitdepth = ceil( log2( png->colours ) );
if( !vips_object_argument_isset( object, "bitdepth" ) )
png->bitdepth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16;
/* If this is a RGB or RGBA image and a low bit depth has been
* requested, enable palettization.
*/
@ -144,6 +145,11 @@ vips_foreign_save_png_build( VipsObject *object )
png->bitdepth < 8 )
png->palette = TRUE;
/* Disable palettization for >8 bit save.
*/
if( png->bitdepth >= 8 )
png->palette = FALSE;
if( vips__png_write_target( in, png->target,
png->compression, png->interlace, png->profile, png->filter,
save->strip, png->palette, png->Q, png->dither,

View File

@ -42,9 +42,9 @@
*/
/*
*/
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -485,7 +485,7 @@ vips_foreign_save_spng_write( VipsForeignSaveSpng *spng, VipsImage *in )
spng_set_option( spng->ctx,
SPNG_FILTER_CHOICE, spng->filter );
/* Set resolution. libpng uses pixels per meter.
/* Set resolution. png uses pixels per meter.
*/
phys.unit_specifier = 1;
phys.ppu_x = VIPS_RINT( in->Xres * 1000.0 );
@ -580,12 +580,22 @@ vips_foreign_save_spng_build( VipsObject *object )
in = save->ready;
g_object_ref( in );
/* in will have been converted to uint16 for high-bitdepth
* formats (eg. float) ... we need to check Type to see if we want
* to save as 8 or 16-bits. Eg. imagine a float image tagged as sRGB.
/* If no output bitdepth has been specified, use input Type to pick.
*/
if( in->Type == VIPS_INTERPRETATION_sRGB ||
in->Type == VIPS_INTERPRETATION_B_W ) {
if( !vips_object_argument_isset( object, "bitdepth" ) )
spng->bitdepth =
in->Type == VIPS_INTERPRETATION_RGB16 ||
in->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8;
/* Deprecated "colours" arg just sets bitdepth large enough to hold
* that many colours.
*/
if( vips_object_argument_isset( object, "colours" ) )
spng->bitdepth = ceil( log2( spng->colours ) );
/* Cast in down to 8 bit if we can.
*/
if( spng->bitdepth <= 8 ) {
VipsImage *x;
if( vips_cast( in, &x, VIPS_FORMAT_UCHAR, NULL ) ) {
@ -596,19 +606,6 @@ vips_foreign_save_spng_build( VipsObject *object )
in = x;
}
/* If no output bitdepth has been specified, use input Type to pick.
* We only go for 16 bits for the types where we know there's a
* 0-65535 range.
*/
if( !vips_object_argument_isset( object, "bitdepth" ) )
spng->bitdepth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16;
/* Deprecated "colours" arg just sets bitdepth large enough to hold
* that many colours.
*/
if( vips_object_argument_isset( object, "colours" ) )
spng->bitdepth = ceil( log2( spng->colours ) );
/* If this is a RGB or RGBA image and a low bit depth has been
* requested, enable palettisation.
*/
@ -616,6 +613,11 @@ vips_foreign_save_spng_build( VipsObject *object )
spng->bitdepth < 8 )
spng->palette = TRUE;
/* Disable palettization for >8 bit save.
*/
if( spng->bitdepth >= 8 )
spng->palette = FALSE;
if( vips_foreign_save_spng_write( spng, in ) ) {
g_object_unref( in );
return( -1 );