From 7489b0e72b962f7d3f2818cea385ef1b6bed57b6 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Thu, 30 Oct 2014 15:17:09 -0700 Subject: [PATCH] gif2webp: Add '-min-size' option to get best compression. This disables key-frame insertion and tries both dispose methods for each frame. Change-Id: Ib167747198fd1d98cb93321f76826e91228f24d8 --- examples/gif2webp.c | 9 ++++++++- examples/gif2webp_util.c | 15 +++++++++++++-- examples/gif2webp_util.h | 4 +++- man/gif2webp.1 | 6 ++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/examples/gif2webp.c b/examples/gif2webp.c index 1c43b9c8..d49de656 100644 --- a/examples/gif2webp.c +++ b/examples/gif2webp.c @@ -231,6 +231,10 @@ static void Help(void) { " or lossless compression heuristically\n"); printf(" -q ............. quality factor (0:small..100:big)\n"); printf(" -m ............... compression method (0=fast, 6=slowest)\n"); + printf(" -min_size .............. minimize output size (default:off)\n" + " lossless compression by default; can be\n" + " combined with -q, -m, -lossy or -mixed\n" + " options\n"); printf(" -kmin ............ min distance between key frames\n"); printf(" -kmax ............ max distance between key frames\n"); printf(" -f ............... filter strength (0=off..100)\n"); @@ -274,6 +278,7 @@ int main(int argc, const char *argv[]) { int stored_icc = 0; // Whether we have already stored an ICC profile. int stored_xmp = 0; + int minimize_size = 0; int default_kmin = 1; // Whether to use default kmin value. int default_kmax = 1; size_t kmin = 0; @@ -307,6 +312,8 @@ int main(int argc, const char *argv[]) { config.quality = ExUtilGetFloat(argv[++c], &parse_error); } else if (!strcmp(argv[c], "-m") && c < argc - 1) { config.method = ExUtilGetInt(argv[++c], 0, &parse_error); + } else if (!strcmp(argv[c], "-min_size")) { + minimize_size = 1; } else if (!strcmp(argv[c], "-kmax") && c < argc - 1) { kmax = ExUtilGetUInt(argv[++c], 0, &parse_error); default_kmax = 0; @@ -466,7 +473,7 @@ int main(int argc, const char *argv[]) { WebPUtilClearPic(&frame, NULL); // Initialize cache. - cache = WebPFrameCacheNew(frame.width, frame.height, + cache = WebPFrameCacheNew(frame.width, frame.height, minimize_size, kmin, kmax, allow_mixed); if (cache == NULL) goto End; diff --git a/examples/gif2webp_util.c b/examples/gif2webp_util.c index 6c3666af..6c2e3952 100644 --- a/examples/gif2webp_util.c +++ b/examples/gif2webp_util.c @@ -287,6 +287,9 @@ struct WebPFrameCache { // transparent pixels in a frame. int keyframe; // Index of selected keyframe relative to 'start'. + // TODO(urvang): Create a struct WebPAnimationEncodingConfig for these + // encoding parameters. + int min_size; // If true, produce the smallest output. size_t kmin; // Min distance between key frames. size_t kmax; // Max distance between key frames. size_t count_since_key_frame; // Frames seen since the last key frame. @@ -319,7 +322,7 @@ static void CacheReset(WebPFrameCache* const cache) { cache->keyframe = KEYFRAME_NONE; } -WebPFrameCache* WebPFrameCacheNew(int width, int height, +WebPFrameCache* WebPFrameCacheNew(int width, int height, int minimize_size, size_t kmin, size_t kmax, int allow_mixed) { WebPFrameCache* cache = (WebPFrameCache*)WebPSafeCalloc(1, sizeof(*cache)); if (cache == NULL) return NULL; @@ -354,7 +357,12 @@ WebPFrameCache* WebPFrameCacheNew(int width, int height, WebPUtilClearPic(&cache->prev_to_prev_canvas_disposed, NULL); // Cache data. + cache->min_size = minimize_size; cache->allow_mixed = allow_mixed; + if (cache->min_size) { // Disable keyframe insertion. + kmax = ~0; + kmin = kmax - 1; + } cache->kmin = kmin; cache->kmax = kmax; cache->count_since_key_frame = 0; @@ -790,7 +798,10 @@ static WebPEncodingError SetFrame(WebPFrameCache* const cache, GetSubRect(prev_canvas_disposed, curr_canvas, orig_rect, is_key_frame, &rect_bg, &sub_frame_bg); - if (RectArea(&rect_bg) < RectArea(&rect_none)) { + if (cache->min_size) { // Try both dispose methods. + try_dispose_bg = 1; + try_dispose_none = 1; + } else if (RectArea(&rect_bg) < RectArea(&rect_none)) { try_dispose_bg = 1; // Pick DISPOSE_BACKGROUND. try_dispose_none = 0; } diff --git a/examples/gif2webp_util.h b/examples/gif2webp_util.h index 522a3fe7..c152eed4 100644 --- a/examples/gif2webp_util.h +++ b/examples/gif2webp_util.h @@ -51,10 +51,12 @@ typedef struct WebPFrameCache WebPFrameCache; // Given the minimum distance between key frames 'kmin' and maximum distance // between key frames 'kmax', returns an appropriately allocated cache object. +// If 'minimize_size' is true, optimizes for file size. This also implies that +// keyframe addition is off. // If 'allow_mixed' is true, the subsequent calls to WebPFrameCacheAddFrame() // will heuristically pick lossy or lossless compression for each frame. // Use WebPFrameCacheDelete() to deallocate the 'cache'. -WebPFrameCache* WebPFrameCacheNew(int width, int height, +WebPFrameCache* WebPFrameCacheNew(int width, int height, int minimize_size, size_t kmin, size_t kmax, int allow_mixed); // Release all the frame data from 'cache' and free 'cache'. diff --git a/man/gif2webp.1 b/man/gif2webp.1 index d41b423a..ccc61726 100644 --- a/man/gif2webp.1 +++ b/man/gif2webp.1 @@ -54,6 +54,12 @@ additional encoding possibilities and decide on the quality gain. Lower value can result is faster processing time at the expense of larger file size and lower compression quality. .TP +.BI \-min_size +Encode image to achieve smallest size. This disables key frame insertion and +picks the dispose method resulting in smallest output for each frame. It uses +lossless compression by default, but can be combined with \-q, \-m, \-lossy or +\-mixed options. +.TP .BI \-kmin " int .TP .BI \-kmax " int