From 252028aaacd4342bfe225b3dcb7e3be823f55e66 Mon Sep 17 00:00:00 2001 From: Vikas Arora Date: Thu, 5 Jan 2012 13:04:30 +0530 Subject: [PATCH] Add predictive filtering option for Alpha. Add predictive filtering option for Alpha plane. Valid range for filter option is [0, 5] corresponding to prediction methods none, horizontal, vertical, gradient & paeth filter. The prediction method 5 will try all the prediction methods (0 to 4) and pick the prediction method that gives best compression. Change-Id: I9244d4a9c5017501a9696c7cec5045f04c16d49b --- Android.mk | 1 + Makefile.vc | 1 + examples/cwebp.c | 3 + makefile.unix | 5 +- man/cwebp.1 | 6 + src/enc/alpha.c | 2 +- src/enc/config.c | 3 + src/utils/Makefile.am | 1 + src/utils/alpha.c | 99 ++++++++++++---- src/utils/alpha.h | 11 +- src/utils/filters.c | 267 ++++++++++++++++++++++++++++++++++++++++++ src/utils/filters.h | 50 ++++++++ src/webp/encode.h | 3 + 13 files changed, 424 insertions(+), 28 deletions(-) create mode 100644 src/utils/filters.c create mode 100644 src/utils/filters.h diff --git a/Android.mk b/Android.mk index 4e90eb09..2c984566 100644 --- a/Android.mk +++ b/Android.mk @@ -34,6 +34,7 @@ LOCAL_SRC_FILES := \ src/utils/alpha.c \ src/utils/bit_reader.c \ src/utils/bit_writer.c \ + src/utils/filters.c \ src/utils/quant_levels.c \ src/utils/tcoder.c \ src/utils/thread.c \ diff --git a/Makefile.vc b/Makefile.vc index 76ea1424..f54dc58e 100644 --- a/Makefile.vc +++ b/Makefile.vc @@ -178,6 +178,7 @@ X_OBJS= \ $(DIROBJ)\utils\alpha.obj \ $(DIROBJ)\utils\bit_reader.obj \ $(DIROBJ)\utils\bit_writer.obj \ + $(DIROBJ)\utils\filters.obj \ $(DIROBJ)\utils\quant_levels.obj \ $(DIROBJ)\utils\tcoder.obj \ $(DIROBJ)\utils\thread.obj \ diff --git a/examples/cwebp.c b/examples/cwebp.c index 572a3149..20b19205 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -700,6 +700,7 @@ static void HelpLong(void) { printf(" -map ............. print map of extra info.\n"); printf(" -d .......... dump the compressed output (PGM file).\n"); printf(" -alpha_method .... Transparency-compression method (0..1)\n"); + printf(" -alpha_filter .... predictive filtering for Alpha (0..5)\n"); printf(" -noalpha ............... discard any transparency information.\n"); printf("\n"); @@ -793,6 +794,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_filter") && c < argc - 1) { + config.alpha_filtering = strtol(argv[++c], NULL, 0); } else if (!strcmp(argv[c], "-noalpha")) { keep_alpha = 0; } else if (!strcmp(argv[c], "-size") && c < argc - 1) { diff --git a/makefile.unix b/makefile.unix index 104c89f0..b0399b59 100644 --- a/makefile.unix +++ b/makefile.unix @@ -71,7 +71,8 @@ DSP_OBJS = src/dsp/cpu.o src/dsp/enc.o \ src/dsp/dec_neon.o src/dsp/upsampling.o src/dsp/upsampling_sse2.o \ src/dsp/yuv.o UTILS_OBJS = src/utils/alpha.o src/utils/bit_reader.o src/utils/bit_writer.o \ - src/utils/quant_levels.o src/utils/thread.o src/utils/tcoder.o + src/utils/filters.o src/utils/quant_levels.o src/utils/thread.o \ + src/utils/tcoder.o OBJS = $(DEC_OBJS) $(ENC_OBJS) $(DSP_OBJS) $(UTILS_OBJS) @@ -81,7 +82,7 @@ HDRS = src/webp/encode.h src/enc/vp8enci.h src/enc/cost.h src/webp/mux.h \ src/dec/vp8i.h \ src/dsp/yuv.h src/dsp/dsp.h \ src/utils/alpha.h src/utils/bit_writer.h src/utils/bit_reader.h \ - src/utils/thread.h src/utils/tcoder.h + src/utils/filters.h src/utils/thread.h src/utils/tcoder.h OUT_LIBS = src/libwebp.a src/mux/libwebpmux.a OUT_EXAMPLES = examples/cwebp examples/dwebp examples/webpmux diff --git a/man/cwebp.1 b/man/cwebp.1 index 5c313319..5cd7c474 100644 --- a/man/cwebp.1 +++ b/man/cwebp.1 @@ -41,6 +41,12 @@ Specify the compression factor for alpha compression between 0 and 100. Lossless compression of alpha is achieved using a value of 100, while the lower values result in a lossy compression. The default is 100. .TP +.B \-alpha_filter int +Specify the predictive filtering method (between 0 and 5) for alpha plane. +These correspond to prediction modes none, horizontal, vertical, gradient and +paeth filters. The prediction mode 5 will try all the prediction modes (0 to 4) +and pick the best prediction mode. The default value is 0 (no prediction). +.TP .B \-f int Specify the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering). A value of 0 will turn off any filtering. diff --git a/src/enc/alpha.c b/src/enc/alpha.c index 48cbe76a..3ab5d42e 100644 --- a/src/enc/alpha.c +++ b/src/enc/alpha.c @@ -36,7 +36,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) { assert(pic->a); if (!EncodeAlpha(pic->a, pic->width, pic->height, pic->a_stride, config->alpha_quality, config->alpha_compression, - &tmp_data, &tmp_size)) { + config->alpha_filtering, &tmp_data, &tmp_size)) { return 0; } if (tmp_size != (uint32_t)tmp_size) { // Sanity check. diff --git a/src/enc/config.c b/src/enc/config.c index 47d8f52f..467013d8 100644 --- a/src/enc/config.c +++ b/src/enc/config.c @@ -43,6 +43,7 @@ int WebPConfigInitInternal(WebPConfig* const config, config->autofilter = 0; config->partition_limit = 0; config->alpha_compression = 1; + config->alpha_filtering = 0; config->alpha_quality = 100; // TODO(skal): tune. @@ -112,6 +113,8 @@ int WebPValidateConfig(const WebPConfig* const config) { return 0; if (config->alpha_compression < 0) return 0; + if (config->alpha_filtering < 0) + return 0; if (config->alpha_quality < 0 || config->alpha_quality > 100) return 0; return 1; diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index e832b390..29cfac2f 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -3,6 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src libwebputils_la_SOURCES = alpha.h alpha.c \ bit_reader.h bit_reader.c \ bit_writer.h bit_writer.c \ + filters.h filters.c \ quant_levels.c \ tcoder.h tcoderi.h tcoder.c \ thread.h thread.c diff --git a/src/utils/alpha.c b/src/utils/alpha.c index 7db066ed..8bb87177 100644 --- a/src/utils/alpha.c +++ b/src/utils/alpha.c @@ -14,6 +14,7 @@ #include "./bit_reader.h" #include "./bit_writer.h" +#include "./filters.h" #include "./tcoder.h" #if defined(__cplusplus) || defined(c_plusplus) @@ -228,7 +229,7 @@ static void CopyPlane(const uint8_t* src, int src_stride, } int EncodeAlpha(const uint8_t* data, int width, int height, int stride, - int quality, int method, + int quality, int method, int filter, uint8_t** output, size_t* output_size) { uint8_t* quant_alpha = NULL; const size_t data_size = height * width; @@ -238,6 +239,7 @@ int EncodeAlpha(const uint8_t* data, int width, int height, int stride, assert(data != NULL && output != NULL && output_size != NULL); assert(width > 0 && height > 0); assert(stride >= width); + assert(filter < WEBP_FILTER_LAST); if (quality < 0 || quality > 100) { return 0; @@ -265,22 +267,60 @@ int EncodeAlpha(const uint8_t* data, int width, int height, int stride, } if (ok) { - uint8_t header[ALPHA_HEADER_LEN]; - VP8BitWriter bw; - VP8BitWriterInit(&bw, - (method == 0) ? (2 + data_size) - : (data_size >> 5) /* rough estimate of final size */); - header[0] = method & 0xff; // Compression Method. - header[1] = 0; // reserved byte for later use - VP8BitWriterAppend(&bw, header, sizeof(header)); - - ok = EncodeAlphaInternal(quant_alpha, width, height, method, &bw); - if (!ok) { - VP8BitWriterWipeOut(&bw); - } else { - *output = VP8BitWriterBuf(&bw); - *output_size = VP8BitWriterSize(&bw); + WEBP_FILTER_TYPE this_filter; + size_t best_size = 1 << 30; + uint8_t* tmp_out = NULL; + uint8_t* const filtered_alpha = (uint8_t*)malloc(data_size); + if (filtered_alpha == NULL) { + free(quant_alpha); + return 0; } + // Filtering. + for (this_filter = WEBP_FILTER_NONE; this_filter < WEBP_FILTER_LAST; + ++this_filter) { + uint8_t header[ALPHA_HEADER_LEN]; + VP8BitWriter bw; + WebPFilterFunc filter_func = NULL; + const size_t expected_size = (method == 0) ? + (ALPHA_HEADER_LEN + data_size) : (data_size >> 5); + if (this_filter == WEBP_FILTER_BEST) { + continue; + } else if (this_filter != filter && filter != WEBP_FILTER_BEST) { + continue; + } + + header[0] = ((this_filter & 0x0f) << 4) | (method & 0x0f); + header[1] = 0; // reserved byte for later use + VP8BitWriterInit(&bw, expected_size); + VP8BitWriterAppend(&bw, header, sizeof(header)); + + filter_func = WebPFilters[this_filter]; + if (filter_func) { + filter_func(quant_alpha, width, height, 1, width, filtered_alpha); + ok = EncodeAlphaInternal(filtered_alpha, width, height, method, &bw); + } else { + ok = EncodeAlphaInternal(quant_alpha, width, height, method, &bw); + } + if (ok) { + const size_t this_size = VP8BitWriterSize(&bw); + if (this_size < best_size) { + free(tmp_out); + tmp_out = VP8BitWriterBuf(&bw); + best_size = this_size; + } else { + VP8BitWriterWipeOut(&bw); + } + } else { + free(tmp_out); + VP8BitWriterWipeOut(&bw); + break; + } + } + if (ok) { + *output_size = best_size; + *output = tmp_out; + } + free(filtered_alpha); } free(quant_alpha); @@ -338,6 +378,8 @@ int DecodeAlpha(const uint8_t* data, size_t data_size, uint8_t* output) { uint8_t* decoded_data = NULL; const size_t decoded_size = height * width; + uint8_t* unfiltered_data = NULL; + int filter; int ok = 0; int method; @@ -348,9 +390,11 @@ int DecodeAlpha(const uint8_t* data, size_t data_size, return 0; } - method = data[0]; + method = data[0] & 0x0f; + filter = data[0] >> 4; ok = (data[1] == 0); - if (method < 0 || method > 1 || !ok) { + if (method < 0 || method > 1 || + filter < WEBP_FILTER_NONE || filter > WEBP_FILTER_PAETH || !ok) { return 0; } @@ -366,9 +410,24 @@ int DecodeAlpha(const uint8_t* data, size_t data_size, VP8InitBitReader(&br, data + ALPHA_HEADER_LEN, data + data_size); ok = DecompressZlibTCoder(&br, width, decoded_data, decoded_size); } - // Construct raw_data (height x stride) from alpha data (height x width). if (ok) { - CopyPlane(decoded_data, width, output, stride, width, height); + WebPFilterFunc unfilter_func = WebPUnfilters[filter]; + if (unfilter_func) { + unfiltered_data = (uint8_t*)malloc(decoded_size); + if (unfiltered_data == NULL) { + if (method == 1) free(decoded_data); + return 0; + } + // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode + // and apply filter per image-row. + unfilter_func(decoded_data, width, height, 1, width, unfiltered_data); + // Construct raw_data (height x stride) from alpha data (height x width). + CopyPlane(unfiltered_data, width, output, stride, width, height); + free(unfiltered_data); + } else { + // Construct raw_data (height x stride) from alpha data (height x width). + CopyPlane(decoded_data, width, output, stride, width, height); + } } if (method == 1) { free(decoded_data); diff --git a/src/utils/alpha.h b/src/utils/alpha.h index f6416ec8..33379ed6 100644 --- a/src/utils/alpha.h +++ b/src/utils/alpha.h @@ -26,6 +26,10 @@ extern "C" { // lossy. Valid ranges for 'quality' is [0, 100] and 'method' is [0, 1]: // 'method = 0' - No compression; // 'method = 1' - Backward reference counts encoded with arithmetic encoder; +// 'filter' values [0, 5] correspond to prediction modes none, horizontal, +// vertical, gradient & paeth filters. The prediction value 5 will try all the +// prediction modes (0 to 4) and pick the best prediction mode. + // 'output' corresponds to the buffer containing compressed alpha data. // This buffer is allocated by this method and caller should call // free(*output) when done. @@ -33,13 +37,11 @@ extern "C" { // // Returns 1 on successfully encoding the alpha and // 0 if either: -// data, output or output_size is NULL, or -// inappropriate width, height or stride, or // invalid quality or method, or // memory allocation for the compressed data fails. int EncodeAlpha(const uint8_t* data, int width, int height, int stride, - int quality, int method, + int quality, int method, int filter, uint8_t** output, size_t* output_size); // Decodes the compressed data 'data' of size 'data_size' into the 'output'. @@ -48,8 +50,7 @@ int EncodeAlpha(const uint8_t* data, int width, int height, int stride, // // Returns 1 on successfully decoding the compressed alpha and // 0 if either: -// data or output is NULL, or -// error in bit-stream header (invalid compression mode or qbits), or +// error in bit-stream header (invalid compression mode or filter), or // error returned by appropriate compression method. int DecodeAlpha(const uint8_t* data, size_t data_size, int width, int height, int stride, uint8_t* output); diff --git a/src/utils/filters.c b/src/utils/filters.c new file mode 100644 index 00000000..0abdd687 --- /dev/null +++ b/src/utils/filters.c @@ -0,0 +1,267 @@ +// Copyright 2011 Google Inc. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#include "./filters.h" +#include +#include +#include +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Helpful macro. + +# define SANITY_CHECK(in, out) \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(bpp > 0); \ + assert(stride >= width * bpp); + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static void HorizontalFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + int h; + SANITY_CHECK(data, filtered_data); + + // Filter line-by-line. + for (h = 0; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = filtered_data + h * stride; + + memcpy((void*)out, (const void*)scan_line, bpp); + for (w = bpp; w < width * bpp; ++w) { + out[w] = scan_line[w] - scan_line[w - bpp]; + } + } +} + +static void HorizontalUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + int h; + SANITY_CHECK(data, recon_data); + + // Unfilter line-by-line. + for (h = 0; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = recon_data + h * stride; + + memcpy((void*)out, (const void*)scan_line, bpp); + for (w = bpp; w < width * bpp; ++w) { + out[w] = scan_line[w] + out[w - bpp]; + } + } +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static void VerticalFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + int h; + SANITY_CHECK(data, filtered_data); + + // Copy top scan-line as it is. + memcpy((void*)filtered_data, (const void*)data, width * bpp); + + // Filter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = filtered_data + h * stride; + const uint8_t* const prev_line = scan_line - stride; + for (w = 0; w < width * bpp; ++w) { + out[w] = scan_line[w] - prev_line[w]; + } + } +} + +static void VerticalUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + int h; + SANITY_CHECK(data, recon_data); + + // Copy top scan-line as it is. + memcpy((void*)recon_data, (const void*)data, width * bpp); + + // Unfilter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = recon_data + h * stride; + const uint8_t* const out_prev_line = out - stride; + for (w = 0; w < width * bpp; ++w) { + out[w] = scan_line[w] + out_prev_line[w]; + } + } +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static void GradientFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + int h; + SANITY_CHECK(data, filtered_data); + + // Copy top scan-line as it is. + memcpy((void*)filtered_data, (const void*)data, width * bpp); + + // Filter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = filtered_data + h * stride; + const uint8_t* const prev_line = scan_line - stride; + memcpy((void*)out, (const void*)scan_line, bpp); + for (w = bpp; w < width * bpp; ++w) { + const uint8_t predictor = scan_line[w - bpp] + prev_line[w] - + prev_line[w - bpp]; + out[w] = scan_line[w] - predictor; + } + } +} + +static void GradientUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + int h; + SANITY_CHECK(data, recon_data); + + // Copy top scan-line as it is. + memcpy((void*)recon_data, (const void*)data, width * bpp); + + // Unfilter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = recon_data + h * stride; + const uint8_t* const out_prev_line = out - stride; + memcpy((void*)out, (const void*)scan_line, bpp); + for (w = bpp; w < width * bpp; ++w) { + const uint8_t predictor = out[w - bpp] + out_prev_line[w] - + out_prev_line[w - bpp]; + out[w] = scan_line[w] + predictor; + } + } +} + +//------------------------------------------------------------------------------ +// Paeth filter. + +static inline int AbsDiff(int a, int b) { + return (a > b) ? a - b : b - a; +} + +static inline uint8_t PaethPredictor(uint8_t a, uint8_t b, uint8_t c) { + const int p = a + b - c; // Base. + const int pa = AbsDiff(p, a); + const int pb = AbsDiff(p, b); + const int pc = AbsDiff(p, c); + + // Return nearest to base of a, b, c. + return (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; +} + +static void PaethFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + int w; + int h; + SANITY_CHECK(data, filtered_data); + + // Top scan line (special case). + memcpy((void*)filtered_data, (const void*)data, bpp); + for (w = bpp; w < width * bpp; ++w) { + // Note: PaethPredictor(scan_line[w - bpp], 0, 0) == scan_line[w - bpp]. + filtered_data[w] = data[w] - data[w - bpp]; + } + + // Filter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = filtered_data + h * stride; + const uint8_t* const prev_line = scan_line - stride; + for (w = 0; w < bpp; ++w) { + // Note: PaethPredictor(0, prev_line[w], 0) == prev_line[w]. + out[w] = scan_line[w] - prev_line[w]; + } + for (w = bpp; w < width * bpp; ++w) { + out[w] = scan_line[w] - PaethPredictor(scan_line[w - bpp], prev_line[w], + prev_line[w - bpp]); + } + } +} + +static void PaethUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + int w; + int h; + SANITY_CHECK(data, recon_data); + + // Top scan line (special case). + memcpy((void*)recon_data, (const void*)data, bpp); + for (w = bpp; w < width * bpp; ++w) { + // Note: PaethPredictor(out[w - bpp], 0, 0) == out[w - bpp]. + recon_data[w] = data[w] + recon_data[w - bpp]; + } + + // Unfilter line-by-line. + for (h = 1; h < height; ++h) { + int w; + const uint8_t* const scan_line = data + h * stride; + uint8_t* const out = recon_data + h * stride; + const uint8_t* const out_prev = out - stride; + for (w = 0; w < bpp; ++w) { + // Note: PaethPredictor(0, out_prev[w], 0) == out_prev[w]. + out[w] = scan_line[w] + out_prev[w]; + } + for (w = bpp; w < width * bpp; ++w) { + out[w] = scan_line[w] + PaethPredictor(out[w - bpp], out_prev[w], + out_prev[w - bpp]); + } + } +} + +#undef SANITY_CHECK + +//------------------------------------------------------------------------------ + +const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { + NULL, // WEBP_FILTER_NONE + HorizontalFilter, // WEBP_FILTER_HORIZONTAL + VerticalFilter, // WEBP_FILTER_VERTICAL + GradientFilter, // WEBP_FILTER_GRADIENT + PaethFilter, // WEBP_FILTER_PAETH + NULL // WEBP_FILTER_BEST +}; + +const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { + NULL, // WEBP_FILTER_NONE + HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL + VerticalUnfilter, // WEBP_FILTER_VERTICAL + GradientUnfilter, // WEBP_FILTER_GRADIENT + PaethUnfilter, // WEBP_FILTER_PAETH + NULL // WEBP_FILTER_BEST +}; + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/src/utils/filters.h b/src/utils/filters.h new file mode 100644 index 00000000..e45b66f4 --- /dev/null +++ b/src/utils/filters.h @@ -0,0 +1,50 @@ +// Copyright 2011 Google Inc. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_UTILS_FILTERS_H_ +#define WEBP_UTILS_FILTERS_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// Filters. +typedef enum { + WEBP_FILTER_NONE = 0, + WEBP_FILTER_HORIZONTAL, + WEBP_FILTER_VERTICAL, + WEBP_FILTER_GRADIENT, + WEBP_FILTER_PAETH, + WEBP_FILTER_BEST, + WEBP_FILTER_LAST, +} WEBP_FILTER_TYPE; + +typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, + int bpp, int stride, uint8_t* out); + +// Filter the given data using the given predictor. +// 'in' corresponds to a 2-dimensional pixel array of size (stride * height) +// in raster order. +// 'bpp' is number of bytes per pixel, and +// 'stride' is number of bytes per scan line (with possible padding). +// 'out' should be pre-allocated. +extern const WebPFilterFunc WebPFilters[/*WEBP_FILTER_LAST*/]; + +// Reconstruct the original data from the given filtered data. +extern const WebPFilterFunc WebPUnfilters[/*WEBP_FILTER_LAST*/]; + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_FILTERS_H_ */ diff --git a/src/webp/encode.h b/src/webp/encode.h index 442e70a8..965e9a29 100644 --- a/src/webp/encode.h +++ b/src/webp/encode.h @@ -74,6 +74,9 @@ typedef struct { int alpha_compression; // Algorithm for encoding the alpha plane (0 = none, // 1 = backward reference counts encoded with // arithmetic encoder). Default is 1. + int alpha_filtering; // Predictive filtering method for alpha plane. + // (0 = none, 1 = horizontal, 2 = vertical, 3 = grad, + // 4 = Paeth and 5 = Best of (0 .. 4). int alpha_quality; // Between 0 (smallest size) and 100 (lossless). // Default is 100. } WebPConfig;