lossy decoding: correct alpha-rescaling for YUVA format
The luminance needs to be pre- and post- multiplied by the alpha value in case of rescaling, for proper averaging. Also: - removed util/alpha_processing and moved it to dsp/ - removed WebPInitPremultiply() which was mostly useless and merged it with the new function WebPInitAlphaProcessing() Change-Id: If089cefd4ec53f6880a791c476fb1c7f7c5a8e60
This commit is contained in:
parent
78c12ed8e6
commit
399b916d27
@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
|
|||||||
src/dec/vp8.c \
|
src/dec/vp8.c \
|
||||||
src/dec/vp8l.c \
|
src/dec/vp8l.c \
|
||||||
src/dec/webp.c \
|
src/dec/webp.c \
|
||||||
|
src/dsp/alpha_processing.c \
|
||||||
src/dsp/cpu.c \
|
src/dsp/cpu.c \
|
||||||
src/dsp/dec.c \
|
src/dsp/dec.c \
|
||||||
src/dsp/dec_clip_tables.c \
|
src/dsp/dec_clip_tables.c \
|
||||||
@ -68,7 +69,6 @@ LOCAL_SRC_FILES := \
|
|||||||
src/enc/tree.c \
|
src/enc/tree.c \
|
||||||
src/enc/vp8l.c \
|
src/enc/vp8l.c \
|
||||||
src/enc/webpenc.c \
|
src/enc/webpenc.c \
|
||||||
src/utils/alpha_processing.c \
|
|
||||||
src/utils/bit_reader.c \
|
src/utils/bit_reader.c \
|
||||||
src/utils/bit_writer.c \
|
src/utils/bit_writer.c \
|
||||||
src/utils/color_cache.c \
|
src/utils/color_cache.c \
|
||||||
|
@ -170,6 +170,7 @@ DEMUX_OBJS = \
|
|||||||
$(DIROBJ)\demux\demux.obj \
|
$(DIROBJ)\demux\demux.obj \
|
||||||
|
|
||||||
DSP_DEC_OBJS = \
|
DSP_DEC_OBJS = \
|
||||||
|
$(DIROBJ)\dsp\alpha_processing.obj \
|
||||||
$(DIROBJ)\dsp\cpu.obj \
|
$(DIROBJ)\dsp\cpu.obj \
|
||||||
$(DIROBJ)\dsp\dec.obj \
|
$(DIROBJ)\dsp\dec.obj \
|
||||||
$(DIROBJ)\dsp\dec_clip_tables.obj \
|
$(DIROBJ)\dsp\dec_clip_tables.obj \
|
||||||
@ -228,7 +229,6 @@ MUX_OBJS = \
|
|||||||
$(DIROBJ)\mux\muxread.obj \
|
$(DIROBJ)\mux\muxread.obj \
|
||||||
|
|
||||||
UTILS_DEC_OBJS = \
|
UTILS_DEC_OBJS = \
|
||||||
$(DIROBJ)\utils\alpha_processing.obj \
|
|
||||||
$(DIROBJ)\utils\bit_reader.obj \
|
$(DIROBJ)\utils\bit_reader.obj \
|
||||||
$(DIROBJ)\utils\color_cache.obj \
|
$(DIROBJ)\utils\color_cache.obj \
|
||||||
$(DIROBJ)\utils\filters.obj \
|
$(DIROBJ)\utils\filters.obj \
|
||||||
|
@ -106,6 +106,7 @@ DEMUX_OBJS = \
|
|||||||
src/demux/demux.o \
|
src/demux/demux.o \
|
||||||
|
|
||||||
DSP_DEC_OBJS = \
|
DSP_DEC_OBJS = \
|
||||||
|
src/dsp/alpha_processing.o \
|
||||||
src/dsp/cpu.o \
|
src/dsp/cpu.o \
|
||||||
src/dsp/dec.o \
|
src/dsp/dec.o \
|
||||||
src/dsp/dec_clip_tables.o \
|
src/dsp/dec_clip_tables.o \
|
||||||
@ -166,7 +167,6 @@ MUX_OBJS = \
|
|||||||
src/mux/muxread.o \
|
src/mux/muxread.o \
|
||||||
|
|
||||||
UTILS_DEC_OBJS = \
|
UTILS_DEC_OBJS = \
|
||||||
src/utils/alpha_processing.o \
|
|
||||||
src/utils/bit_reader.o \
|
src/utils/bit_reader.o \
|
||||||
src/utils/color_cache.o \
|
src/utils/color_cache.o \
|
||||||
src/utils/filters.o \
|
src/utils/filters.o \
|
||||||
@ -213,7 +213,6 @@ HDRS = \
|
|||||||
src/enc/vp8enci.h \
|
src/enc/vp8enci.h \
|
||||||
src/enc/vp8li.h \
|
src/enc/vp8li.h \
|
||||||
src/mux/muxi.h \
|
src/mux/muxi.h \
|
||||||
src/utils/alpha_processing.h \
|
|
||||||
src/utils/bit_reader.h \
|
src/utils/bit_reader.h \
|
||||||
src/utils/bit_writer.h \
|
src/utils/bit_writer.h \
|
||||||
src/utils/color_cache.h \
|
src/utils/color_cache.h \
|
||||||
|
36
src/dec/io.c
36
src/dec/io.c
@ -280,7 +280,17 @@ static int Rescale(const uint8_t* src, int src_stride,
|
|||||||
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
const int mb_h = io->mb_h;
|
const int mb_h = io->mb_h;
|
||||||
const int uv_mb_h = (mb_h + 1) >> 1;
|
const int uv_mb_h = (mb_h + 1) >> 1;
|
||||||
const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y);
|
WebPRescaler* const scaler = &p->scaler_y;
|
||||||
|
int num_lines_out = 0;
|
||||||
|
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
|
||||||
|
// Before rescaling, we premultiply the luma directly into the io->y
|
||||||
|
// internal buffer. This is OK since these samples are not used for
|
||||||
|
// intra-prediction (the top samples are saved in cache_y_/u_/v_).
|
||||||
|
// But we need to cast the const away, though.
|
||||||
|
WebPMultRows((uint8_t*)io->y, io->y_stride,
|
||||||
|
io->a, io->width, io->mb_w, mb_h, 0);
|
||||||
|
}
|
||||||
|
num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
|
||||||
Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
|
Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
|
||||||
Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
|
Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
@ -288,7 +298,14 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
|
|
||||||
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
|
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
if (io->a != NULL) {
|
if (io->a != NULL) {
|
||||||
Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
|
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
|
||||||
|
uint8_t* dst_y = buf->y + p->last_y * buf->y_stride;
|
||||||
|
const uint8_t* src_a = buf->a + p->last_y * buf->a_stride;
|
||||||
|
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
|
||||||
|
if (num_lines_out > 0) { // unmultiply the Y
|
||||||
|
WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride,
|
||||||
|
p->scaler_a.dst_width, num_lines_out, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -307,11 +324,11 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
size_t tmp_size;
|
size_t tmp_size;
|
||||||
int32_t* work;
|
int32_t* work;
|
||||||
|
|
||||||
tmp_size = work_size + 2 * uv_work_size;
|
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
tmp_size += work_size;
|
tmp_size += work_size * sizeof(*work);
|
||||||
}
|
}
|
||||||
p->memory = WebPSafeCalloc(1ULL, tmp_size * sizeof(*work));
|
p->memory = WebPSafeCalloc(1ULL, tmp_size);
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
@ -338,6 +355,7 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
io->mb_w, out_width, io->mb_h, out_height,
|
io->mb_w, out_width, io->mb_h, out_height,
|
||||||
work + work_size + 2 * uv_work_size);
|
work + work_size + 2 * uv_work_size);
|
||||||
p->emit_alpha = EmitRescaledAlphaYUV;
|
p->emit_alpha = EmitRescaledAlphaYUV;
|
||||||
|
WebPInitAlphaProcessing();
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -520,6 +538,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
} else {
|
} else {
|
||||||
p->emit_alpha_row = ExportAlpha;
|
p->emit_alpha_row = ExportAlpha;
|
||||||
}
|
}
|
||||||
|
WebPInitAlphaProcessing();
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -540,7 +559,9 @@ static int CustomSetup(VP8Io* io) {
|
|||||||
if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
|
if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (is_alpha && WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
|
if (is_alpha && WebPIsPremultipliedMode(colorspace)) {
|
||||||
|
WebPInitUpsamplers();
|
||||||
|
}
|
||||||
if (io->use_scaling) {
|
if (io->use_scaling) {
|
||||||
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
|
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -574,6 +595,9 @@ static int CustomSetup(VP8Io* io) {
|
|||||||
EmitAlphaRGBA4444
|
EmitAlphaRGBA4444
|
||||||
: is_rgb ? EmitAlphaRGB
|
: is_rgb ? EmitAlphaRGB
|
||||||
: EmitAlphaYUV;
|
: EmitAlphaYUV;
|
||||||
|
if (is_rgb) {
|
||||||
|
WebPInitAlphaProcessing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#include "./alphai.h"
|
#include "./alphai.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li.h"
|
||||||
|
#include "../dsp/dsp.h"
|
||||||
#include "../dsp/lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
#include "../dsp/yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
#include "../utils/alpha_processing.h"
|
|
||||||
#include "../utils/huffman.h"
|
#include "../utils/huffman.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
@ -412,6 +412,7 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
|||||||
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
|
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
|
||||||
out_width, out_height, 0, num_channels,
|
out_width, out_height, 0, num_channels,
|
||||||
in_width, out_width, in_height, out_height, work);
|
in_width, out_width, in_height, out_height, work);
|
||||||
|
WebPInitAlphaProcessing(); // needed for pre/post multiply with alpha
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,6 +475,7 @@ static int EmitRows(WEBP_CSP_MODE colorspace,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Export to YUVA
|
// Export to YUVA
|
||||||
|
|
||||||
|
// TODO(skal): should be in yuv.c
|
||||||
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
|
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
|
||||||
const WebPDecBuffer* const output) {
|
const WebPDecBuffer* const output) {
|
||||||
const WebPYUVABuffer* const buf = &output->u.YUVA;
|
const WebPYUVABuffer* const buf = &output->u.YUVA;
|
||||||
|
@ -9,6 +9,7 @@ common_HEADERS = ../webp/types.h
|
|||||||
commondir = $(includedir)/webp
|
commondir = $(includedir)/webp
|
||||||
|
|
||||||
COMMON_SOURCES =
|
COMMON_SOURCES =
|
||||||
|
COMMON_SOURCES += alpha_processing.c
|
||||||
COMMON_SOURCES += cpu.c
|
COMMON_SOURCES += cpu.c
|
||||||
COMMON_SOURCES += dec.c
|
COMMON_SOURCES += dec.c
|
||||||
COMMON_SOURCES += dec_clip_tables.c
|
COMMON_SOURCES += dec_clip_tables.c
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "./alpha_processing.h"
|
#include "./dsp.h"
|
||||||
|
|
||||||
// Tables can be faster on some platform but incur some extra binary size (~2k).
|
// Tables can be faster on some platform but incur some extra binary size (~2k).
|
||||||
// #define USE_TABLES_FOR_ALPHA_MULT
|
// #define USE_TABLES_FOR_ALPHA_MULT
|
||||||
@ -134,7 +134,7 @@ static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
|
|||||||
|
|
||||||
#endif // USE_TABLES_FOR_ALPHA_MULT
|
#endif // USE_TABLES_FOR_ALPHA_MULT
|
||||||
|
|
||||||
void WebPMultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
const uint32_t argb = ptr[x];
|
const uint32_t argb = ptr[x];
|
||||||
@ -154,16 +154,7 @@ void WebPMultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
int inverse) {
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < num_rows; ++n) {
|
|
||||||
WebPMultARGBRow((uint32_t*)ptr, width, inverse);
|
|
||||||
ptr += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebPMultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
|
||||||
int width, int inverse) {
|
int width, int inverse) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
@ -179,6 +170,26 @@ void WebPMultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef KINV_255
|
||||||
|
#undef HALF
|
||||||
|
#undef MFIX
|
||||||
|
|
||||||
|
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
|
||||||
|
void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
|
int width, int inverse);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Generic per-plane calls
|
||||||
|
|
||||||
|
void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
||||||
|
int inverse) {
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < num_rows; ++n) {
|
||||||
|
WebPMultARGBRow((uint32_t*)ptr, width, inverse);
|
||||||
|
ptr += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WebPMultRows(uint8_t* ptr, int stride,
|
void WebPMultRows(uint8_t* ptr, int stride,
|
||||||
const uint8_t* alpha, int alpha_stride,
|
const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int num_rows, int inverse) {
|
int width, int num_rows, int inverse) {
|
||||||
@ -190,7 +201,98 @@ void WebPMultRows(uint8_t* ptr, int stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef KINV_255
|
//------------------------------------------------------------------------------
|
||||||
#undef HALF
|
// Premultiplied modes
|
||||||
#undef MFIX
|
|
||||||
|
|
||||||
|
// non dithered-modes
|
||||||
|
|
||||||
|
// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
|
||||||
|
// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
|
||||||
|
// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
|
||||||
|
#if 1 // (int)(x * a / 255.)
|
||||||
|
#define MULTIPLIER(a) ((a) * 32897U)
|
||||||
|
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
|
||||||
|
#else // (int)(x * a / 255. + .5)
|
||||||
|
#define MULTIPLIER(a) ((a) * 65793U)
|
||||||
|
#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
||||||
|
int w, int h, int stride) {
|
||||||
|
while (h-- > 0) {
|
||||||
|
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
|
||||||
|
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < w; ++i) {
|
||||||
|
const uint32_t a = alpha[4 * i];
|
||||||
|
if (a != 0xff) {
|
||||||
|
const uint32_t mult = MULTIPLIER(a);
|
||||||
|
rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
|
||||||
|
rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
|
||||||
|
rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rgba += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef MULTIPLIER
|
||||||
|
#undef PREMULTIPLY
|
||||||
|
|
||||||
|
// rgbA4444
|
||||||
|
|
||||||
|
#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
|
||||||
|
|
||||||
|
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
|
||||||
|
return (x & 0xf0) | (x >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
|
||||||
|
return (x & 0x0f) | (x << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
|
||||||
|
return (x * m) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
||||||
|
int w, int h, int stride,
|
||||||
|
int rg_byte_pos /* 0 or 1 */) {
|
||||||
|
while (h-- > 0) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < w; ++i) {
|
||||||
|
const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
|
||||||
|
const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
|
||||||
|
const uint8_t a = ba & 0x0f;
|
||||||
|
const uint32_t mult = MULTIPLIER(a);
|
||||||
|
const uint8_t r = multiply(dither_hi(rg), mult);
|
||||||
|
const uint8_t g = multiply(dither_lo(rg), mult);
|
||||||
|
const uint8_t b = multiply(dither_hi(ba), mult);
|
||||||
|
rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
|
||||||
|
rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
|
||||||
|
}
|
||||||
|
rgba4444 += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef MULTIPLIER
|
||||||
|
|
||||||
|
static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
|
||||||
|
int w, int h, int stride) {
|
||||||
|
#ifdef WEBP_SWAP_16BIT_CSP
|
||||||
|
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
|
||||||
|
#else
|
||||||
|
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
||||||
|
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Init function
|
||||||
|
|
||||||
|
void WebPInitAlphaProcessing(void) {
|
||||||
|
WebPMultARGBRow = MultARGBRow;
|
||||||
|
WebPMultRow = MultRow;
|
||||||
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
||||||
|
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
|
||||||
|
}
|
@ -218,12 +218,14 @@ typedef void (*WebPYUV444Converter)(const uint8_t* y,
|
|||||||
|
|
||||||
extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
||||||
|
|
||||||
// Main functions to be called
|
// Must be called before using the WebPUpsamplers[] (and for premultiplied
|
||||||
|
// colorspaces like rgbA, rgbA4444, etc)
|
||||||
void WebPInitUpsamplers(void);
|
void WebPInitUpsamplers(void);
|
||||||
|
// Must be called before using WebPSamplers[]
|
||||||
void WebPInitSamplers(void);
|
void WebPInitSamplers(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Pre-multiply planes with alpha values
|
// Utilities for processing transparent channel.
|
||||||
|
|
||||||
// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
|
// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
|
||||||
// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
|
// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
|
||||||
@ -234,10 +236,27 @@ extern void (*WebPApplyAlphaMultiply)(
|
|||||||
extern void (*WebPApplyAlphaMultiply4444)(
|
extern void (*WebPApplyAlphaMultiply4444)(
|
||||||
uint8_t* rgba4444, int w, int h, int stride);
|
uint8_t* rgba4444, int w, int h, int stride);
|
||||||
|
|
||||||
// To be called first before using the above.
|
// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
|
||||||
void WebPInitPremultiply(void);
|
// Un-Multiply operation transforms x into x * 255 / A.
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
// Pre-Multiply or Un-Multiply (if 'inverse' is true) argb values in a row.
|
||||||
|
extern void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
|
||||||
|
|
||||||
|
// Same a WebPMultARGBRow(), but for several rows.
|
||||||
|
void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
||||||
|
int inverse);
|
||||||
|
|
||||||
|
// Same for a row of single values, with side alpha values.
|
||||||
|
extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
|
int width, int inverse);
|
||||||
|
|
||||||
|
// Same a WebPMultRow(), but for several 'num_rows' rows.
|
||||||
|
void WebPMultRows(uint8_t* ptr, int stride,
|
||||||
|
const uint8_t* alpha, int alpha_stride,
|
||||||
|
int width, int num_rows, int inverse);
|
||||||
|
|
||||||
|
// To be called first before using the above.
|
||||||
|
void WebPInitAlphaProcessing(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -183,92 +183,6 @@ const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
|
|||||||
Yuv444ToRgba4444 // MODE_rgbA_4444
|
Yuv444ToRgba4444 // MODE_rgbA_4444
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Premultiplied modes
|
|
||||||
|
|
||||||
// non dithered-modes
|
|
||||||
|
|
||||||
// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
|
|
||||||
// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
|
|
||||||
// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
|
|
||||||
#if 1 // (int)(x * a / 255.)
|
|
||||||
#define MULTIPLIER(a) ((a) * 32897UL)
|
|
||||||
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
|
|
||||||
#else // (int)(x * a / 255. + .5)
|
|
||||||
#define MULTIPLIER(a) ((a) * 65793UL)
|
|
||||||
#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
|
||||||
int w, int h, int stride) {
|
|
||||||
while (h-- > 0) {
|
|
||||||
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
|
|
||||||
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < w; ++i) {
|
|
||||||
const uint32_t a = alpha[4 * i];
|
|
||||||
if (a != 0xff) {
|
|
||||||
const uint32_t mult = MULTIPLIER(a);
|
|
||||||
rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
|
|
||||||
rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
|
|
||||||
rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rgba += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#undef MULTIPLIER
|
|
||||||
#undef PREMULTIPLY
|
|
||||||
|
|
||||||
// rgbA4444
|
|
||||||
|
|
||||||
#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
|
|
||||||
|
|
||||||
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
|
|
||||||
return (x & 0xf0) | (x >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
|
|
||||||
return (x & 0x0f) | (x << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
|
|
||||||
return (x * m) >> 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
|
||||||
int w, int h, int stride,
|
|
||||||
int rg_byte_pos /* 0 or 1 */) {
|
|
||||||
while (h-- > 0) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < w; ++i) {
|
|
||||||
const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
|
|
||||||
const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
|
|
||||||
const uint8_t a = ba & 0x0f;
|
|
||||||
const uint32_t mult = MULTIPLIER(a);
|
|
||||||
const uint8_t r = multiply(dither_hi(rg), mult);
|
|
||||||
const uint8_t g = multiply(dither_lo(rg), mult);
|
|
||||||
const uint8_t b = multiply(dither_hi(ba), mult);
|
|
||||||
rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
|
|
||||||
rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
|
|
||||||
}
|
|
||||||
rgba4444 += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#undef MULTIPLIER
|
|
||||||
|
|
||||||
static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
|
|
||||||
int w, int h, int stride) {
|
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
|
||||||
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
|
|
||||||
#else
|
|
||||||
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
|
||||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Main calls
|
// Main calls
|
||||||
|
|
||||||
@ -284,6 +198,10 @@ void WebPInitUpsamplers(void) {
|
|||||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
||||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
||||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
||||||
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
||||||
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
||||||
|
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
|
||||||
|
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
@ -302,33 +220,3 @@ void WebPInitUpsamplers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
extern void WebPInitPremultiplySSE2(void);
|
|
||||||
extern void WebPInitPremultiplyNEON(void);
|
|
||||||
|
|
||||||
void WebPInitPremultiply(void) {
|
|
||||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
|
||||||
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
|
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
|
||||||
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
|
|
||||||
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
|
|
||||||
|
|
||||||
if (VP8GetCPUInfo != NULL) {
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
|
||||||
if (VP8GetCPUInfo(kSSE2)) {
|
|
||||||
WebPInitPremultiplySSE2();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
WebPInitPremultiplyNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif // FANCY_UPSAMPLING
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
@ -237,7 +237,6 @@ NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair, Bgra, 4)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
extern void WebPInitUpsamplersNEON(void);
|
extern void WebPInitUpsamplersNEON(void);
|
||||||
extern void WebPInitPremultiplyNEON(void);
|
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
@ -249,11 +248,6 @@ void WebPInitUpsamplersNEON(void) {
|
|||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||||
#endif // WEBP_USE_NEON
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebPInitPremultiplyNEON(void) {
|
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
||||||
#endif // WEBP_USE_NEON
|
#endif // WEBP_USE_NEON
|
||||||
@ -262,6 +256,6 @@ void WebPInitPremultiplyNEON(void) {
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
// this empty function is to avoid an empty .o
|
// this empty function is to avoid an empty .o
|
||||||
void WebPInitPremultiplyNEON(void) {}
|
void WebPInitUpsamplersNEON(void) {}
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
#endif // FANCY_UPSAMPLING
|
||||||
|
@ -189,7 +189,6 @@ SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
extern void WebPInitUpsamplersSSE2(void);
|
extern void WebPInitUpsamplersSSE2(void);
|
||||||
extern void WebPInitPremultiplySSE2(void);
|
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
@ -202,11 +201,6 @@ void WebPInitUpsamplersSSE2(void) {
|
|||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||||
#endif // WEBP_USE_SSE2
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebPInitPremultiplySSE2(void) {
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
@ -215,6 +209,6 @@ void WebPInitPremultiplySSE2(void) {
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
// this empty function is to avoid an empty .o
|
// this empty function is to avoid an empty .o
|
||||||
void WebPInitPremultiplySSE2(void) {}
|
void WebPInitUpsamplersSSE2(void) {}
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
#endif // FANCY_UPSAMPLING
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "./vp8enci.h"
|
#include "./vp8enci.h"
|
||||||
#include "../utils/alpha_processing.h"
|
|
||||||
#include "../utils/random.h"
|
#include "../utils/random.h"
|
||||||
#include "../utils/rescaler.h"
|
#include "../utils/rescaler.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
@ -402,24 +401,15 @@ static void RescalePlane(const uint8_t* src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
|
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
|
||||||
uint32_t* ptr = pic->argb;
|
assert(pic->argb != NULL);
|
||||||
int y;
|
WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
|
||||||
for (y = 0; y < pic->height; ++y) {
|
pic->width, pic->height, inverse);
|
||||||
WebPMultARGBRow(ptr, pic->width, inverse);
|
|
||||||
ptr += pic->argb_stride;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
|
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
|
||||||
const uint8_t* ptr_a = pic->a;
|
if (pic->a != NULL) {
|
||||||
if (ptr_a != NULL) {
|
WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
|
||||||
uint8_t* ptr_y = pic->y;
|
pic->width, pic->height, inverse);
|
||||||
int y;
|
|
||||||
for (y = 0; y < pic->height; ++y) {
|
|
||||||
WebPMultRow(ptr_y, ptr_a, pic->width, inverse);
|
|
||||||
ptr_y += pic->y_stride;
|
|
||||||
ptr_a += pic->a_stride;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,6 +445,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
|||||||
}
|
}
|
||||||
// If present, we need to rescale alpha first (for AlphaMultiplyY).
|
// If present, we need to rescale alpha first (for AlphaMultiplyY).
|
||||||
if (pic->a != NULL) {
|
if (pic->a != NULL) {
|
||||||
|
WebPInitAlphaProcessing();
|
||||||
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
||||||
tmp.a, width, height, tmp.a_stride, work, 1);
|
tmp.a, width, height, tmp.a_stride, work, 1);
|
||||||
}
|
}
|
||||||
@ -495,6 +486,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
|||||||
// In order to correctly interpolate colors, we need to apply the alpha
|
// In order to correctly interpolate colors, we need to apply the alpha
|
||||||
// weighting first (black-matting), scale the RGB values, and remove
|
// weighting first (black-matting), scale the RGB values, and remove
|
||||||
// the premultiplication afterward (while preserving the alpha channel).
|
// the premultiplication afterward (while preserving the alpha channel).
|
||||||
|
WebPInitAlphaProcessing();
|
||||||
AlphaMultiplyARGB(pic, 0);
|
AlphaMultiplyARGB(pic, 0);
|
||||||
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
||||||
pic->argb_stride * 4,
|
pic->argb_stride * 4,
|
||||||
@ -1367,4 +1359,3 @@ LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
|
|||||||
#undef LOSSLESS_ENCODE_FUNC
|
#undef LOSSLESS_ENCODE_FUNC
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ common_HEADERS = ../webp/types.h
|
|||||||
commondir = $(includedir)/webp
|
commondir = $(includedir)/webp
|
||||||
|
|
||||||
COMMON_SOURCES =
|
COMMON_SOURCES =
|
||||||
COMMON_SOURCES += alpha_processing.c
|
|
||||||
COMMON_SOURCES += alpha_processing.h
|
|
||||||
COMMON_SOURCES += bit_reader.c
|
COMMON_SOURCES += bit_reader.c
|
||||||
COMMON_SOURCES += bit_reader.h
|
COMMON_SOURCES += bit_reader.h
|
||||||
COMMON_SOURCES += color_cache.c
|
COMMON_SOURCES += color_cache.c
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Use of this source code is governed by a BSD-style license
|
|
||||||
// that can be found in the COPYING file in the root of the source
|
|
||||||
// tree. An additional intellectual property rights grant can be found
|
|
||||||
// in the file PATENTS. All contributing project authors may
|
|
||||||
// be found in the AUTHORS file in the root of the source tree.
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Utilities for processing transparent channel.
|
|
||||||
//
|
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_ALPHA_PROCESSING_H_
|
|
||||||
#define WEBP_UTILS_ALPHA_PROCESSING_H_
|
|
||||||
|
|
||||||
#include "../webp/types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
|
|
||||||
// Un-Multiply operation transforms x into x * 255 / A.
|
|
||||||
|
|
||||||
// Pre-Multiply or Un-Multiply (if 'inverse' is true) argb values in a row.
|
|
||||||
void WebPMultARGBRow(uint32_t* const ptr, int width, int inverse);
|
|
||||||
|
|
||||||
// Same a WebPMultARGBRow(), but for several rows.
|
|
||||||
void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
|
||||||
int inverse);
|
|
||||||
|
|
||||||
// Same for a row of single values, with side alpha values.
|
|
||||||
void WebPMultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
|
||||||
int width, int inverse);
|
|
||||||
|
|
||||||
// Same a WebPMultRow(), but for several 'num_rows' rows.
|
|
||||||
void WebPMultRows(uint8_t* ptr, int stride,
|
|
||||||
const uint8_t* alpha, int alpha_stride,
|
|
||||||
int width, int num_rows, int inverse);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // WEBP_UTILS_ALPHA_PROCESSING_H_
|
|
Loading…
x
Reference in New Issue
Block a user