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.
This commit is contained in:
John Cupitt 2021-01-16 15:45:59 +00:00
parent 78d1a4ae57
commit d8ed630d77
3 changed files with 35 additions and 8 deletions

View File

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

View File

@ -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] &&

View File

@ -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