diff --git a/ChangeLog b/ChangeLog index b3b2d6533e..e906a300d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,8 @@ master - share and reuse openslide connections - drop support for openslide 3.3 - fix vips_quadratic() +- rename `thumbnail`'s export/import profile options as input/output for + consistency - restore vips_remosaic(), it was not being linked 8.16.1 diff --git a/doc/using-vipsthumbnail.md b/doc/using-vipsthumbnail.md index a5eb645e4a..d5e111e6b8 100644 --- a/doc/using-vipsthumbnail.md +++ b/doc/using-vipsthumbnail.md @@ -275,7 +275,7 @@ Now transform to sRGB and don't attach a profile (you can also use `keep=none`, though that will remove *all* metadata from the image): ```bash -$ vipsthumbnail shark.jpg --export-profile srgb -o tn_shark.jpg[profile=none] +$ vipsthumbnail shark.jpg --output-profile srgb -o tn_shark.jpg[profile=none] $ ls -l tn_shark.jpg -rw-r–r– 1 john john 4229 Nov  9 14:33 tn_shark.jpg ``` @@ -291,7 +291,7 @@ space, even though it has no embedded profile. ```bash -$ vipsthumbnail kgdev.jpg --import-profile /my/profiles/a98.icm +$ vipsthumbnail kgdev.jpg --input-profile /my/profiles/a98.icm ``` ## Final suggestion @@ -301,6 +301,6 @@ Putting all this together, I suggest this as a sensible set of options: ```bash $ vipsthumbnail fred.jpg \ --size 128 \ - --export-profile srgb \ + --output-profile srgb \ -o tn_%s.jpg[optimize_coding,keep=none] ``` diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index 63cb706485..f7b1f73c1b 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -116,8 +116,8 @@ typedef struct _VipsThumbnail { gboolean no_rotate; VipsInteresting crop; gboolean linear; - char *export_profile; - char *import_profile; + char *output_profile; + char *input_profile; VipsIntent intent; VipsFailOn fail_on; @@ -695,8 +695,8 @@ vips_thumbnail_build(VipsObject *object) */ preshrunk_page_height = vips_image_get_page_height(in); - needs_icc_transform = thumbnail->export_profile && - (thumbnail->import_profile || + needs_icc_transform = thumbnail->output_profile && + (thumbnail->input_profile || vips_image_get_typeof(in, VIPS_META_ICC_NAME)); /* RAD needs special unpacking. @@ -716,20 +716,20 @@ vips_thumbnail_build(VipsObject *object) */ have_imported = FALSE; if (thumbnail->linear) { - /* If we are doing colour management (there's an import + /* If we are doing colour management (there's an input * profile), then we can use XYZ PCS as the resize space. */ if (in->Coding == VIPS_CODING_NONE && (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) && (vips_image_get_typeof(in, VIPS_META_ICC_NAME) || - thumbnail->import_profile)) { + thumbnail->input_profile)) { g_info("importing to XYZ PCS"); - if (thumbnail->import_profile) - g_info("fallback input profile %s", thumbnail->import_profile); + if (thumbnail->input_profile) + g_info("fallback input profile %s", thumbnail->input_profile); if (vips_icc_import(in, &t[2], - "input_profile", thumbnail->import_profile, + "input_profile", thumbnail->input_profile, "embedded", TRUE, "intent", thumbnail->intent, "pcs", VIPS_PCS_XYZ, @@ -844,11 +844,11 @@ vips_thumbnail_build(VipsObject *object) if (have_imported) { /* We are in PCS. Export with the output profile, if any (this * will export with the embedded input profile if there's no - * export profile). + * output profile). */ g_info("exporting to device space with a profile"); if (vips_icc_export(in, &t[9], - "output_profile", thumbnail->export_profile, + "output_profile", thumbnail->output_profile, "intent", thumbnail->intent, "depth", 8, NULL)) @@ -859,8 +859,8 @@ vips_thumbnail_build(VipsObject *object) /* We can transform to the output with a pair of ICC profiles. */ g_info("transforming with supplied profiles"); - if (vips_icc_transform(in, &t[9], thumbnail->export_profile, - "input_profile", thumbnail->import_profile, + if (vips_icc_transform(in, &t[9], thumbnail->output_profile, + "input_profile", thumbnail->input_profile, "intent", thumbnail->intent, "embedded", TRUE, "depth", 8, @@ -869,14 +869,14 @@ vips_thumbnail_build(VipsObject *object) in = t[9]; } - else if (thumbnail->export_profile) { + else if (thumbnail->output_profile) { /* We are in one of the resize space (sRGB, scRGB, B_W, GREY16, etc.) * and need to go to PCS, then export. */ - g_info("exporting with %s", thumbnail->export_profile); + g_info("exporting with %s", thumbnail->output_profile); if (vips_colourspace(in, &t[9], VIPS_INTERPRETATION_XYZ, NULL) || vips_icc_export(t[9], &t[10], - "output_profile", thumbnail->export_profile, + "output_profile", thumbnail->output_profile, "intent", thumbnail->intent, "depth", 8, NULL)) @@ -885,7 +885,7 @@ vips_thumbnail_build(VipsObject *object) } else if (thumbnail->linear) { /* We are in one of the scRGB or GREY16 spaces and there's - * no export profile. Output to sRGB or B_W. + * no output profile. Output to sRGB or B_W. */ VipsInterpretation interpretation; @@ -1012,18 +1012,18 @@ vips_thumbnail_class_init(VipsThumbnailClass *class) G_STRUCT_OFFSET(VipsThumbnail, linear), FALSE); - VIPS_ARG_STRING(class, "import_profile", 118, - _("Import profile"), - _("Fallback import profile"), + VIPS_ARG_STRING(class, "input_profile", 118, + _("Input profile"), + _("Fallback input profile"), VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET(VipsThumbnail, import_profile), + G_STRUCT_OFFSET(VipsThumbnail, input_profile), NULL); - VIPS_ARG_STRING(class, "export_profile", 119, - _("Export profile"), - _("Fallback export profile"), + VIPS_ARG_STRING(class, "output_profile", 119, + _("Output profile"), + _("Fallback output profile"), VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET(VipsThumbnail, export_profile), + G_STRUCT_OFFSET(VipsThumbnail, output_profile), NULL); VIPS_ARG_ENUM(class, "intent", 120, @@ -1046,12 +1046,30 @@ vips_thumbnail_class_init(VipsThumbnailClass *class) * This is now replaced (though still functional) with "no-rotate", * see above. */ - VIPS_ARG_BOOL(class, "auto_rotate", 121, + VIPS_ARG_BOOL(class, "auto_rotate", 130, _("Auto rotate"), _("Use orientation tags to rotate image upright"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsThumbnail, auto_rotate), TRUE); + + /* Renamed as input-profile and output-profile for consistency with the + * rest of the API. + */ + + VIPS_ARG_STRING(class, "import_profile", 131, + _("Import profile"), + _("Fallback import profile"), + VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, + G_STRUCT_OFFSET(VipsThumbnail, input_profile), + NULL); + + VIPS_ARG_STRING(class, "export_profile", 132, + _("Export profile"), + _("Fallback export profile"), + VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, + G_STRUCT_OFFSET(VipsThumbnail, output_profile), + NULL); } static void @@ -1217,7 +1235,7 @@ vips_thumbnail_file_init(VipsThumbnailFile *file) * 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 + * shrink-on-load features available in the image load library, using a block * shrink, and using a lanczos3 shrink. At least the final 200% is done with * lanczos3. The output should be high quality, and the operation should be * quick. @@ -1256,9 +1274,9 @@ vips_thumbnail_file_init(VipsThumbnailFile *file) * also be far slower, since tricks like JPEG shrink-on-load cannot be used in * linear space. * - * If you set @export_profile to the filename of an ICC profile, the image + * If you set @output_profile to the filename of an ICC profile, the image * will be transformed to the target colourspace before writing to the - * output. You can also give an @import_profile which will be used if the + * output. You can also give an @input_profile which will be used if the * input image has no ICC profile, or if the profile embedded in the * input image is broken. * @@ -1274,8 +1292,8 @@ vips_thumbnail_file_init(VipsThumbnailFile *file) * * @no_rotate: %gboolean, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: %gboolean, perform shrink in linear light - * * @import_profile: %gchararray, fallback import ICC profile - * * @export_profile: %gchararray, export ICC profile + * * @input_profile: %gchararray, fallback input ICC profile + * * @output_profile: %gchararray, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * @@ -1482,8 +1500,8 @@ vips_thumbnail_buffer_init(VipsThumbnailBuffer *buffer) * * @no_rotate: %gboolean, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: %gboolean, perform shrink in linear light - * * @import_profile: %gchararray, fallback import ICC profile - * * @export_profile: %gchararray, export ICC profile + * * @input_profile: %gchararray, fallback input ICC profile + * * @output_profile: %gchararray, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * @option_string: %gchararray, extra loader options @@ -1696,8 +1714,8 @@ vips_thumbnail_source_init(VipsThumbnailSource *source) * * @no_rotate: %gboolean, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: %gboolean, perform shrink in linear light - * * @import_profile: %gchararray, fallback import ICC profile - * * @export_profile: %gchararray, export ICC profile + * * @input_profile: %gchararray, fallback input ICC profile + * * @output_profile: %gchararray, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * @option_string: %gchararray, extra loader options @@ -1815,8 +1833,8 @@ vips_thumbnail_image_init(VipsThumbnailImage *image) * * @no_rotate: %gboolean, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: %gboolean, perform shrink in linear light - * * @import_profile: %gchararray, fallback import ICC profile - * * @export_profile: %gchararray, export ICC profile + * * @input_profile: %gchararray, fallback input ICC profile + * * @output_profile: %gchararray, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * diff --git a/man/vipsthumbnail.1 b/man/vipsthumbnail.1 index b14ac4f2fd..d42942018c 100644 --- a/man/vipsthumbnail.1 +++ b/man/vipsthumbnail.1 @@ -5,7 +5,7 @@ vipsthumbnail \- make thumbnails of image files .B vipsthumbnail [flags] imagefile1 imagefile2 ... .SH DESCRIPTION .B vipsthumbnail(1) -processes each +processes each .B imagefile in turn, shrinking each image to fit within a 128 by 128 pixel square. The shrunk image is written to a new file named @@ -17,9 +17,9 @@ For example: $ vipsthumbnail fred.png jim.tif -will read image files +will read image files .B fred.png -and +and .B jim.tif and write thumbnails to the files .B tn_fred.jpg @@ -30,36 +30,36 @@ and will read image file .B fred.jpg -and write a 64 x 64 pixel thumbnail to the file +and write a 64 x 64 pixel thumbnail to the file .B thumbnails/fred.png. .SH OPTIONS .TP .B -s N, --size=N -Set the output thumbnail size to -.B N -x -.B N -pixels. +Set the output thumbnail size to +.B N +x +.B N +pixels. You can use "MxN" to specify a rectangular bounding box. The image is shrunk so that it just fits within this area, images -which are smaller than this are expanded. +which are smaller than this are expanded. Use "xN" or "Mx" to just resize on -one axis. +one axis. Append "<" to only resize if the input image is smaller than the target, append ">" to only resize if the input image is larger than the target. .TP -.B -o FORMAT, --output=FORMAT +.B -o FORMAT, --output=FORMAT Set the output format string. The input filename has any file type suffix -removed, then that value is substituted into +removed, then that value is substituted into .B FORMAT replacing -.B %s. -If +.B %s. +If .B FORMAT is a relative path, the name of the input directory is prepended. In other words, any path in @@ -75,7 +75,7 @@ prepended. You can add format options too, for example will write JPEG images with Q set to 20. .TP -.B -e PROFILE, --eprofile=PROFILE +.B -e PROFILE, --eprofile=PROFILE Export thumbnails with this ICC profile. Images are only colour-transformed if there is both an output and an input profile available. The input profile can either be embedded in the input image or supplied with the @@ -83,8 +83,8 @@ either be embedded in the input image or supplied with the option. .TP -.B -i PROFILE, --iprofile=PROFILE -Import images with this ICC profile, if no profile is embedded in the image. +.B -i PROFILE, --iprofile=PROFILE +Import images with this ICC profile, if no profile is embedded in the image. Images are only colour-transformed if there is both an output and an input profile available. The output profile should be supplied with the @@ -94,20 +94,20 @@ option. .TP .B -c, --crop Crop the output image down. The image is shrunk so as to completely fill the -bounding box in both axes, then any excess is cropped off. +bounding box in both axes, then any excess is cropped off. .TP .B -d, --delete Delete the output profile from the image. This can save a small amount of -space. +space. .TP .B -t, --rotate -Auto-rotate images using EXIF orientation tags. +Auto-rotate images using EXIF orientation tags. .TP .B -a, --linear -Shrink images in linear light colour space. This can be much slower. +Shrink images in linear light colour space. This can be much slower. .SH RETURN VALUE returns 0 on success and non-zero on error. Error can mean one or more diff --git a/test/test-suite/test_resample.py b/test/test-suite/test_resample.py index 6fd5c18c15..6ac8704477 100644 --- a/test/test-suite/test_resample.py +++ b/test/test-suite/test_resample.py @@ -241,7 +241,7 @@ def test_thumbnail(self): @pytest.mark.skipif(not pyvips.at_least_libvips(8, 5), reason="requires libvips >= 8.5") def test_thumbnail_icc(self): - im = pyvips.Image.thumbnail(JPEG_FILE_XYB, 442, export_profile="srgb") + im = pyvips.Image.thumbnail(JPEG_FILE_XYB, 442, output_profile="srgb") assert im.width == 290 assert im.height == 442 diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index 3ff8c38a2f..852cde250c 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -105,6 +105,8 @@ * 2/10/20 * - support "stdin" as a magic input filename for thumbnail_source * - support ".suffix" as a magic output format for stdout write + * 30/4/25 + * - rename import/export profile args as input/oputput */ #ifdef HAVE_CONFIG_H @@ -131,8 +133,8 @@ static int thumbnail_width = 128; static int thumbnail_height = 128; static VipsSize size_restriction = VIPS_SIZE_BOTH; static char *output_format = "tn_%s.jpg"; -static char *export_profile = NULL; -static char *import_profile = NULL; +static char *output_profile = NULL; +static char *input_profile = NULL; static gboolean linear_processing = FALSE; static gboolean crop_image = FALSE; static gboolean no_rotate_image = FALSE; @@ -159,12 +161,12 @@ static GOptionEntry options[] = { G_OPTION_ARG_STRING, &output_format, N_("output to FORMAT"), N_("FORMAT") }, - { "export-profile", 'e', 0, - G_OPTION_ARG_FILENAME, &export_profile, + { "output-profile", 0, 0, + G_OPTION_ARG_FILENAME, &output_profile, N_("export with PROFILE"), N_("PROFILE") }, - { "import-profile", 'i', 0, - G_OPTION_ARG_FILENAME, &import_profile, + { "input-profile", 0, 0, + G_OPTION_ARG_FILENAME, &input_profile, N_("import untagged images with PROFILE"), N_("PROFILE") }, { "linear", 'a', 0, @@ -187,18 +189,28 @@ static GOptionEntry options[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, N_("print version"), NULL }, - { "format", 'f', G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_STRING, &output_format, - N_("set output format string to FORMAT"), - N_("FORMAT") }, + /* All deprecated. + */ + { "export-profile", 'e', G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_FILENAME, &output_profile, + N_("export with PROFILE"), + N_("PROFILE") }, + { "import-profile", 'i', G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_FILENAME, &input_profile, + N_("import untagged images with PROFILE"), + N_("PROFILE") }, { "eprofile", 0, G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_FILENAME, &export_profile, + G_OPTION_ARG_FILENAME, &output_profile, N_("export with PROFILE"), N_("PROFILE") }, { "iprofile", 0, G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_FILENAME, &import_profile, + G_OPTION_ARG_FILENAME, &input_profile, N_("import untagged images with PROFILE"), N_("PROFILE") }, + { "format", 'f', G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_STRING, &output_format, + N_("set output format string to FORMAT"), + N_("FORMAT") }, { "rotate", 't', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &rotate_image, N_("(deprecated, does nothing)"), NULL }, @@ -321,8 +333,8 @@ thumbnail_process(VipsObject *process, const char *name) "no-rotate", no_rotate_image, "crop", interesting, "linear", linear_processing, - "import-profile", import_profile, - "export-profile", export_profile, + "import-profile", input_profile, + "output-profile", output_profile, "intent", intent, NULL)) { VIPS_UNREF(source); @@ -337,8 +349,8 @@ thumbnail_process(VipsObject *process, const char *name) "no-rotate", no_rotate_image, "crop", interesting, "linear", linear_processing, - "import-profile", import_profile, - "export-profile", export_profile, + "import-profile", input_profile, + "output-profile", output_profile, "intent", intent, NULL)) return -1;