Skip to content

Commit f38acde

Browse files
authored
spngsave: ensure quantisation occurs last (#3073)
* spngsave: ensure quantisation occurs last i.e. after setting the metadata and phyiscal pixel dimensions, since quantisation will overwrite the image. * spngsave: avoid over-allocation of temporary buffer For low-bitdepth write and palette-based output.
1 parent fbef674 commit f38acde

File tree

2 files changed

+73
-68
lines changed

2 files changed

+73
-68
lines changed

libvips/foreign/spngsave.c

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,6 @@ vips_foreign_save_spng_write( VipsForeignSaveSpng *spng, VipsImage *in )
362362
int error;
363363
struct spng_ihdr ihdr;
364364
struct spng_phys phys;
365-
struct spng_plte plte = { 0 };
366-
struct spng_trns trns = { 0 };
367365
int fmt;
368366
enum spng_encode_flags encode_flags;
369367

@@ -375,8 +373,76 @@ vips_foreign_save_spng_write( VipsForeignSaveSpng *spng, VipsImage *in )
375373
return( -1 );
376374
}
377375

376+
ihdr.width = in->Xsize;
377+
ihdr.height = in->Ysize;
378+
ihdr.bit_depth = spng->bitdepth;
379+
380+
switch( in->Bands ) {
381+
case 1:
382+
ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE;
383+
break;
384+
385+
case 2:
386+
ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE_ALPHA;
387+
break;
388+
389+
case 3:
390+
ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR;
391+
break;
392+
393+
case 4:
394+
ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA;
395+
break;
396+
397+
default:
398+
vips_error( class->nickname, "%s", _( "bad bands" ) );
399+
return( -1 );
400+
}
401+
402+
#ifdef HAVE_QUANTIZATION
403+
/* Enable image quantisation to paletted 8bpp PNG if palette is set.
404+
*/
405+
if( spng->palette )
406+
ihdr.color_type = SPNG_COLOR_TYPE_INDEXED;
407+
#else
408+
if( spng->palette )
409+
g_warning( "%s",
410+
_( "ignoring palette (no quantisation support)" ) );
411+
#endif /*HAVE_QUANTIZATION*/
412+
413+
ihdr.compression_method = 0;
414+
ihdr.filter_method = 0;
415+
ihdr.interlace_method = spng->interlace ? 1 : 0;
416+
if( (error = spng_set_ihdr( spng->ctx, &ihdr )) ) {
417+
vips_error( class->nickname, "%s", spng_strerror( error ) );
418+
return( -1 );
419+
}
420+
421+
spng_set_option( spng->ctx,
422+
SPNG_IMG_COMPRESSION_LEVEL, spng->compression );
423+
spng_set_option( spng->ctx,
424+
SPNG_TEXT_COMPRESSION_LEVEL, spng->compression );
425+
spng_set_option( spng->ctx,
426+
SPNG_FILTER_CHOICE, spng->filter );
427+
428+
/* Set resolution. spng uses pixels per meter.
429+
*/
430+
phys.unit_specifier = 1;
431+
phys.ppu_x = VIPS_RINT( in->Xres * 1000.0 );
432+
phys.ppu_y = VIPS_RINT( in->Xres * 1000.0 );
433+
spng_set_phys( spng->ctx, &phys );
434+
435+
/* Metadata.
436+
*/
437+
if( !save->strip &&
438+
vips_foreign_save_spng_metadata( spng, in ) )
439+
return( -1 );
440+
378441
#ifdef HAVE_QUANTIZATION
379442
if( spng->palette ) {
443+
struct spng_plte plte = { 0 };
444+
struct spng_trns trns = { 0 };
445+
380446
VipsImage *im_index;
381447
VipsImage *im_palette;
382448
int palette_count;
@@ -426,14 +492,14 @@ vips_foreign_save_spng_write( VipsForeignSaveSpng *spng, VipsImage *in )
426492

427493
VIPS_UNREF( im_palette );
428494

495+
spng_set_plte( spng->ctx, &plte );
496+
if( trns.n_type3_entries )
497+
spng_set_trns( spng->ctx, &trns );
498+
429499
in = spng->memory = im_index;
430500
}
431501
#endif /*HAVE_QUANTIZATION*/
432502

433-
ihdr.width = in->Xsize;
434-
ihdr.height = in->Ysize;
435-
ihdr.bit_depth = spng->bitdepth;
436-
437503
/* Low-bitdepth write needs an extra buffer for packing pixels.
438504
*/
439505
if( spng->bitdepth < 8 ) {
@@ -445,67 +511,6 @@ vips_foreign_save_spng_write( VipsForeignSaveSpng *spng, VipsImage *in )
445511
return( -1 );
446512
}
447513

448-
switch( in->Bands ) {
449-
case 1:
450-
if( spng->palette )
451-
ihdr.color_type = SPNG_COLOR_TYPE_INDEXED;
452-
else
453-
ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE;
454-
break;
455-
456-
case 2:
457-
ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE_ALPHA;
458-
break;
459-
460-
case 3:
461-
ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR;
462-
break;
463-
464-
case 4:
465-
ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA;
466-
break;
467-
468-
default:
469-
vips_error( class->nickname, "%s", _( "bad bands" ) );
470-
return( -1 );
471-
}
472-
473-
ihdr.compression_method = 0;
474-
ihdr.filter_method = 0;
475-
ihdr.interlace_method = spng->interlace ? 1 : 0;
476-
if( (error = spng_set_ihdr( spng->ctx, &ihdr )) ) {
477-
vips_error( class->nickname, "%s", spng_strerror( error ) );
478-
return( -1 );
479-
}
480-
481-
spng_set_option( spng->ctx,
482-
SPNG_IMG_COMPRESSION_LEVEL, spng->compression );
483-
spng_set_option( spng->ctx,
484-
SPNG_TEXT_COMPRESSION_LEVEL, spng->compression );
485-
spng_set_option( spng->ctx,
486-
SPNG_FILTER_CHOICE, spng->filter );
487-
488-
/* Set resolution. png uses pixels per meter.
489-
*/
490-
phys.unit_specifier = 1;
491-
phys.ppu_x = VIPS_RINT( in->Xres * 1000.0 );
492-
phys.ppu_y = VIPS_RINT( in->Xres * 1000.0 );
493-
spng_set_phys( spng->ctx, &phys );
494-
495-
/* Metadata.
496-
*/
497-
if( !save->strip &&
498-
vips_foreign_save_spng_metadata( spng, in ) )
499-
return( -1 );
500-
501-
#ifdef HAVE_QUANTIZATION
502-
if( spng->palette ) {
503-
spng_set_plte( spng->ctx, &plte );
504-
if( trns.n_type3_entries )
505-
spng_set_trns( spng->ctx, &trns );
506-
}
507-
#endif /*HAVE_QUANTIZATION*/
508-
509514
/* SPNG_FMT_PNG is a special value that matches the format in ihdr
510515
*/
511516
fmt = SPNG_FMT_PNG;

libvips/foreign/vipspng.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ write_vips( Write *write,
10771077
}
10781078

10791079
#ifdef HAVE_QUANTIZATION
1080-
/* Enable image quantisation to paletted 8bpp PNG if colours is set.
1080+
/* Enable image quantisation to paletted 8bpp PNG if palette is set.
10811081
*/
10821082
if( palette )
10831083
color_type = PNG_COLOR_TYPE_PALETTE;

0 commit comments

Comments
 (0)