diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 83e5b8e0..d0773caa 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -187,7 +187,7 @@ int vips__png_write_target( VipsImage *in, VipsTarget *target, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip, gboolean palette, int Q, double dither, - int bitdepth ); + int bitdepth, int effort ); /* Map WEBP metadata names to vips names. */ @@ -217,7 +217,7 @@ int vips__webp_write_target( VipsImage *image, VipsTarget *target, int vips__quantise_image( VipsImage *in, VipsImage **index_out, VipsImage **palette_out, - int colours, int Q, double dither ); + int colours, int Q, double dither, int effort ); extern const char *vips_foreign_nifti_suffs[]; diff --git a/libvips/foreign/pngsave.c b/libvips/foreign/pngsave.c index fcbdd112..ecdbb3a2 100644 --- a/libvips/foreign/pngsave.c +++ b/libvips/foreign/pngsave.c @@ -68,6 +68,7 @@ typedef struct _VipsForeignSavePng { int Q; double dither; int bitdepth; + int effort; /* Set by subclasses. */ @@ -153,7 +154,7 @@ vips_foreign_save_png_build( VipsObject *object ) 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 ) ) { + png->bitdepth, png->effort ) ) { g_object_unref( in ); return( -1 ); } @@ -262,6 +263,13 @@ vips_foreign_save_png_class_init( VipsForeignSavePngClass *class ) G_STRUCT_OFFSET( VipsForeignSavePng, bitdepth ), 0, 8, 0 ); + VIPS_ARG_INT( class, "effort", 18, + _( "Effort" ), + _( "Quantisation CPU effort" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSavePng, effort ), + 1, 10, 7 ); + VIPS_ARG_INT( class, "colours", 14, _( "Colours" ), _( "Max number of palette colours" ), @@ -278,6 +286,7 @@ vips_foreign_save_png_init( VipsForeignSavePng *png ) png->filter = VIPS_FOREIGN_PNG_FILTER_ALL; png->Q = 100; png->dither = 1.0; + png->effort = 7; } typedef struct _VipsForeignSavePngTarget { @@ -464,6 +473,7 @@ vips_foreign_save_png_buffer_init( VipsForeignSavePngBuffer *buffer ) * * @Q: %gint, quality for 8bpp quantisation * * @dither: %gdouble, amount of dithering for 8bpp quantization * * @bitdepth: %int, set write bit depth to 1, 2, 4 or 8 + * * @effort: %int, quantisation CPU effort * * Write a VIPS image to a file as PNG. * @@ -492,8 +502,9 @@ vips_foreign_save_png_buffer_init( VipsForeignSavePngBuffer *buffer ) * * Set @palette to %TRUE to enable palette mode for RGB or RGBA images. A * palette will be computed with enough space for @bitdepth (1, 2, 4 or 8) - * bits. Use @Q to set the optimisation effort, and @dither to set the degree of - * Floyd-Steinberg dithering. + * bits. Use @Q to set the optimisation effort, @dither to set the degree of + * Floyd-Steinberg dithering and @effort to control the CPU effort + * (1 is the fastest, 10 is the slowest, 7 is the default). * This feature requires libvips to be compiled with libimagequant. * * You can also set @bitdepth for mono and mono + alpha images, and the image @@ -536,6 +547,7 @@ vips_pngsave( VipsImage *in, const char *filename, ... ) * * @Q: %gint, quality for 8bpp quantisation * * @dither: %gdouble, amount of dithering for 8bpp quantization * * @bitdepth: %int, set write bit depth to 1, 2, 4 or 8 + * * @effort: %int, quantisation CPU effort * * As vips_pngsave(), but save to a memory buffer. * @@ -591,6 +603,7 @@ vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) * * @Q: quality for 8bpp quantisation * * @dither: amount of dithering for 8bpp quantization * * @bitdepth: %int, set write bit depth to 1, 2, 4 or 8 + * * @effort: %int, quantisation CPU effort * * As vips_pngsave(), but save to a target. * diff --git a/libvips/foreign/quantise.c b/libvips/foreign/quantise.c index 160d9b69..4bc10669 100644 --- a/libvips/foreign/quantise.c +++ b/libvips/foreign/quantise.c @@ -53,11 +53,12 @@ */ typedef struct _Quantise { VipsImage *in; - VipsImage **index_out; - VipsImage **palette_out; - int colours; - int Q; - double dither; + VipsImage **index_out; + VipsImage **palette_out; + int colours; + int Q; + double dither; + int effort; liq_attr *attr; liq_image *input_image; @@ -83,7 +84,7 @@ vips__quantise_free( Quantise *quantise ) static Quantise * vips__quantise_new( VipsImage *in, VipsImage **index_out, VipsImage **palette_out, - int colours, int Q, double dither ) + int colours, int Q, double dither, int effort ) { Quantise *quantise; int i; @@ -95,6 +96,7 @@ vips__quantise_new( VipsImage *in, quantise->colours = colours; quantise->Q = Q; quantise->dither = dither; + quantise->effort = effort; for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ ) quantise->t[i] = NULL; @@ -104,7 +106,7 @@ vips__quantise_new( VipsImage *in, int vips__quantise_image( VipsImage *in, VipsImage **index_out, VipsImage **palette_out, - int colours, int Q, double dither ) + int colours, int Q, double dither, int effort ) { Quantise *quantise; VipsImage *index; @@ -113,7 +115,7 @@ vips__quantise_image( VipsImage *in, int i; quantise = vips__quantise_new( in, index_out, palette_out, - colours, Q, dither ); + colours, Q, dither, effort ); /* Ensure input is sRGB. */ @@ -145,13 +147,14 @@ vips__quantise_image( VipsImage *in, quantise->attr = liq_attr_create(); liq_set_max_colors( quantise->attr, colours ); liq_set_quality( quantise->attr, 0, Q ); + liq_set_speed( quantise->attr, 11 - effort ); quantise->input_image = liq_image_create_rgba( quantise->attr, VIPS_IMAGE_ADDR( in, 0, 0 ), in->Xsize, in->Ysize, 0 ); if( liq_image_quantize( quantise->input_image, quantise->attr, &quantise->quantisation_result ) ) { - vips_error( "vips2png", "%s", _( "quantisation failed" ) ); + vips_error( "quantise", "%s", _( "quantisation failed" ) ); vips__quantise_free( quantise ); return( -1 ); } @@ -171,7 +174,7 @@ vips__quantise_image( VipsImage *in, if( liq_write_remapped_image( quantise->quantisation_result, quantise->input_image, VIPS_IMAGE_ADDR( index, 0, 0 ), VIPS_IMAGE_N_PELS( index ) ) ) { - vips_error( "vips2png", "%s", _( "quantisation failed" ) ); + vips_error( "quantise", "%s", _( "quantisation failed" ) ); vips__quantise_free( quantise ); return( -1 ); } diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index 6b15b1c8..1915a819 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -986,7 +986,7 @@ write_vips( Write *write, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip, gboolean palette, int Q, double dither, - int bitdepth ) + int bitdepth, int effort ) { VipsImage *in = write->in; @@ -1162,7 +1162,7 @@ write_vips( Write *write, int trans_count; if( vips__quantise_image( in, &im_index, &im_palette, - 1 << bitdepth, Q, dither ) ) + 1 << bitdepth, Q, dither, effort ) ) return( -1 ); palette_count = im_palette->Xsize; @@ -1256,7 +1256,7 @@ vips__png_write_target( VipsImage *in, VipsTarget *target, int compression, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip, gboolean palette, int Q, double dither, - int bitdepth ) + int bitdepth, int effort ) { Write *write; @@ -1265,7 +1265,7 @@ vips__png_write_target( VipsImage *in, VipsTarget *target, if( write_vips( write, compression, interlace, profile, filter, strip, palette, - Q, dither, bitdepth ) ) { + Q, dither, bitdepth, effort ) ) { write_destroy( write ); vips_error( "vips2png", _( "unable to write to target %s" ), vips_connection_nick( VIPS_CONNECTION( target ) ) );