From 2e3e8b2ef5d2e7d620b5414f8ac2236fd4c3c8dd Mon Sep 17 00:00:00 2001 From: Pascal Massimino Date: Tue, 17 Jan 2012 08:18:22 +0000 Subject: [PATCH] add a WebPCleanupTransparentArea() method to 'clean up' the fully-transparent area and make it more compressible new cwebp flags: -alpha_cleanup (off by default, since gain is not 100% guaranteed) Change-Id: I74d77e1915eee146584cd61c9c1132a41db922eb --- README | 15 +++++------ examples/cwebp.c | 12 +++++++++ man/cwebp.1 | 4 +++ src/enc/picture.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ src/webp/encode.h | 5 ++++ 5 files changed, 93 insertions(+), 8 deletions(-) diff --git a/README b/README index 828e0144..11676ff9 100644 --- a/README +++ b/README @@ -121,19 +121,21 @@ A longer list of options is available using the -longhelp command line flag: Usage: cwebp [-preset <...>] [options] in_file [-o out_file] -If input size (-s) for an image is not specified, it is assumed to be a either - PNG or JPEG format file. +If input size (-s) for an image is not specified, it is assumed to be a + PNG or JPEG file. options: -h / -help ............ short help -H / -longhelp ........ long help -q ............. quality factor (0:small..100:big) - -alpha_q ......... Transparency-compression quality (0..100) + -alpha_q ......... Transparency-compression quality (0..100). -preset ....... Preset setting, one of: default, photo, picture, drawing, icon, text -preset must come first, as it overwrites other parameters. -m ............... compression method (0=fast, 6=slowest) -segments ........ number of segments to use (1..4) + -size ............ Target size (in bytes) + -psnr .......... Target PSNR (in dB. typically: 42) -s ......... Input size (width x height) for YUV -sns ............. Spatial Noise Shaping (0:off, 100:max) @@ -143,7 +145,6 @@ options: -partition_limit . limit quality to fit the 512k limit on the first partition (0=no degradation ... 100=full) -pass ............ analysis pass number (1..10) - -partitions ...... number of partitions to use (0..3) -crop .. crop picture with the given rectangle -resize ........ resize picture (after any cropping) -map ............. print map of extra info. @@ -151,6 +152,7 @@ options: -alpha_method .... Transparency-compression method (0..1) -alpha_filter . predictive filtering for alpha plane. One of: none, fast (default) or best. + -alpha_cleanup ......... Clean RGB values in transparent area. -noalpha ............... discard any transparency information. -short ................. condense printed message @@ -160,11 +162,8 @@ options: -v ..................... verbose, e.g. print encoding/decoding times -progress .............. report encoding progress - Experimental Options: - -size ............ Target size (in bytes) - -psnr .......... Target PSNR (in dB. typically: 42) - -af .............. adjust filter strength (0=off, 1=on) + -af .................... auto-adjust filter strength. -pre ............. pre-processing filter diff --git a/examples/cwebp.c b/examples/cwebp.c index ebe52afe..d9067dc0 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -206,6 +206,11 @@ static HRESULT ReadPictureWithWIC(const char* filename, if (!ok) hr = E_FAIL; } + if (SUCCEEDED(hr)) { + if (has_alpha && keep_alpha == 2) { + WebPCleanupTransparentArea(pic); + } + } // Cleanup. if (pConverter != NULL) IUnknown_Release(pConverter); @@ -416,6 +421,10 @@ static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) { : WebPPictureImportRGB(pic, rgb, stride); free(rgb); + if (ok && has_alpha && keep_alpha == 2) { + WebPCleanupTransparentArea(pic); + } + End: return ok; } @@ -702,6 +711,7 @@ static void HelpLong(void) { printf(" -alpha_method .... Transparency-compression method (0..1)\n"); printf(" -alpha_filter . predictive filtering for alpha plane.\n"); printf(" One of: none, fast (default) or best.\n"); + printf(" -alpha_cleanup ......... Clean RGB values in transparent area.\n"); printf(" -noalpha ............... discard any transparency information.\n"); printf("\n"); @@ -795,6 +805,8 @@ int main(int argc, const char *argv[]) { config.alpha_quality = strtol(argv[++c], NULL, 0); } else if (!strcmp(argv[c], "-alpha_method") && c < argc - 1) { config.alpha_compression = strtol(argv[++c], NULL, 0); + } else if (!strcmp(argv[c], "-alpha_cleanup")) { + keep_alpha = keep_alpha ? 2 : 0; } else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) { ++c; if (!strcmp(argv[c], "none")) { diff --git a/man/cwebp.1 b/man/cwebp.1 index 3b306923..2192fd5f 100644 --- a/man/cwebp.1 +++ b/man/cwebp.1 @@ -155,6 +155,10 @@ Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes no compression, 1 uses uses backward reference counts encoded with arithmetic encoder. The default is 1. .TP +.B \-alpha_cleanup +Modify unseen RGB values under fully transparent area, to help compressibility. +The default is off. +.TP .B \-noalpha Using this option will discard the alpha channel. .TP diff --git a/src/enc/picture.c b/src/enc/picture.c index 700b88ec..a4312fb9 100644 --- a/src/enc/picture.c +++ b/src/enc/picture.c @@ -593,6 +593,71 @@ int WebPPictureImportBGRA(WebPPicture* const picture, return Import(picture, rgba, rgba_stride, 4, 1, 1); } +//------------------------------------------------------------------------------ +// Helper: clean up fully transparent area to help compressibility. + +#define SIZE 8 +#define SIZE2 (SIZE / 2) +static int is_transparent_area(const uint8_t* ptr, int stride, int size) { + int y, x; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (ptr[x]) { + return 0; + } + } + ptr += stride; + } + return 1; +} + +static WEBP_INLINE void flatten(uint8_t* ptr, int v, int stride, int size) { + int y; + for (y = 0; y < size; ++y) { + memset(ptr, v, size); + ptr += stride; + } +} + +void WebPCleanupTransparentArea(WebPPicture* const pic) { + int x, y, w, h; + const uint8_t* a_ptr; + int values[3] = { 0 }; + + if (pic == NULL) return; + + a_ptr = pic->a; + if (a_ptr == NULL) return; // nothing to do + + w = pic->width / SIZE; + h = pic->height / SIZE; + for (y = 0; y < h; ++y) { + int need_reset = 1; + for (x = 0; x < w; ++x) { + const int off_a = (y * pic->a_stride + x) * SIZE; + const int off_y = (y * pic->y_stride + x) * SIZE; + const int off_uv = (y * pic->uv_stride + x) * SIZE2; + if (is_transparent_area(a_ptr + off_a, pic->a_stride, SIZE)) { + if (need_reset) { + values[0] = pic->y[off_y]; + values[1] = pic->u[off_uv]; + values[2] = pic->v[off_uv]; + need_reset = 0; + } + flatten(pic->y + off_y, values[0], pic->y_stride, SIZE); + flatten(pic->u + off_uv, values[1], pic->uv_stride, SIZE2); + flatten(pic->v + off_uv, values[2], pic->uv_stride, SIZE2); + } else { + need_reset = 1; + } + } + // ignore the left-overs on right/bottom + } +} + +#undef SIZE +#undef SIZE2 + //------------------------------------------------------------------------------ // Simplest call: diff --git a/src/webp/encode.h b/src/webp/encode.h index 8f6c85b6..8dcac2f9 100644 --- a/src/webp/encode.h +++ b/src/webp/encode.h @@ -276,6 +276,11 @@ WEBP_EXTERN(int) WebPPictureImportBGR( WEBP_EXTERN(int) WebPPictureImportBGRA( WebPPicture* const picture, const uint8_t* const bgra, int bgra_stride); +// Helper function: given a width x height plane of YUV(A) samples +// (with stride 'stride'), clean-up the YUV samples under fully transparent +// area, to help compressibility (no guarantee, though). +WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* const picture); + //------------------------------------------------------------------------------ // Main call