From 005360dba7f172311ff253a0c98f9e7c2236fdc8 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 29 Mar 2021 12:41:02 +0100 Subject: [PATCH] add support for lcms black point compensation Add a --black-point-compensation flag. See https://github.com/libvips/libvips/discussions/2169 --- ChangeLog | 1 + libvips/colour/icc_transform.c | 56 ++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 67264ff7..87e0fbb3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ - add vips_image_[set|get]_array_double() - add GIF load with libnsgif - add JPEG2000 load and save +- add black_point_compensation flag for icc transforms 22/12/20 start 8.10.6 - don't seek on bad file descriptors [kleisauke] diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index 1caa8a58..6fe7658a 100644 --- a/libvips/colour/icc_transform.c +++ b/libvips/colour/icc_transform.c @@ -43,6 +43,8 @@ * they can be triggered under normal circumstances * 17/4/19 kleisauke * - better rejection of broken embedded profiles + * 29/3/21 [hanssonrickard] + * - add black_point_compensation */ /* @@ -152,6 +154,7 @@ typedef struct _VipsIcc { VipsIntent intent; VipsPCS pcs; int depth; + gboolean black_point_compensation; VipsBlob *in_blob; cmsHPROFILE in_profile; @@ -215,6 +218,8 @@ vips_icc_build( VipsObject *object ) VipsColourCode *code = (VipsColourCode *) object; VipsIcc *icc = (VipsIcc *) object; + cmsUInt32Number flags; + if( icc->depth != 8 && icc->depth != 16 ) { vips_error( class->nickname, @@ -353,10 +358,15 @@ vips_icc_build( VipsObject *object ) /* Use cmsFLAGS_NOCACHE to disable the 1-pixel cache and make * calling cmsDoTransform() from multiple threads safe. */ + flags = cmsFLAGS_NOCACHE; + + if( icc->black_point_compensation ) + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + if( !(icc->trans = cmsCreateTransform( icc->in_profile, icc->in_icc_format, icc->out_profile, icc->out_icc_format, - icc->intent, cmsFLAGS_NOCACHE )) ) + icc->intent, flags )) ) return( -1 ); if( VIPS_OBJECT_CLASS( vips_icc_parent_class )-> @@ -394,6 +404,13 @@ vips_icc_class_init( VipsIccClass *class ) G_STRUCT_OFFSET( VipsIcc, pcs ), VIPS_TYPE_PCS, VIPS_PCS_LAB ); + VIPS_ARG_BOOL( class, "black_point_compensation", 7, + _( "Black point compensation" ), + _( "Enable black point compensation" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsIcc, black_point_compensation ), + FALSE ); + cmsSetLogErrorHandler( icc_error ); } @@ -1345,10 +1362,11 @@ vips_icc_is_compatible_profile( VipsImage *image, * * Optional arguments: * - * * @input_profile: get the input profile from here - * * @intent: transform with this intent - * * @embedded: use profile embedded in input image - * * @pcs: use XYZ or LAB PCS + * * @pcs: #VipsPCS, use XYZ or LAB PCS + * * @intent: #VipsIntent, transform with this intent + * * @black_point_compensation: %gboolean, enable black point compensation + * * @embedded: %gboolean, use profile embedded in input image + * * @input_profile: %gchararray, get the input profile from here * * Import an image from device space to D65 LAB with an ICC profile. If @pcs is * set to #VIPS_PCS_XYZ, use CIE XYZ PCS instead. @@ -1365,6 +1383,9 @@ vips_icc_is_compatible_profile( VipsImage *image, * @input_profile. If @input_profile is not supplied, the * metadata profile, if any, is used as a fall-back. * + * If @black_point_compensation is set, LCMS black point compensation is + * enabled. + * * Returns: 0 on success, -1 on error. */ int @@ -1388,10 +1409,11 @@ vips_icc_import( VipsImage *in, VipsImage **out, ... ) * * Optional arguments: * - * * @intent: transform with this intent - * * @depth: depth of output image in bits - * * @output_profile: get the output profile from here - * * @pcs: use XYZ or LAB PCS + * * @pcs: #VipsPCS, use XYZ or LAB PCS + * * @intent: #VipsIntent, transform with this intent + * * @black_point_compensation: %gboolean, enable black point compensation + * * @output_profile: %gchararray, get the output profile from here + * * @depth: %gint, depth of output image in bits * * Export an image from D65 LAB to device space with an ICC profile. * If @pcs is @@ -1400,6 +1422,9 @@ vips_icc_import( VipsImage *in, VipsImage **out, ... ) * If @output_profile is set, export with that and attach it to the output * image. * + * If @black_point_compensation is set, LCMS black point compensation is + * enabled. + * * Returns: 0 on success, -1 on error. */ int @@ -1424,10 +1449,12 @@ vips_icc_export( VipsImage *in, VipsImage **out, ... ) * * Optional arguments: * - * * @input_profile: get the input profile from here - * * @intent: transform with this intent - * * @depth: depth of output image in bits - * * @embedded: use profile embedded in input image + * * @pcs: #VipsPCS, use XYZ or LAB PCS + * * @intent: #VipsIntent, transform with this intent + * * @black_point_compensation: %gboolean, enable black point compensation + * * @embedded: %gboolean, use profile embedded in input image + * * @input_profile: %gchararray, get the input profile from here + * * @depth: %gint, depth of output image in bits * * Transform an image with a pair of ICC profiles. The input image is moved to * profile-connection space with the input profile and then to the output @@ -1445,6 +1472,9 @@ vips_icc_export( VipsImage *in, VipsImage **out, ... ) * @input_profile. If @input_profile is not supplied, the * metadata profile, if any, is used as a fall-back. * + * If @black_point_compensation is set, LCMS black point compensation is + * enabled. + * * The output image has the output profile attached to the #VIPS_META_ICC_NAME * field. *