cwebp: add -resize_mode

* `down_only`: downsample only if one of the input dimensions is larger
               than the target
* `up_only`: upsample only if one of the input dimensions is smaller
             than the target
* `always`: the original behavior

This change doesn't add related modes like area (@ in ImageMagick) or
minimum width/height (^ in ImageMagick). These can be added if a need
arises.

Bug: webp:405437935
Change-Id: I7752789dce6e3b9c3fb7d6edf63ca5559bb3463c
This commit is contained in:
James Zern 2025-04-10 13:05:30 -07:00
parent ad52d5fc7e
commit eb4f813761
3 changed files with 57 additions and 1 deletions

View File

@ -65,6 +65,7 @@ Options:
(default: 0 100) (default: 0 100)
-crop <x> <y> <w> <h> .. crop picture with the given rectangle -crop <x> <y> <w> <h> .. crop picture with the given rectangle
-resize <w> <h> ........ resize picture (*after* any cropping) -resize <w> <h> ........ resize picture (*after* any cropping)
-resize_mode <string> .. one of: up_only, down_only, always (default)
-mt .................... use multi-threading if available -mt .................... use multi-threading if available
-low_memory ............ reduce memory usage (slower encoding) -low_memory ............ reduce memory usage (slower encoding)
-map <int> ............. print map of extra info -map <int> ............. print map of extra info

View File

@ -515,6 +515,37 @@ static int WriteWebPWithMetadata(FILE* const out,
return (fwrite(webp, webp_size, 1, out) == 1); return (fwrite(webp, webp_size, 1, out) == 1);
} }
//------------------------------------------------------------------------------
// Resize
enum {
RESIZE_MODE_DOWN_ONLY,
RESIZE_MODE_UP_ONLY,
RESIZE_MODE_ALWAYS,
RESIZE_MODE_DEFAULT = RESIZE_MODE_ALWAYS
};
static void ApplyResizeMode(const int resize_mode,
const WebPPicture* const pic,
int* const resize_w, int* const resize_h) {
const int src_w = pic->width;
const int src_h = pic->height;
const int dst_w = *resize_w;
const int dst_h = *resize_h;
if (resize_mode == RESIZE_MODE_DOWN_ONLY) {
if ((dst_w == 0 && src_h <= dst_h) ||
(dst_h == 0 && src_w <= dst_w) ||
(src_w <= dst_w && src_h <= dst_h)) {
*resize_w = *resize_h = 0;
}
} else if (resize_mode == RESIZE_MODE_UP_ONLY) {
if (src_w >= dst_w && src_h >= dst_h) {
*resize_w = *resize_h = 0;
}
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static int ProgressReport(int percent, const WebPPicture* const picture) { static int ProgressReport(int percent, const WebPPicture* const picture) {
@ -583,6 +614,8 @@ static void HelpLong(void) {
" (default: 0 100)\n"); " (default: 0 100)\n");
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n"); printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
printf(" -resize <w> <h> ........ resize picture (*after* any cropping)\n"); printf(" -resize <w> <h> ........ resize picture (*after* any cropping)\n");
printf(" -resize_mode <string> .. one of: up_only, down_only,"
" always (default)\n");
printf(" -mt .................... use multi-threading if available\n"); printf(" -mt .................... use multi-threading if available\n");
printf(" -low_memory ............ reduce memory usage (slower encoding)\n"); printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
printf(" -map <int> ............. print map of extra info\n"); printf(" -map <int> ............. print map of extra info\n");
@ -670,6 +703,7 @@ int main(int argc, const char* argv[]) {
uint32_t background_color = 0xffffffu; uint32_t background_color = 0xffffffu;
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0; int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
int resize_w = 0, resize_h = 0; int resize_w = 0, resize_h = 0;
int resize_mode = RESIZE_MODE_DEFAULT;
int lossless_preset = 6; int lossless_preset = 6;
int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it
int show_progress = 0; int show_progress = 0;
@ -837,6 +871,18 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-resize") && c + 2 < argc) { } else if (!strcmp(argv[c], "-resize") && c + 2 < argc) {
resize_w = ExUtilGetInt(argv[++c], 0, &parse_error); resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
resize_h = ExUtilGetInt(argv[++c], 0, &parse_error); resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-resize_mode") && c + 1 < argc) {
++c;
if (!strcmp(argv[c], "down_only")) {
resize_mode = RESIZE_MODE_DOWN_ONLY;
} else if (!strcmp(argv[c], "up_only")) {
resize_mode = RESIZE_MODE_UP_ONLY;
} else if (!strcmp(argv[c], "always")) {
resize_mode = RESIZE_MODE_ALWAYS;
} else {
fprintf(stderr, "Error! Unrecognized resize mode: %s\n", argv[c]);
goto Error;
}
#ifndef WEBP_DLL #ifndef WEBP_DLL
} else if (!strcmp(argv[c], "-noasm")) { } else if (!strcmp(argv[c], "-noasm")) {
VP8GetCPUInfo = NULL; VP8GetCPUInfo = NULL;
@ -1057,6 +1103,7 @@ int main(int argc, const char* argv[]) {
goto Error; goto Error;
} }
} }
ApplyResizeMode(resize_mode, &picture, &resize_w, &resize_h);
if ((resize_w | resize_h) > 0) { if ((resize_w | resize_h) > 0) {
WebPPicture picture_no_alpha; WebPPicture picture_no_alpha;
if (config.exact) { if (config.exact) {

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "September 17, 2024" .TH CWEBP 1 "April 10, 2025"
.SH NAME .SH NAME
cwebp \- compress an image file to a WebP file cwebp \- compress an image file to a WebP file
.SH SYNOPSIS .SH SYNOPSIS
@ -102,6 +102,14 @@ If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
the value will be calculated preserving the aspect\-ratio. Note: scaling the value will be calculated preserving the aspect\-ratio. Note: scaling
is applied \fIafter\fP cropping. is applied \fIafter\fP cropping.
.TP .TP
.BI \-resize_mode " string
Specify the behavior of the \fB\-resize\fP option. Possible values are:
\fBdown_only\fP, \fBup_only\fP, \fBalways\fP (default). \fBdown_only\fP will
use the values specified by \fB\-resize\fP if \fIeither\fP the input width or
height are larger than the given dimensions. Similarly, \fBup_only\fP will only
resize if \fIeither\fP the input width or height are smaller than the given
dimensions.
.TP
.B \-mt .B \-mt
Use multi\-threading for encoding, if possible. Use multi\-threading for encoding, if possible.
.TP .TP