diff --git a/ChangeLog b/ChangeLog index 240d555c..b6a5465f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -41,6 +41,7 @@ - vipsheader allows "stdin" as a filename - gifload allows gifs with images outside the canvas - wasm compatibility patches [kleisauke] +- webpsave has a @profile param 24/4/20 started 8.9.3 - better iiif tile naming [IllyaMoskvin] diff --git a/libvips/foreign/jpegsave.c b/libvips/foreign/jpegsave.c index e1cca6c1..cc08710d 100644 --- a/libvips/foreign/jpegsave.c +++ b/libvips/foreign/jpegsave.c @@ -525,7 +525,7 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime ) * Optional arguments: * * * @Q: %gint, quality factor - * * @profile: filename of ICC profile to attach + * * @profile: %gchararray, filename of ICC profile to attach * * @optimize_coding: %gboolean, compute optimal Huffman coding tables * * @interlace: %gboolean, write an interlaced (progressive) jpeg * * @strip: %gboolean, remove all metadata from image @@ -641,7 +641,7 @@ vips_jpegsave( VipsImage *in, const char *filename, ... ) * Optional arguments: * * * @Q: %gint, quality factor - * * @profile: filename of ICC profile to attach + * * @profile: %gchararray, filename of ICC profile to attach * * @optimize_coding: %gboolean, compute optimal Huffman coding tables * * @interlace: %gboolean, write an interlaced (progressive) jpeg * * @strip: %gboolean, remove all metadata from image @@ -680,7 +680,7 @@ vips_jpegsave_target( VipsImage *in, VipsTarget *target, ... ) * Optional arguments: * * * @Q: %gint, quality factor - * * @profile: filename of ICC profile to attach + * * @profile: %gchararray, filename of ICC profile to attach * * @optimize_coding: %gboolean, compute optimal Huffman coding tables * * @interlace: %gboolean, write an interlaced (progressive) jpeg * * @strip: %gboolean, remove all metadata from image @@ -736,7 +736,7 @@ vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) * Optional arguments: * * * @Q: %gint, quality factor - * * @profile: filename of ICC profile to attach + * * @profile: %gchararray, filename of ICC profile to attach * * @optimize_coding: %gboolean, compute optimal Huffman coding tables * * @interlace: %gboolean, write an interlaced (progressive) jpeg * * @strip: %gboolean, remove all metadata from image diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 6adea1bc..4b42bbe5 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -50,7 +50,7 @@ void vips__tiff_init( void ); int vips__tiff_write( VipsImage *in, const char *filename, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, - char *profile, + const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, @@ -70,7 +70,7 @@ int vips__tiff_write_buf( VipsImage *in, void **obuf, size_t *olen, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, - char *profile, + const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, @@ -211,7 +211,7 @@ int vips__webp_write_target( VipsImage *image, VipsTarget *target, gboolean smart_subsample, gboolean near_lossless, int alpha_q, int reduction_effort, gboolean min_size, int kmin, int kmax, - gboolean strip ); + gboolean strip, const char *profile ); int vips__openslide_isslide( const char *filename ); int vips__openslide_read_header( const char *filename, VipsImage *out, diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 9a6244a9..a4331b77 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -344,7 +344,7 @@ struct _Wtiff { int resunit; /* Resolution unit (inches or cm) */ double xres; /* Resolution in X */ double yres; /* Resolution in Y */ - char *icc_profile; /* Profile to embed */ + const char *profile; /* Profile to embed */ int bigtiff; /* True for bigtiff write */ int rgbjpeg; /* True for RGB not YCbCr */ int properties; /* Set to save XML props */ @@ -512,11 +512,11 @@ wtiff_layer_init( Wtiff *wtiff, Layer **layer, Layer *above, static int wtiff_embed_profile( Wtiff *wtiff, TIFF *tif ) { - if( wtiff->icc_profile && - embed_profile_file( tif, wtiff->icc_profile ) ) + if( wtiff->profile && + embed_profile_file( tif, wtiff->profile ) ) return( -1 ); - if( !wtiff->icc_profile && + if( !wtiff->profile && vips_image_get_typeof( wtiff->ready, VIPS_META_ICC_NAME ) && embed_profile_meta( tif, wtiff->ready ) ) return( -1 ); @@ -981,7 +981,6 @@ wtiff_free( Wtiff *wtiff ) VIPS_UNREF( wtiff->ready ); VIPS_FREE( wtiff->tbuf ); VIPS_FREEF( layer_free_all, wtiff->layer ); - VIPS_FREE( wtiff->icc_profile ); VIPS_FREE( wtiff->filename ); VIPS_FREE( wtiff ); } @@ -1062,7 +1061,7 @@ static Wtiff * wtiff_new( VipsImage *input, const char *filename, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, - char *profile, + const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, @@ -1099,7 +1098,7 @@ wtiff_new( VipsImage *input, const char *filename, wtiff->resunit = get_resunit( resunit ); wtiff->xres = xres; wtiff->yres = yres; - wtiff->icc_profile = vips_strdup( NULL, profile ); + wtiff->profile = profile; wtiff->bigtiff = bigtiff; wtiff->rgbjpeg = rgbjpeg; wtiff->properties = properties; @@ -1866,7 +1865,7 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in ) TIFFSetField( out, TIFFTAG_ZSTD_LEVEL, wtiff->level ); #endif /*HAVE_TIFF_COMPRESSION_WEBP*/ - /* We can't copy profiles or xmp :( Set again from Wtiff. + /* We can't copy profiles or xmp :( Set again from wtiff. */ if( !wtiff->strip ) if( wtiff_embed_profile( wtiff, out ) || @@ -2059,7 +2058,7 @@ int vips__tiff_write( VipsImage *input, const char *filename, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, - char *profile, + const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, @@ -2105,7 +2104,7 @@ vips__tiff_write_buf( VipsImage *input, void **obuf, size_t *olen, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, - char *profile, + const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, diff --git a/libvips/foreign/vips2webp.c b/libvips/foreign/vips2webp.c index f480e67d..49ab1d1c 100644 --- a/libvips/foreign/vips2webp.c +++ b/libvips/foreign/vips2webp.c @@ -18,6 +18,8 @@ * - set loop even if we strip * 14/10/19 * - revise for target IO + * 18/7/20 + * - add @profile param to match tiff, jpg, etc. */ /* @@ -88,6 +90,7 @@ typedef struct { int kmin; int kmax; gboolean strip; + const char *profile; WebPConfig config; @@ -146,7 +149,7 @@ vips_webp_write_init( VipsWebPWrite *write, VipsImage *image, gboolean smart_subsample, gboolean near_lossless, int alpha_q, int reduction_effort, gboolean min_size, int kmin, int kmax, - gboolean strip ) + gboolean strip, const char *profile ) { write->image = NULL; write->Q = Q; @@ -160,14 +163,15 @@ vips_webp_write_init( VipsWebPWrite *write, VipsImage *image, write->kmin = kmin; write->kmax = kmax; write->strip = strip; + write->profile = profile; WebPMemoryWriterInit( &write->memory_writer ); write->enc = NULL; write->mux = NULL; - /* Rebuild exif on image. We must do this on a copy. + /* We need a copy of the input image in case we change the metadata + * eg. in vips__exif_update(). */ - if( vips_copy( image, &write->image, NULL ) || - vips__exif_update( write->image ) ) { + if( vips_copy( image, &write->image, NULL ) ) { vips_webp_write_unset( write ); return( -1 ); } @@ -456,6 +460,9 @@ vips_webp_add_chunks( VipsWebPWrite *write ) const char *vips_name = vips__webp_names[i].vips; const char *webp_name = vips__webp_names[i].webp; + if( strcmp( vips_name, VIPS_META_ICC_NAME ) == 0 && + write->profile ) + if( vips_image_get_typeof( write->image, vips_name ) ) { const void *data; size_t length; @@ -507,9 +514,22 @@ vips_webp_add_metadata( VipsWebPWrite *write ) /* Add extra metadata. */ - if( !write->strip && - vips_webp_add_chunks( write ) ) - return( -1 ); + if( !write->strip ) { + /* We need to rebuild exif from the other image tags before + * writing the metadata. + */ + if( vips__exif_update( write->image ) ) + return( -1 ); + + /* Override profile. + */ + if( write->profile && + vips__profile_set( write->image, write->profile ) ) + return( -1 ); + + if( vips_webp_add_chunks( write ) ) + return( -1 ); + } if( WebPMuxAssemble( write->mux, &data ) != WEBP_MUX_OK ) { vips_error( "vips2webp", "%s", _( "mux error" ) ); @@ -531,13 +551,14 @@ vips__webp_write_target( VipsImage *image, VipsTarget *target, gboolean smart_subsample, gboolean near_lossless, int alpha_q, int reduction_effort, gboolean min_size, int kmin, int kmax, - gboolean strip ) + gboolean strip, const char *profile ) { VipsWebPWrite write; if( vips_webp_write_init( &write, image, Q, lossless, preset, smart_subsample, near_lossless, - alpha_q, reduction_effort, min_size, kmin, kmax, strip ) ) + alpha_q, reduction_effort, min_size, kmin, kmax, strip, + profile ) ) return( -1 ); if( write_webp( &write ) ) { diff --git a/libvips/foreign/webpsave.c b/libvips/foreign/webpsave.c index ef08e8a2..e969fd00 100644 --- a/libvips/foreign/webpsave.c +++ b/libvips/foreign/webpsave.c @@ -6,6 +6,8 @@ * - add animated webp support * 15/1/19 lovell * - add @reduction_effort + * 18/7/20 + * - add @profile param to match tiff, jpg, etc. */ /* @@ -99,6 +101,10 @@ typedef struct _VipsForeignSaveWebp { */ int kmax; + /* Profile to embed. + */ + char *profile; + } VipsForeignSaveWebp; typedef VipsForeignSaveClass VipsForeignSaveWebpClass; @@ -204,6 +210,13 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class ) VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsForeignSaveWebp, reduction_effort ), 0, 6, 4 ); + + VIPS_ARG_STRING( class, "profile", 20, + _( "Profile" ), + _( "ICC profile to embed" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveWebp, profile ), + NULL ); } static void @@ -248,7 +261,7 @@ vips_foreign_save_webp_target_build( VipsObject *object ) webp->smart_subsample, webp->near_lossless, webp->alpha_q, webp->reduction_effort, webp->min_size, webp->kmin, webp->kmax, - save->strip ) ) + save->strip, webp->profile ) ) return( -1 ); return( 0 ); @@ -316,7 +329,7 @@ vips_foreign_save_webp_file_build( VipsObject *object ) webp->smart_subsample, webp->near_lossless, webp->alpha_q, webp->reduction_effort, webp->min_size, webp->kmin, webp->kmax, - save->strip ) ) { + save->strip, webp->profile ) ) { VIPS_UNREF( target ); return( -1 ); } @@ -388,7 +401,7 @@ vips_foreign_save_webp_buffer_build( VipsObject *object ) webp->smart_subsample, webp->near_lossless, webp->alpha_q, webp->reduction_effort, webp->min_size, webp->kmin, webp->kmax, - save->strip ) ) { + save->strip, webp->profile ) ) { VIPS_UNREF( target ); return( -1 ); } @@ -462,7 +475,7 @@ vips_foreign_save_webp_mime_build( VipsObject *object ) webp->smart_subsample, webp->near_lossless, webp->alpha_q, webp->reduction_effort, webp->min_size, webp->kmin, webp->kmax, - save->strip ) ) { + save->strip, webp->profile ) ) { VIPS_UNREF( target ); return( -1 ); } @@ -520,6 +533,7 @@ vips_foreign_save_webp_mime_init( VipsForeignSaveWebpMime *mime ) * * @kmin: %gint, minimum number of frames between keyframes * * @kmax: %gint, maximum number of frames between keyframes * * @strip: %gboolean, remove all metadata from image + * * @profile: %gchararray, filename of ICC profile to attach * * Write an image to a file in WebP format. * @@ -550,6 +564,10 @@ vips_foreign_save_webp_mime_init( VipsForeignSaveWebpMime *mime ) * frames between frames. Setting 0 means no keyframes. By default, keyframes * are disabled. * + * Use @profile to give the name of a profile to be embedded in the file. + * This does not affect the pixels which are written, just the way + * they are tagged. See vips_profile_load() for details on profile naming. + * * Use the metadata items `loop` and `delay` to set the number of * loops for the animation and the frame delays. * @@ -593,6 +611,7 @@ vips_webpsave( VipsImage *in, const char *filename, ... ) * * @kmin: %gint, minimum number of frames between keyframes * * @kmax: %gint, maximum number of frames between keyframes * * @strip: %gboolean, remove all metadata from image + * * @profile: %gchararray, filename of ICC profile to attach * * As vips_webpsave(), but save to a memory buffer. * @@ -650,6 +669,7 @@ vips_webpsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) * * @kmin: %gint, minimum number of frames between keyframes * * @kmax: %gint, maximum number of frames between keyframes * * @strip: %gboolean, remove all metadata from image + * * @profile: %gchararray, filename of ICC profile to attach * * As vips_webpsave(), but save as a mime webp on stdout. * @@ -689,6 +709,7 @@ vips_webpsave_mime( VipsImage *in, ... ) * * @kmin: %gint, minimum number of frames between keyframes * * @kmax: %gint, maximum number of frames between keyframes * * @strip: %gboolean, remove all metadata from image + * * @profile: %gchararray, filename of ICC profile to attach * * As vips_webpsave(), but save to a target. *