diff --git a/ChangeLog b/ChangeLog index 636a1b8b..be62334b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ - remove lcms1 support, it had bitrotted - `join` tagged as seq - support tiffsave_buffer for pyramids, thanks bubba +- thumbnail and vipsthumbnail have an option for rendering intent, thanks kleisauke 29/8/17 started 8.5.9 - make --fail stop jpeg read on any libjpeg warning, thanks @mceachen diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index 0ef78d0a..c10b511e 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -9,6 +9,8 @@ * - add FORCE * 29/5/17 * - don't cache (thanks tomasc) + * 30/8/17 + * - add intent option, thanks kleisauke */ /* @@ -81,6 +83,7 @@ typedef struct _VipsThumbnail { gboolean linear; char *export_profile; char *import_profile; + VipsIntent intent; /* Set by subclasses to the input image. */ @@ -375,6 +378,7 @@ vips_thumbnail_build( VipsObject *object ) if( vips_icc_import( in, &t[1], "input_profile", thumbnail->import_profile, "embedded", TRUE, + "intent", thumbnail->intent, "pcs", VIPS_PCS_XYZ, NULL ) ) return( -1 ); @@ -442,6 +446,7 @@ vips_thumbnail_build( VipsObject *object ) g_info( "exporting to device space with a profile" ); if( vips_icc_export( in, &t[7], "output_profile", thumbnail->export_profile, + "intent", thumbnail->intent, NULL ) ) return( -1 ); in = t[7]; @@ -470,6 +475,7 @@ vips_thumbnail_build( VipsObject *object ) if( vips_icc_transform( in, &t[7], thumbnail->export_profile, + "intent", thumbnail->intent, "embedded", TRUE, NULL ) ) { g_warning( _( "unable to import with " @@ -489,6 +495,7 @@ vips_thumbnail_build( VipsObject *object ) if( vips_icc_transform( in, &t[7], thumbnail->export_profile, "input_profile", thumbnail->import_profile, + "intent", thumbnail->intent, "embedded", FALSE, NULL ) ) return( -1 ); @@ -630,6 +637,13 @@ vips_thumbnail_class_init( VipsThumbnailClass *class ) G_STRUCT_OFFSET( VipsThumbnail, export_profile ), NULL ); + VIPS_ARG_ENUM( class, "intent", 120, + _( "Intent" ), + _( "Rendering intent" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsThumbnail, intent ), + VIPS_TYPE_INTENT, VIPS_INTENT_RELATIVE ); + } static void @@ -638,6 +652,7 @@ vips_thumbnail_init( VipsThumbnail *thumbnail ) thumbnail->width = 1; thumbnail->height = 1; thumbnail->auto_rotate = TRUE; + thumbnail->intent = VIPS_INTENT_RELATIVE; } typedef struct _VipsThumbnailFile { @@ -745,6 +760,7 @@ vips_thumbnail_file_init( VipsThumbnailFile *file ) * * @linear: %gboolean, perform shrink in linear light * * @import_profile: %gchararray, fallback import ICC profile * * @export_profile: %gchararray, export ICC profile + * * @intent: #VipsIntent, rendering intent * * Make a thumbnail from a file. Shrinking is done in three stages: using any * shrink-on-load features available in the file import library, using a block @@ -786,6 +802,9 @@ vips_thumbnail_file_init( VipsThumbnailFile *file ) * input image has no ICC profile, or if the profile embedded in the * input image is broken. * + * Use @intent to set the rendering intent for any ICC transform. The default + * is #VIPS_INTENT_RELATIVE. + * * See also: vips_thumbnail_buffer(). * * Returns: 0 on success, -1 on error. @@ -917,6 +936,7 @@ vips_thumbnail_buffer_init( VipsThumbnailBuffer *buffer ) * * @linear: %gboolean, perform shrink in linear light * * @import_profile: %gchararray, fallback import ICC profile * * @export_profile: %gchararray, export ICC profile + * * @intent: #VipsIntent, rendering intent * * Exacty as vips_thumbnail(), but read from a memory buffer. * @@ -1031,6 +1051,7 @@ vips_thumbnail_image_init( VipsThumbnailImage *image ) * * @linear: %gboolean, perform shrink in linear light * * @import_profile: %gchararray, fallback import ICC profile * * @export_profile: %gchararray, export ICC profile + * * @intent: #VipsIntent, rendering intent * * Exacty as vips_thumbnail(), but read from an existing image. * diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index b41fc47e..b14b9972 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -92,6 +92,8 @@ * - support VipSize restrictions * 4/5/17 * - add ! geo modifier + * 30/8/17 + * - add --intent */ #ifdef HAVE_CONFIG_H @@ -125,6 +127,7 @@ static gboolean linear_processing = FALSE; static gboolean crop_image = FALSE; static char *smartcrop_image = NULL; static gboolean rotate_image = FALSE; +static char *thumbnail_intent = NULL; /* Deprecated and unused. */ @@ -162,6 +165,10 @@ static GOptionEntry options[] = { G_OPTION_ARG_STRING, &smartcrop_image, N_( "shrink and crop to fill SIZE using STRATEGY" ), N_( "STRATEGY" ) }, + { "intent", 'n', 0, + G_OPTION_ARG_STRING, &thumbnail_intent, + N_( "ICC transform with INTENT" ), + N_( "INTENT" ) }, { "rotate", 't', 0, G_OPTION_ARG_NONE, &rotate_image, N_( "auto-rotate" ), NULL }, @@ -245,18 +252,28 @@ thumbnail_process( VipsObject *process, const char *filename ) { VipsInteresting interesting; VipsImage *image; + VipsIntent intent; interesting = VIPS_INTERESTING_NONE; if( crop_image ) interesting = VIPS_INTERESTING_CENTRE; if( smartcrop_image ) { int n; - + if( (n = vips_enum_from_nick( "vipsthumbnail", VIPS_TYPE_INTERESTING, smartcrop_image )) < 0 ) return( -1 ); interesting = n; } + intent = VIPS_INTENT_RELATIVE; + if( thumbnail_intent ) { + int n; + + if( (n = vips_enum_from_nick( "vipsthumbnail", + VIPS_TYPE_INTENT, thumbnail_intent )) < 0 ) + return( -1 ); + intent = n; + } if( vips_thumbnail( filename, &image, thumbnail_width, "height", thumbnail_height, @@ -266,6 +283,7 @@ thumbnail_process( VipsObject *process, const char *filename ) "linear", linear_processing, "import_profile", import_profile, "export_profile", export_profile, + "intent", intent, NULL ) ) return( -1 );