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
This commit is contained in:
Urvang Joshi 2014-10-30 15:17:09 -07:00
parent 77bdddf016
commit 7489b0e72b
4 changed files with 30 additions and 4 deletions

View File

@ -231,6 +231,10 @@ static void Help(void) {
" or lossless compression heuristically\n"); " or lossless compression heuristically\n");
printf(" -q <float> ............. quality factor (0:small..100:big)\n"); printf(" -q <float> ............. quality factor (0:small..100:big)\n");
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n"); printf(" -m <int> ............... 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 <int> ............ min distance between key frames\n"); printf(" -kmin <int> ............ min distance between key frames\n");
printf(" -kmax <int> ............ max distance between key frames\n"); printf(" -kmax <int> ............ max distance between key frames\n");
printf(" -f <int> ............... filter strength (0=off..100)\n"); printf(" -f <int> ............... 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_icc = 0; // Whether we have already stored an ICC profile.
int stored_xmp = 0; int stored_xmp = 0;
int minimize_size = 0;
int default_kmin = 1; // Whether to use default kmin value. int default_kmin = 1; // Whether to use default kmin value.
int default_kmax = 1; int default_kmax = 1;
size_t kmin = 0; size_t kmin = 0;
@ -307,6 +312,8 @@ int main(int argc, const char *argv[]) {
config.quality = ExUtilGetFloat(argv[++c], &parse_error); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = ExUtilGetInt(argv[++c], 0, &parse_error); 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) { } else if (!strcmp(argv[c], "-kmax") && c < argc - 1) {
kmax = ExUtilGetUInt(argv[++c], 0, &parse_error); kmax = ExUtilGetUInt(argv[++c], 0, &parse_error);
default_kmax = 0; default_kmax = 0;
@ -466,7 +473,7 @@ int main(int argc, const char *argv[]) {
WebPUtilClearPic(&frame, NULL); WebPUtilClearPic(&frame, NULL);
// Initialize cache. // Initialize cache.
cache = WebPFrameCacheNew(frame.width, frame.height, cache = WebPFrameCacheNew(frame.width, frame.height, minimize_size,
kmin, kmax, allow_mixed); kmin, kmax, allow_mixed);
if (cache == NULL) goto End; if (cache == NULL) goto End;

View File

@ -287,6 +287,9 @@ struct WebPFrameCache {
// transparent pixels in a frame. // transparent pixels in a frame.
int keyframe; // Index of selected keyframe relative to 'start'. 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 kmin; // Min distance between key frames.
size_t kmax; // Max 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. 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; 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) { size_t kmin, size_t kmax, int allow_mixed) {
WebPFrameCache* cache = (WebPFrameCache*)WebPSafeCalloc(1, sizeof(*cache)); WebPFrameCache* cache = (WebPFrameCache*)WebPSafeCalloc(1, sizeof(*cache));
if (cache == NULL) return NULL; if (cache == NULL) return NULL;
@ -354,7 +357,12 @@ WebPFrameCache* WebPFrameCacheNew(int width, int height,
WebPUtilClearPic(&cache->prev_to_prev_canvas_disposed, NULL); WebPUtilClearPic(&cache->prev_to_prev_canvas_disposed, NULL);
// Cache data. // Cache data.
cache->min_size = minimize_size;
cache->allow_mixed = allow_mixed; cache->allow_mixed = allow_mixed;
if (cache->min_size) { // Disable keyframe insertion.
kmax = ~0;
kmin = kmax - 1;
}
cache->kmin = kmin; cache->kmin = kmin;
cache->kmax = kmax; cache->kmax = kmax;
cache->count_since_key_frame = 0; 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, GetSubRect(prev_canvas_disposed, curr_canvas, orig_rect, is_key_frame,
&rect_bg, &sub_frame_bg); &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_bg = 1; // Pick DISPOSE_BACKGROUND.
try_dispose_none = 0; try_dispose_none = 0;
} }

View File

@ -51,10 +51,12 @@ typedef struct WebPFrameCache WebPFrameCache;
// Given the minimum distance between key frames 'kmin' and maximum distance // Given the minimum distance between key frames 'kmin' and maximum distance
// between key frames 'kmax', returns an appropriately allocated cache object. // 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() // If 'allow_mixed' is true, the subsequent calls to WebPFrameCacheAddFrame()
// will heuristically pick lossy or lossless compression for each frame. // will heuristically pick lossy or lossless compression for each frame.
// Use WebPFrameCacheDelete() to deallocate the 'cache'. // 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); size_t kmin, size_t kmax, int allow_mixed);
// Release all the frame data from 'cache' and free 'cache'. // Release all the frame data from 'cache' and free 'cache'.

View File

@ -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 Lower value can result is faster processing time at the expense of
larger file size and lower compression quality. larger file size and lower compression quality.
.TP .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 .BI \-kmin " int
.TP .TP
.BI \-kmax " int .BI \-kmax " int