mirror of
https://github.com/webmproject/libwebp.git
synced 2025-01-28 23:52:56 +01:00
Merge "Add delta_palettization feature to WebP"
This commit is contained in:
commit
0dd282672e
@ -97,6 +97,7 @@ enc_srcs := \
|
|||||||
src/enc/backward_references.c \
|
src/enc/backward_references.c \
|
||||||
src/enc/config.c \
|
src/enc/config.c \
|
||||||
src/enc/cost.c \
|
src/enc/cost.c \
|
||||||
|
src/enc/delta_palettization.c \
|
||||||
src/enc/filter.c \
|
src/enc/filter.c \
|
||||||
src/enc/frame.c \
|
src/enc/frame.c \
|
||||||
src/enc/histogram.c \
|
src/enc/histogram.c \
|
||||||
|
@ -262,6 +262,7 @@ ENC_OBJS = \
|
|||||||
$(DIROBJ)\enc\backward_references.obj \
|
$(DIROBJ)\enc\backward_references.obj \
|
||||||
$(DIROBJ)\enc\config.obj \
|
$(DIROBJ)\enc\config.obj \
|
||||||
$(DIROBJ)\enc\cost.obj \
|
$(DIROBJ)\enc\cost.obj \
|
||||||
|
$(DIROBJ)\enc\delta_palettization.obj \
|
||||||
$(DIROBJ)\enc\filter.obj \
|
$(DIROBJ)\enc\filter.obj \
|
||||||
$(DIROBJ)\enc\frame.obj \
|
$(DIROBJ)\enc\frame.obj \
|
||||||
$(DIROBJ)\enc\histogram.obj \
|
$(DIROBJ)\enc\histogram.obj \
|
||||||
|
@ -617,6 +617,9 @@ static void HelpLong(void) {
|
|||||||
printf(" -lossless .............. encode image losslessly\n");
|
printf(" -lossless .............. encode image losslessly\n");
|
||||||
printf(" -near_lossless <int> ... use near-lossless image\n"
|
printf(" -near_lossless <int> ... use near-lossless image\n"
|
||||||
" preprocessing (0..100=off)\n");
|
" preprocessing (0..100=off)\n");
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
printf(" -delta_palettization ... use delta palettization\n");
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
printf(" -hint <string> ......... specify image characteristics hint,\n");
|
printf(" -hint <string> ......... specify image characteristics hint,\n");
|
||||||
printf(" one of: photo, picture or graph\n");
|
printf(" one of: photo, picture or graph\n");
|
||||||
|
|
||||||
@ -775,6 +778,11 @@ int main(int argc, const char *argv[]) {
|
|||||||
} else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
|
||||||
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
|
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
config.lossless = 1; // use near-lossless only with lossless
|
config.lossless = 1; // use near-lossless only with lossless
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
} else if (!strcmp(argv[c], "-delta_palettization")) {
|
||||||
|
config.delta_palettization = 1;
|
||||||
|
config.lossless = 1; // use delta-palettization only with lossless
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
|
||||||
++c;
|
++c;
|
||||||
if (!strcmp(argv[c], "photo")) {
|
if (!strcmp(argv[c], "photo")) {
|
||||||
|
@ -187,6 +187,7 @@ ENC_OBJS = \
|
|||||||
src/enc/backward_references.o \
|
src/enc/backward_references.o \
|
||||||
src/enc/config.o \
|
src/enc/config.o \
|
||||||
src/enc/cost.o \
|
src/enc/cost.o \
|
||||||
|
src/enc/delta_palettization.o \
|
||||||
src/enc/filter.o \
|
src/enc/filter.o \
|
||||||
src/enc/frame.o \
|
src/enc/frame.o \
|
||||||
src/enc/histogram.o \
|
src/enc/histogram.o \
|
||||||
@ -272,6 +273,7 @@ HDRS = \
|
|||||||
src/dsp/yuv_tables_sse2.h \
|
src/dsp/yuv_tables_sse2.h \
|
||||||
src/enc/backward_references.h \
|
src/enc/backward_references.h \
|
||||||
src/enc/cost.h \
|
src/enc/cost.h \
|
||||||
|
src/enc/delta_palettization.h \
|
||||||
src/enc/histogram.h \
|
src/enc/histogram.h \
|
||||||
src/enc/vp8enci.h \
|
src/enc/vp8enci.h \
|
||||||
src/enc/vp8li.h \
|
src/enc/vp8li.h \
|
||||||
|
@ -634,3 +634,103 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
// Delta palettization functions.
|
||||||
|
static WEBP_INLINE int Square(int x) {
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint32_t Intensity(uint32_t a) {
|
||||||
|
return
|
||||||
|
30 * ((a >> 16) & 0xff) +
|
||||||
|
59 * ((a >> 8) & 0xff) +
|
||||||
|
11 * ((a >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t CalcDist(uint32_t predicted_value, uint32_t actual_value,
|
||||||
|
uint32_t palette_entry) {
|
||||||
|
int i;
|
||||||
|
uint32_t distance = 0;
|
||||||
|
AddPixelsEq(&predicted_value, palette_entry);
|
||||||
|
for (i = 0; i < 32; i += 8) {
|
||||||
|
const int32_t av = (actual_value >> i) & 0xff;
|
||||||
|
const int32_t pv = (predicted_value >> i) & 0xff;
|
||||||
|
distance += Square(pv - av);
|
||||||
|
}
|
||||||
|
// We sum square of intensity difference with factor 10, but because Intensity
|
||||||
|
// returns 100 times real intensity we need to multiply differences of colors
|
||||||
|
// by 1000.
|
||||||
|
distance *= 1000u;
|
||||||
|
distance += Square(Intensity(predicted_value)
|
||||||
|
- Intensity(actual_value));
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t Predict(int x, int y, uint32_t* image) {
|
||||||
|
const uint32_t t = y == 0 ? ARGB_BLACK : image[x];
|
||||||
|
const uint32_t l = x == 0 ? ARGB_BLACK : image[x - 1];
|
||||||
|
const uint32_t p =
|
||||||
|
(((((t >> 24) & 0xff) + ((l >> 24) & 0xff)) / 2) << 24) +
|
||||||
|
(((((t >> 16) & 0xff) + ((l >> 16) & 0xff)) / 2) << 16) +
|
||||||
|
(((((t >> 8) & 0xff) + ((l >> 8) & 0xff)) / 2) << 8) +
|
||||||
|
(((((t >> 0) & 0xff) + ((l >> 0) & 0xff)) / 2) << 0);
|
||||||
|
if (x == 0 && y == 0) return ARGB_BLACK;
|
||||||
|
if (x == 0) return t;
|
||||||
|
if (y == 0) return l;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int AddSubtractComponentFullWithCoefficient(
|
||||||
|
int a, int b, int c) {
|
||||||
|
return Clip255(a + ((b - c) >> 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint32_t ClampedAddSubtractFullWithCoefficient(
|
||||||
|
uint32_t c0, uint32_t c1, uint32_t c2) {
|
||||||
|
const int a = AddSubtractComponentFullWithCoefficient(
|
||||||
|
c0 >> 24, c1 >> 24, c2 >> 24);
|
||||||
|
const int r = AddSubtractComponentFullWithCoefficient((c0 >> 16) & 0xff,
|
||||||
|
(c1 >> 16) & 0xff,
|
||||||
|
(c2 >> 16) & 0xff);
|
||||||
|
const int g = AddSubtractComponentFullWithCoefficient((c0 >> 8) & 0xff,
|
||||||
|
(c1 >> 8) & 0xff,
|
||||||
|
(c2 >> 8) & 0xff);
|
||||||
|
const int b = AddSubtractComponentFullWithCoefficient(
|
||||||
|
c0 & 0xff, c1 & 0xff, c2 & 0xff);
|
||||||
|
return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FindBestPaletteEntry(int x, int y, const uint32_t* palette,
|
||||||
|
int palette_size, uint32_t* src,
|
||||||
|
int src_stride, uint32_t* new_image) {
|
||||||
|
int i;
|
||||||
|
const uint32_t predicted_value = Predict(x, y, new_image);
|
||||||
|
int idx = 0;
|
||||||
|
uint32_t best_distance = CalcDist(predicted_value, src[x], palette[0]);
|
||||||
|
for (i = 1; i < palette_size; ++i) {
|
||||||
|
const uint32_t distance = CalcDist(predicted_value, src[x], palette[i]);
|
||||||
|
if (distance < best_distance) {
|
||||||
|
best_distance = distance;
|
||||||
|
idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t new_value = predicted_value;
|
||||||
|
AddPixelsEq(&new_value, palette[idx]);
|
||||||
|
if (x > 0) {
|
||||||
|
src[x - 1] = ClampedAddSubtractFullWithCoefficient(
|
||||||
|
src[x - 1], new_value, src[x]);
|
||||||
|
}
|
||||||
|
if (y > 0) {
|
||||||
|
src[x - src_stride] =
|
||||||
|
ClampedAddSubtractFullWithCoefficient(
|
||||||
|
src[x - src_stride], new_value, src[x]);
|
||||||
|
}
|
||||||
|
new_image[x] = new_value;
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
#include "../enc/delta_palettization.h"
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// Not a trivial literal symbol.
|
// Not a trivial literal symbol.
|
||||||
#define VP8L_NON_TRIVIAL_SYM (0xffffffff)
|
#define VP8L_NON_TRIVIAL_SYM (0xffffffff)
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ libwebpencode_la_SOURCES += backward_references.c
|
|||||||
libwebpencode_la_SOURCES += config.c
|
libwebpencode_la_SOURCES += config.c
|
||||||
libwebpencode_la_SOURCES += cost.c
|
libwebpencode_la_SOURCES += cost.c
|
||||||
libwebpencode_la_SOURCES += cost.h
|
libwebpencode_la_SOURCES += cost.h
|
||||||
|
libwebpencode_la_SOURCES += delta_palettization.c
|
||||||
|
libwebpencode_la_SOURCES += delta_palettization.h
|
||||||
libwebpencode_la_SOURCES += filter.c
|
libwebpencode_la_SOURCES += filter.c
|
||||||
libwebpencode_la_SOURCES += frame.c
|
libwebpencode_la_SOURCES += frame.c
|
||||||
libwebpencode_la_SOURCES += histogram.c
|
libwebpencode_la_SOURCES += histogram.c
|
||||||
|
@ -48,6 +48,9 @@ int WebPConfigInitInternal(WebPConfig* config,
|
|||||||
config->thread_level = 0;
|
config->thread_level = 0;
|
||||||
config->low_memory = 0;
|
config->low_memory = 0;
|
||||||
config->near_lossless = 100;
|
config->near_lossless = 100;
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
config->delta_palettization = 0;
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// TODO(skal): tune.
|
// TODO(skal): tune.
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
@ -136,6 +139,10 @@ int WebPValidateConfig(const WebPConfig* config) {
|
|||||||
return 0;
|
return 0;
|
||||||
if (config->low_memory < 0 || config->low_memory > 1)
|
if (config->low_memory < 0 || config->low_memory > 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
if (config->delta_palettization < 0 || config->delta_palettization > 1)
|
||||||
|
return 0;
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
273
src/enc/delta_palettization.c
Normal file
273
src/enc/delta_palettization.c
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
#include "./delta_palettization.h"
|
||||||
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
#define MK_COL(r, g, b) (((r) << 16) + ((g) << 8) + (b))
|
||||||
|
|
||||||
|
// Palette used for delta_palettization.
|
||||||
|
const uint32_t kDeltaPalette[DELTA_PALETTE_SIZE] = {
|
||||||
|
MK_COL(128u, 128u, 128u),
|
||||||
|
MK_COL(128u, 128u, 64u),
|
||||||
|
MK_COL(128u, 128u, 192u),
|
||||||
|
MK_COL(128u, 128u, 0u),
|
||||||
|
MK_COL(128u, 64u, 128u),
|
||||||
|
MK_COL(128u, 64u, 64u),
|
||||||
|
MK_COL(128u, 64u, 192u),
|
||||||
|
MK_COL(128u, 64u, 0u),
|
||||||
|
MK_COL(128u, 192u, 128u),
|
||||||
|
MK_COL(128u, 192u, 64u),
|
||||||
|
MK_COL(128u, 192u, 192u),
|
||||||
|
MK_COL(128u, 192u, 0u),
|
||||||
|
MK_COL(128u, 0u, 128u),
|
||||||
|
MK_COL(128u, 0u, 64u),
|
||||||
|
MK_COL(128u, 0u, 192u),
|
||||||
|
MK_COL(128u, 0u, 0u),
|
||||||
|
MK_COL(64u, 128u, 128u),
|
||||||
|
MK_COL(64u, 128u, 64u),
|
||||||
|
MK_COL(64u, 128u, 192u),
|
||||||
|
MK_COL(64u, 128u, 0u),
|
||||||
|
MK_COL(64u, 64u, 128u),
|
||||||
|
MK_COL(64u, 64u, 64u),
|
||||||
|
MK_COL(64u, 64u, 192u),
|
||||||
|
MK_COL(64u, 64u, 0u),
|
||||||
|
MK_COL(64u, 192u, 128u),
|
||||||
|
MK_COL(64u, 192u, 64u),
|
||||||
|
MK_COL(64u, 192u, 192u),
|
||||||
|
MK_COL(64u, 192u, 0u),
|
||||||
|
MK_COL(64u, 0u, 128u),
|
||||||
|
MK_COL(64u, 0u, 64u),
|
||||||
|
MK_COL(64u, 0u, 192u),
|
||||||
|
MK_COL(64u, 0u, 0u),
|
||||||
|
MK_COL(192u, 128u, 128u),
|
||||||
|
MK_COL(192u, 128u, 64u),
|
||||||
|
MK_COL(192u, 128u, 192u),
|
||||||
|
MK_COL(192u, 128u, 0u),
|
||||||
|
MK_COL(192u, 64u, 128u),
|
||||||
|
MK_COL(192u, 64u, 64u),
|
||||||
|
MK_COL(192u, 64u, 192u),
|
||||||
|
MK_COL(192u, 64u, 0u),
|
||||||
|
MK_COL(192u, 192u, 128u),
|
||||||
|
MK_COL(192u, 192u, 64u),
|
||||||
|
MK_COL(192u, 192u, 192u),
|
||||||
|
MK_COL(192u, 192u, 0u),
|
||||||
|
MK_COL(192u, 0u, 128u),
|
||||||
|
MK_COL(192u, 0u, 64u),
|
||||||
|
MK_COL(192u, 0u, 192u),
|
||||||
|
MK_COL(192u, 0u, 0u),
|
||||||
|
MK_COL(176u, 80u, 80u),
|
||||||
|
MK_COL(176u, 80u, 176u),
|
||||||
|
MK_COL(176u, 80u, 40u),
|
||||||
|
MK_COL(176u, 80u, 216u),
|
||||||
|
MK_COL(176u, 176u, 80u),
|
||||||
|
MK_COL(176u, 176u, 176u),
|
||||||
|
MK_COL(176u, 176u, 40u),
|
||||||
|
MK_COL(176u, 176u, 216u),
|
||||||
|
MK_COL(176u, 40u, 80u),
|
||||||
|
MK_COL(176u, 40u, 176u),
|
||||||
|
MK_COL(176u, 40u, 40u),
|
||||||
|
MK_COL(176u, 40u, 216u),
|
||||||
|
MK_COL(176u, 216u, 80u),
|
||||||
|
MK_COL(176u, 216u, 176u),
|
||||||
|
MK_COL(176u, 216u, 40u),
|
||||||
|
MK_COL(176u, 216u, 216u),
|
||||||
|
MK_COL(0u, 128u, 128u),
|
||||||
|
MK_COL(0u, 128u, 64u),
|
||||||
|
MK_COL(0u, 128u, 192u),
|
||||||
|
MK_COL(0u, 128u, 0u),
|
||||||
|
MK_COL(0u, 64u, 128u),
|
||||||
|
MK_COL(0u, 64u, 64u),
|
||||||
|
MK_COL(0u, 64u, 192u),
|
||||||
|
MK_COL(0u, 64u, 0u),
|
||||||
|
MK_COL(0u, 192u, 128u),
|
||||||
|
MK_COL(0u, 192u, 64u),
|
||||||
|
MK_COL(0u, 192u, 192u),
|
||||||
|
MK_COL(0u, 192u, 0u),
|
||||||
|
MK_COL(0u, 0u, 128u),
|
||||||
|
MK_COL(0u, 0u, 64u),
|
||||||
|
MK_COL(0u, 0u, 192u),
|
||||||
|
MK_COL(80u, 80u, 80u),
|
||||||
|
MK_COL(80u, 80u, 176u),
|
||||||
|
MK_COL(80u, 80u, 40u),
|
||||||
|
MK_COL(80u, 80u, 216u),
|
||||||
|
MK_COL(80u, 176u, 80u),
|
||||||
|
MK_COL(80u, 176u, 176u),
|
||||||
|
MK_COL(80u, 176u, 40u),
|
||||||
|
MK_COL(80u, 176u, 216u),
|
||||||
|
MK_COL(80u, 40u, 80u),
|
||||||
|
MK_COL(80u, 40u, 176u),
|
||||||
|
MK_COL(80u, 40u, 40u),
|
||||||
|
MK_COL(80u, 40u, 216u),
|
||||||
|
MK_COL(80u, 216u, 80u),
|
||||||
|
MK_COL(80u, 216u, 176u),
|
||||||
|
MK_COL(80u, 216u, 40u),
|
||||||
|
MK_COL(80u, 216u, 216u),
|
||||||
|
MK_COL(40u, 80u, 80u),
|
||||||
|
MK_COL(40u, 80u, 176u),
|
||||||
|
MK_COL(40u, 80u, 40u),
|
||||||
|
MK_COL(40u, 80u, 216u),
|
||||||
|
MK_COL(40u, 176u, 80u),
|
||||||
|
MK_COL(40u, 176u, 176u),
|
||||||
|
MK_COL(40u, 176u, 40u),
|
||||||
|
MK_COL(40u, 176u, 216u),
|
||||||
|
MK_COL(40u, 40u, 80u),
|
||||||
|
MK_COL(40u, 40u, 176u),
|
||||||
|
MK_COL(40u, 40u, 40u),
|
||||||
|
MK_COL(40u, 40u, 216u),
|
||||||
|
MK_COL(40u, 216u, 80u),
|
||||||
|
MK_COL(40u, 216u, 176u),
|
||||||
|
MK_COL(40u, 216u, 40u),
|
||||||
|
MK_COL(40u, 216u, 216u),
|
||||||
|
MK_COL(216u, 80u, 80u),
|
||||||
|
MK_COL(216u, 80u, 176u),
|
||||||
|
MK_COL(216u, 80u, 40u),
|
||||||
|
MK_COL(216u, 80u, 216u),
|
||||||
|
MK_COL(216u, 176u, 80u),
|
||||||
|
MK_COL(216u, 176u, 176u),
|
||||||
|
MK_COL(216u, 176u, 40u),
|
||||||
|
MK_COL(216u, 176u, 216u),
|
||||||
|
MK_COL(216u, 40u, 80u),
|
||||||
|
MK_COL(216u, 40u, 176u),
|
||||||
|
MK_COL(216u, 40u, 40u),
|
||||||
|
MK_COL(216u, 40u, 216u),
|
||||||
|
MK_COL(216u, 216u, 80u),
|
||||||
|
MK_COL(216u, 216u, 176u),
|
||||||
|
MK_COL(216u, 216u, 40u),
|
||||||
|
MK_COL(216u, 216u, 216u),
|
||||||
|
MK_COL(104u, 104u, 0u),
|
||||||
|
MK_COL(104u, 152u, 0u),
|
||||||
|
MK_COL(104u, 0u, 104u),
|
||||||
|
MK_COL(104u, 0u, 152u),
|
||||||
|
MK_COL(104u, 0u, 0u),
|
||||||
|
MK_COL(152u, 104u, 0u),
|
||||||
|
MK_COL(152u, 152u, 0u),
|
||||||
|
MK_COL(152u, 0u, 104u),
|
||||||
|
MK_COL(152u, 0u, 152u),
|
||||||
|
MK_COL(152u, 0u, 0u),
|
||||||
|
MK_COL(0u, 104u, 104u),
|
||||||
|
MK_COL(0u, 104u, 152u),
|
||||||
|
MK_COL(0u, 104u, 0u),
|
||||||
|
MK_COL(0u, 152u, 104u),
|
||||||
|
MK_COL(0u, 152u, 152u),
|
||||||
|
MK_COL(0u, 152u, 0u),
|
||||||
|
MK_COL(0u, 0u, 104u),
|
||||||
|
MK_COL(0u, 0u, 152u),
|
||||||
|
MK_COL(80u, 80u, 0u),
|
||||||
|
MK_COL(80u, 176u, 0u),
|
||||||
|
MK_COL(80u, 0u, 80u),
|
||||||
|
MK_COL(80u, 0u, 176u),
|
||||||
|
MK_COL(80u, 0u, 0u),
|
||||||
|
MK_COL(176u, 80u, 0u),
|
||||||
|
MK_COL(176u, 176u, 0u),
|
||||||
|
MK_COL(176u, 0u, 80u),
|
||||||
|
MK_COL(176u, 0u, 176u),
|
||||||
|
MK_COL(176u, 0u, 0u),
|
||||||
|
MK_COL(0u, 80u, 80u),
|
||||||
|
MK_COL(0u, 80u, 176u),
|
||||||
|
MK_COL(0u, 80u, 0u),
|
||||||
|
MK_COL(0u, 176u, 80u),
|
||||||
|
MK_COL(0u, 176u, 176u),
|
||||||
|
MK_COL(0u, 176u, 0u),
|
||||||
|
MK_COL(0u, 0u, 80u),
|
||||||
|
MK_COL(0u, 0u, 176u),
|
||||||
|
MK_COL(224u, 224u, 224u),
|
||||||
|
MK_COL(32u, 224u, 224u),
|
||||||
|
MK_COL(224u, 32u, 224u),
|
||||||
|
MK_COL(32u, 32u, 224u),
|
||||||
|
MK_COL(224u, 224u, 32u),
|
||||||
|
MK_COL(32u, 224u, 32u),
|
||||||
|
MK_COL(224u, 32u, 32u),
|
||||||
|
MK_COL(32u, 32u, 32u),
|
||||||
|
MK_COL(24u, 0u, 0u),
|
||||||
|
MK_COL(0u, 24u, 0u),
|
||||||
|
MK_COL(0u, 0u, 24u),
|
||||||
|
MK_COL(232u, 0u, 0u),
|
||||||
|
MK_COL(0u, 232u, 0u),
|
||||||
|
MK_COL(0u, 0u, 232u),
|
||||||
|
MK_COL(240u, 240u, 240u),
|
||||||
|
MK_COL(16u, 240u, 240u),
|
||||||
|
MK_COL(240u, 16u, 240u),
|
||||||
|
MK_COL(16u, 16u, 240u),
|
||||||
|
MK_COL(240u, 240u, 16u),
|
||||||
|
MK_COL(16u, 240u, 16u),
|
||||||
|
MK_COL(240u, 16u, 16u),
|
||||||
|
MK_COL(16u, 16u, 16u),
|
||||||
|
MK_COL(8u, 8u, 0u),
|
||||||
|
MK_COL(8u, 248u, 0u),
|
||||||
|
MK_COL(8u, 0u, 8u),
|
||||||
|
MK_COL(8u, 0u, 248u),
|
||||||
|
MK_COL(8u, 0u, 0u),
|
||||||
|
MK_COL(248u, 8u, 0u),
|
||||||
|
MK_COL(248u, 248u, 0u),
|
||||||
|
MK_COL(248u, 0u, 8u),
|
||||||
|
MK_COL(248u, 0u, 248u),
|
||||||
|
MK_COL(248u, 0u, 0u),
|
||||||
|
MK_COL(0u, 8u, 8u),
|
||||||
|
MK_COL(0u, 8u, 248u),
|
||||||
|
MK_COL(0u, 8u, 0u),
|
||||||
|
MK_COL(0u, 248u, 8u),
|
||||||
|
MK_COL(0u, 248u, 248u),
|
||||||
|
MK_COL(0u, 248u, 0u),
|
||||||
|
MK_COL(0u, 0u, 8u),
|
||||||
|
MK_COL(0u, 0u, 248u),
|
||||||
|
MK_COL(0u, 0u, 0u),
|
||||||
|
MK_COL(255u, 255u, 255u),
|
||||||
|
MK_COL(1u, 1u, 1u),
|
||||||
|
MK_COL(254u, 254u, 2u),
|
||||||
|
MK_COL(248u, 249u, 248u),
|
||||||
|
MK_COL(255u, 0u, 255u),
|
||||||
|
// MK_COL(0u, 255u, 255u),
|
||||||
|
MK_COL(1u, 2u, 255u),
|
||||||
|
MK_COL(50u, 50u, 50u),
|
||||||
|
MK_COL(1u, 254u, 1u),
|
||||||
|
MK_COL(5u, 5u, 5u),
|
||||||
|
MK_COL(255u, 2u, 1u),
|
||||||
|
MK_COL(9u, 9u, 9u),
|
||||||
|
MK_COL(3u, 3u, 3u),
|
||||||
|
MK_COL(253u, 253u, 253u),
|
||||||
|
// MK_COL(0u, 0u, 1u),
|
||||||
|
// MK_COL(0u, 0u, 255u),
|
||||||
|
MK_COL(2u, 2u, 2u),
|
||||||
|
MK_COL(254u, 254u, 254u),
|
||||||
|
MK_COL(244u, 244u, 244u),
|
||||||
|
MK_COL(255u, 0u, 0u),
|
||||||
|
MK_COL(232u, 232u, 232u),
|
||||||
|
// MK_COL(1u, 1u, 2u),
|
||||||
|
// MK_COL(1u, 0u, 0u),
|
||||||
|
// MK_COL(0u, 0u, 2u),
|
||||||
|
MK_COL(13u, 13u, 13u),
|
||||||
|
// MK_COL(255u, 255u, 0u),
|
||||||
|
MK_COL(23u, 23u, 23u),
|
||||||
|
MK_COL(0u, 255u, 0u),
|
||||||
|
MK_COL(250u, 249u, 253u),
|
||||||
|
MK_COL(2u, 1u, 1u),
|
||||||
|
MK_COL(254u, 254u, 255u),
|
||||||
|
MK_COL(255u, 254u, 254u),
|
||||||
|
MK_COL(254u, 249u, 249u),
|
||||||
|
MK_COL(1u, 2u, 1u),
|
||||||
|
// MK_COL(0u, 1u, 0u),
|
||||||
|
MK_COL(254u, 255u, 254u),
|
||||||
|
MK_COL(2u, 2u, 3u),
|
||||||
|
MK_COL(3u, 2u, 2u),
|
||||||
|
MK_COL(249u, 254u, 249u),
|
||||||
|
MK_COL(251u, 251u, 251u),
|
||||||
|
MK_COL(4u, 4u, 4u),
|
||||||
|
MK_COL(2u, 3u, 2u),
|
||||||
|
// MK_COL(0u, 1u, 255u),
|
||||||
|
MK_COL(0u, 0u, 253u),
|
||||||
|
MK_COL(252u, 252u, 252u),
|
||||||
|
MK_COL(236u, 236u, 236u),
|
||||||
|
MK_COL(255u, 1u, 0u),
|
||||||
|
MK_COL(204u, 204u, 204u),
|
||||||
|
MK_COL(245u, 245u, 250u),
|
||||||
|
// MK_COL(0u, 255u, 1u)
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef MK_COL
|
||||||
|
|
||||||
|
#else // !WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
void delta_palettization_stub(void);
|
||||||
|
void delta_palettization_stub(void) {}
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
22
src/enc/delta_palettization.h
Normal file
22
src/enc/delta_palettization.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef WEBP_ENC_DELTA_PALETTIZATION_H_
|
||||||
|
#define WEBP_ENC_DELTA_PALETTIZATION_H_
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
#define DELTA_PALETTE_SIZE (256 - 10)
|
||||||
|
|
||||||
|
extern const uint32_t kDeltaPalette[DELTA_PALETTE_SIZE];
|
||||||
|
|
||||||
|
// Find palette entry with minimum error from difference of actual pixel value
|
||||||
|
// and predicted pixel value. Propagate error of pixel to its top and left pixel
|
||||||
|
// in src array. Write predicted_value + palette_entry to new_image. Return
|
||||||
|
// index of best palette entry.
|
||||||
|
int FindBestPaletteEntry(int x, int y, const uint32_t* palette,
|
||||||
|
int palette_size, uint32_t* src,
|
||||||
|
int src_stride, uint32_t* new_image);
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
#endif // WEBP_ENC_DELTA_PALETTIZATION_H_
|
@ -21,6 +21,10 @@
|
|||||||
#include "../utils/thread.h"
|
#include "../utils/thread.h"
|
||||||
#include "../webp/encode.h"
|
#include "../webp/encode.h"
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
#include "./vp8li.h"
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
189
src/enc/vp8l.c
189
src/enc/vp8l.c
@ -24,6 +24,8 @@
|
|||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
||||||
|
#include "./delta_palettization.h"
|
||||||
|
|
||||||
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
|
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
|
||||||
// Maximum number of histogram images (sub-blocks).
|
// Maximum number of histogram images (sub-blocks).
|
||||||
#define MAX_HUFF_IMAGE_SIZE 2600
|
#define MAX_HUFF_IMAGE_SIZE 2600
|
||||||
@ -1044,6 +1046,42 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
|||||||
quality);
|
quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
static WebPEncodingError ApplyDeltaPalette(uint32_t* src, uint32_t* dst,
|
||||||
|
uint32_t src_stride,
|
||||||
|
uint32_t dst_stride,
|
||||||
|
const uint32_t* palette,
|
||||||
|
int palette_size,
|
||||||
|
int width, int height,
|
||||||
|
int xbits, uint8_t* row,
|
||||||
|
int num_passes) {
|
||||||
|
int x, y;
|
||||||
|
WebPEncodingError err = VP8_ENC_OK;
|
||||||
|
uint32_t* new_image = (uint32_t*)WebPSafeMalloc(width, sizeof(*new_image));
|
||||||
|
if (new_image == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
while (num_passes--) {
|
||||||
|
uint32_t* cur_src = src;
|
||||||
|
uint32_t* cur_dst = dst;
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
for (x = 0; x < width; ++x) {
|
||||||
|
row[x] = FindBestPaletteEntry(x, y, palette, palette_size, cur_src,
|
||||||
|
src_stride, new_image);
|
||||||
|
}
|
||||||
|
VP8LBundleColorMap(row, width, xbits, cur_dst);
|
||||||
|
cur_src += src_stride;
|
||||||
|
cur_dst += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPSafeFree(new_image);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
|
static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
|
||||||
@ -1210,7 +1248,8 @@ static void ApplyPalette(uint32_t* src, uint32_t* dst,
|
|||||||
// Also, "enc->palette_" will be modified after this call and should not be used
|
// Also, "enc->palette_" will be modified after this call and should not be used
|
||||||
// later.
|
// later.
|
||||||
static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
||||||
VP8LEncoder* const enc) {
|
VP8LEncoder* const enc,
|
||||||
|
int use_delta_palette) {
|
||||||
WebPEncodingError err = VP8_ENC_OK;
|
WebPEncodingError err = VP8_ENC_OK;
|
||||||
int i;
|
int i;
|
||||||
const WebPPicture* const pic = enc->pic_;
|
const WebPPicture* const pic = enc->pic_;
|
||||||
@ -1223,6 +1262,10 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
|||||||
uint8_t* row = NULL;
|
uint8_t* row = NULL;
|
||||||
int xbits;
|
int xbits;
|
||||||
|
|
||||||
|
#ifndef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
(void)use_delta_palette;
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// Replace each input pixel by corresponding palette index.
|
// Replace each input pixel by corresponding palette index.
|
||||||
// This is done line by line.
|
// This is done line by line.
|
||||||
if (palette_size <= 4) {
|
if (palette_size <= 4) {
|
||||||
@ -1238,8 +1281,17 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
|||||||
row = (uint8_t*)WebPSafeMalloc(width, sizeof(*row));
|
row = (uint8_t*)WebPSafeMalloc(width, sizeof(*row));
|
||||||
if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
ApplyPalette(src, dst, pic->argb_stride, enc->current_width_,
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
palette, palette_size, width, height, xbits, row);
|
if (use_delta_palette) {
|
||||||
|
ApplyDeltaPalette(src, dst, pic->argb_stride, enc->current_width_,
|
||||||
|
palette, palette_size, width, height, xbits, row, 2);
|
||||||
|
} else {
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
ApplyPalette(src, dst, pic->argb_stride, enc->current_width_,
|
||||||
|
palette, palette_size, width, height, xbits, row);
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
}
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// Save palette to bitstream.
|
// Save palette to bitstream.
|
||||||
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
|
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
|
||||||
@ -1256,6 +1308,62 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
static WebPEncodingError EncodeDeltaPalettizedImage(VP8LBitWriter* const bw,
|
||||||
|
VP8LEncoder* const enc,
|
||||||
|
int quality) {
|
||||||
|
const WebPPicture* const pic = enc->pic_;
|
||||||
|
uint32_t* src = pic->argb;
|
||||||
|
const int width = pic->width;
|
||||||
|
const int height = pic->height;
|
||||||
|
uint8_t* row = NULL;
|
||||||
|
|
||||||
|
const int pred_bits = 5;
|
||||||
|
const int transform_width = VP8LSubSampleSize(width, pred_bits);
|
||||||
|
const int transform_height = VP8LSubSampleSize(height, pred_bits);
|
||||||
|
const int pred = 7;
|
||||||
|
const int tiles_per_row = VP8LSubSampleSize(width, pred_bits);
|
||||||
|
const int tiles_per_col = VP8LSubSampleSize(height, pred_bits);
|
||||||
|
uint32_t* predictors;
|
||||||
|
int tile_x, tile_y;
|
||||||
|
WebPEncodingError err = VP8_ENC_OK;
|
||||||
|
|
||||||
|
predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row,
|
||||||
|
sizeof(*predictors));
|
||||||
|
if (predictors == NULL) {
|
||||||
|
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
|
||||||
|
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
||||||
|
predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
|
||||||
|
VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
|
||||||
|
VP8LPutBits(bw, pred_bits - 2, 3);
|
||||||
|
err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_,
|
||||||
|
(VP8LBackwardRefs*)enc->refs_, // cast const away
|
||||||
|
transform_width, transform_height,
|
||||||
|
quality);
|
||||||
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
|
|
||||||
|
memcpy(enc->palette_, kDeltaPalette, sizeof(kDeltaPalette));
|
||||||
|
enc->palette_[DELTA_PALETTE_SIZE - 1] = src[0] - 0xff000000u;
|
||||||
|
enc->palette_size_ = DELTA_PALETTE_SIZE;
|
||||||
|
EncodePalette(bw, enc, 1);
|
||||||
|
|
||||||
|
Error:
|
||||||
|
WebPSafeFree(row);
|
||||||
|
WebPSafeFree(predictors);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// VP8LEncoder
|
// VP8LEncoder
|
||||||
|
|
||||||
@ -1324,42 +1432,55 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc->use_palette_) {
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
err = EncodePalette(bw, enc);
|
if (config->delta_palettization) {
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
enc->use_predict_ = 1;
|
||||||
}
|
enc->use_cross_color_ = 0;
|
||||||
|
enc->use_subtract_green_ = 0;
|
||||||
// In case image is not packed.
|
enc->use_palette_ = 1;
|
||||||
if (enc->argb_ == NULL) {
|
EncodeDeltaPalettizedImage(bw, enc, quality);
|
||||||
int y;
|
} else {
|
||||||
err = AllocateTransformBuffer(enc, width, height);
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
if (enc->use_palette_) {
|
||||||
assert(enc->argb_ != NULL);
|
err = EncodePalette(bw, enc, 0);
|
||||||
for (y = 0; y < height; ++y) {
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
memcpy(enc->argb_ + y * width,
|
|
||||||
picture->argb + y * picture->argb_stride,
|
|
||||||
width * sizeof(*enc->argb_));
|
|
||||||
}
|
}
|
||||||
enc->current_width_ = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// In case image is not packed.
|
||||||
// Apply transforms and write transform data.
|
if (enc->argb_ == NULL) {
|
||||||
|
int y;
|
||||||
|
err = AllocateTransformBuffer(enc, width, height);
|
||||||
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
|
assert(enc->argb_ != NULL);
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
memcpy(enc->argb_ + y * width,
|
||||||
|
picture->argb + y * picture->argb_stride,
|
||||||
|
width * sizeof(*enc->argb_));
|
||||||
|
}
|
||||||
|
enc->current_width_ = width;
|
||||||
|
}
|
||||||
|
|
||||||
if (enc->use_subtract_green_) {
|
// -------------------------------------------------------------------------
|
||||||
ApplySubtractGreen(enc, enc->current_width_, height, bw);
|
// Apply transforms and write transform data.
|
||||||
}
|
|
||||||
|
|
||||||
if (enc->use_predict_) {
|
if (enc->use_subtract_green_) {
|
||||||
err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
|
ApplySubtractGreen(enc, enc->current_width_, height, bw);
|
||||||
low_effort, bw);
|
}
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc->use_cross_color_) {
|
if (enc->use_predict_) {
|
||||||
err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw);
|
err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
low_effort, bw);
|
||||||
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc->use_cross_color_) {
|
||||||
|
err = ApplyCrossColorFilter(enc, enc->current_width_,
|
||||||
|
height, quality, bw);
|
||||||
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
|
}
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
}
|
}
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms.
|
VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms.
|
||||||
|
|
||||||
@ -1415,7 +1536,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
|
|||||||
// Initialize BitWriter with size corresponding to 16 bpp to photo images and
|
// Initialize BitWriter with size corresponding to 16 bpp to photo images and
|
||||||
// 8 bpp for graphical images.
|
// 8 bpp for graphical images.
|
||||||
initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
|
initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
|
||||||
width * height : width * height * 2;
|
width * height : width * height * 2;
|
||||||
if (!VP8LBitWriterInit(&bw, initial_size)) {
|
if (!VP8LBitWriterInit(&bw, initial_size)) {
|
||||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||||
goto Error;
|
goto Error;
|
||||||
|
@ -137,7 +137,12 @@ struct WebPConfig {
|
|||||||
int near_lossless; // Near lossless encoding [0 = off(default) .. 100].
|
int near_lossless; // Near lossless encoding [0 = off(default) .. 100].
|
||||||
// This feature is experimental.
|
// This feature is experimental.
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
int delta_palettization;
|
||||||
|
uint32_t pad[3]; // padding for later use
|
||||||
|
#else
|
||||||
uint32_t pad[4]; // padding for later use
|
uint32_t pad[4]; // padding for later use
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enumerate some predefined settings for WebPConfig, depending on the type
|
// Enumerate some predefined settings for WebPConfig, depending on the type
|
||||||
|
Loading…
x
Reference in New Issue
Block a user