From d8ed630d77c21a994e15939ccd148fcff9e423f2 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 16 Jan 2021 15:45:59 +0000 Subject: [PATCH] better 8/16 bit casting for pngsave pngsave was just using the image format to decide whether to save as 8 or 16 bit PNG. With this patch it checks Type as well. This means that eg. a uint32 image tagged as sRGB will save as png8, but a uint32 image tagged as RGB16 will save as png16. --- ChangeLog | 1 + libvips/foreign/foreign.c | 9 ++++++--- libvips/foreign/pngsave.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8cb7f038..9e25c5be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,7 @@ - add vips_source_g_input_stream_new() to load images from a GInputStream - add openslideload_source(), vipsload_source(), vipssave_target() - add hist path to rank for large windows on uchar images +- better 8/16-bit choice for pngsave 22/12/20 start 8.10.6 - don't seek on bad file descriptors [kleisauke] diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index e9a8b31c..326b4507 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1395,12 +1395,15 @@ vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, in = out; } - /* If this is something other than CMYK or RAD, eg. maybe a LAB image, - * we need to transform to RGB. + /* If this is something other than CMYK or RAD, and it's not already + * an RGB image, eg. maybe a LAB or scRGB image, we need to transform + * to RGB. */ if( !coding[VIPS_CODING_RAD] && in->Bands >= 3 && in->Type != VIPS_INTERPRETATION_CMYK && + in->Type != VIPS_INTERPRETATION_sRGB && + in->Type != VIPS_INTERPRETATION_RGB16 && vips_colourspace_issupported( in ) && (saveable == VIPS_SAVEABLE_RGB || saveable == VIPS_SAVEABLE_RGBA || @@ -1426,7 +1429,7 @@ vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, in = out; } - /* VIPS_SAVEABLE_RGBA_ONLY does not support 1 or 2 bands ... convert + /* VIPS_SAVEABLE_RGBA_ONLY does not support mono types ... convert * to sRGB. */ if( !coding[VIPS_CODING_RAD] && diff --git a/libvips/foreign/pngsave.c b/libvips/foreign/pngsave.c index 7113d972..f188f3f9 100644 --- a/libvips/foreign/pngsave.c +++ b/libvips/foreign/pngsave.c @@ -102,10 +102,31 @@ vips_foreign_save_png_build( VipsObject *object ) VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSavePng *png = (VipsForeignSavePng *) object; + VipsImage *in; + if( VIPS_OBJECT_CLASS( vips_foreign_save_png_parent_class )-> build( object ) ) return( -1 ); + 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( in->Type == VIPS_INTERPRETATION_sRGB || + in->Type == VIPS_INTERPRETATION_B_W ) { + VipsImage *x; + + if( vips_cast( in, &x, VIPS_FORMAT_UCHAR, NULL ) ) { + g_object_unref( in ); + return( -1 ); + } + g_object_unref( in ); + in = x; + } + /* Deprecated "colours" arg just sets bitdepth large enough to hold * that many colours. */ @@ -113,17 +134,16 @@ vips_foreign_save_png_build( VipsObject *object ) png->bitdepth = ceil( log2( png->colours ) ); if( !vips_object_argument_isset( object, "bitdepth" ) ) - png->bitdepth = - save->ready->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16; + 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. */ - if( save->ready->Bands > 2 && + if( in->Bands > 2 && png->bitdepth < 8 ) png->palette = TRUE; - if( vips__png_write_target( save->ready, png->target, + if( vips__png_write_target( in, png->target, png->compression, png->interlace, png->profile, png->filter, save->strip, png->palette, png->Q, png->dither, png->bitdepth ) ) @@ -145,9 +165,12 @@ vips_foreign_save_png_build( VipsObject *object ) #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX +/* Except for 8-bit inputs, we send everything else to 16. We decide on png8 + * vs. png16 based on Type in_build(), see above. + */ static int bandfmt_png[10] = { /* UC C US S UI I F X D DX */ - UC, UC, US, US, US, US, UC, UC, UC, UC + UC, UC, US, US, US, US, US, US, US, US }; static void