mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
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/vp8l.c \
|
||||
src/dec/webp.c \
|
||||
src/dsp/alpha_processing.c \
|
||||
src/dsp/cpu.c \
|
||||
src/dsp/dec.c \
|
||||
src/dsp/dec_clip_tables.c \
|
||||
@ -68,7 +69,6 @@ LOCAL_SRC_FILES := \
|
||||
src/enc/tree.c \
|
||||
src/enc/vp8l.c \
|
||||
src/enc/webpenc.c \
|
||||
src/utils/alpha_processing.c \
|
||||
src/utils/bit_reader.c \
|
||||
src/utils/bit_writer.c \
|
||||
src/utils/color_cache.c \
|
||||
|
@ -170,6 +170,7 @@ DEMUX_OBJS = \
|
||||
$(DIROBJ)\demux\demux.obj \
|
||||
|
||||
DSP_DEC_OBJS = \
|
||||
$(DIROBJ)\dsp\alpha_processing.obj \
|
||||
$(DIROBJ)\dsp\cpu.obj \
|
||||
$(DIROBJ)\dsp\dec.obj \
|
||||
$(DIROBJ)\dsp\dec_clip_tables.obj \
|
||||
@ -228,7 +229,6 @@ MUX_OBJS = \
|
||||
$(DIROBJ)\mux\muxread.obj \
|
||||
|
||||
UTILS_DEC_OBJS = \
|
||||
$(DIROBJ)\utils\alpha_processing.obj \
|
||||
$(DIROBJ)\utils\bit_reader.obj \
|
||||
$(DIROBJ)\utils\color_cache.obj \
|
||||
$(DIROBJ)\utils\filters.obj \
|
||||
|
@ -106,6 +106,7 @@ DEMUX_OBJS = \
|
||||
src/demux/demux.o \
|
||||
|
||||
DSP_DEC_OBJS = \
|
||||
src/dsp/alpha_processing.o \
|
||||
src/dsp/cpu.o \
|
||||
src/dsp/dec.o \
|
||||
src/dsp/dec_clip_tables.o \
|
||||
@ -166,7 +167,6 @@ MUX_OBJS = \
|
||||
src/mux/muxread.o \
|
||||
|
||||
UTILS_DEC_OBJS = \
|
||||
src/utils/alpha_processing.o \
|
||||
src/utils/bit_reader.o \
|
||||
src/utils/color_cache.o \
|
||||
src/utils/filters.o \
|
||||
@ -213,7 +213,6 @@ HDRS = \
|
||||
src/enc/vp8enci.h \
|
||||
src/enc/vp8li.h \
|
||||
src/mux/muxi.h \
|
||||
src/utils/alpha_processing.h \
|
||||
src/utils/bit_reader.h \
|
||||
src/utils/bit_writer.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) {
|
||||
const int mb_h = io->mb_h;
|
||||
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->v, io->uv_stride, uv_mb_h, &p->scaler_v);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
@ -307,11 +324,11 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
size_t tmp_size;
|
||||
int32_t* work;
|
||||
|
||||
tmp_size = work_size + 2 * uv_work_size;
|
||||
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
||||
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) {
|
||||
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,
|
||||
work + work_size + 2 * uv_work_size);
|
||||
p->emit_alpha = EmitRescaledAlphaYUV;
|
||||
WebPInitAlphaProcessing();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -520,6 +538,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
} else {
|
||||
p->emit_alpha_row = ExportAlpha;
|
||||
}
|
||||
WebPInitAlphaProcessing();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -540,7 +559,9 @@ static int CustomSetup(VP8Io* io) {
|
||||
if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
|
||||
return 0;
|
||||
}
|
||||
if (is_alpha && WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
|
||||
if (is_alpha && WebPIsPremultipliedMode(colorspace)) {
|
||||
WebPInitUpsamplers();
|
||||
}
|
||||
if (io->use_scaling) {
|
||||
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
|
||||
if (!ok) {
|
||||
@ -574,6 +595,9 @@ static int CustomSetup(VP8Io* io) {
|
||||
EmitAlphaRGBA4444
|
||||
: is_rgb ? EmitAlphaRGB
|
||||
: EmitAlphaYUV;
|
||||
if (is_rgb) {
|
||||
WebPInitAlphaProcessing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#include "./alphai.h"
|
||||
#include "./vp8li.h"
|
||||
#include "../dsp/dsp.h"
|
||||
#include "../dsp/lossless.h"
|
||||
#include "../dsp/yuv.h"
|
||||
#include "../utils/alpha_processing.h"
|
||||
#include "../utils/huffman.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,
|
||||
out_width, out_height, 0, num_channels,
|
||||
in_width, out_width, in_height, out_height, work);
|
||||
WebPInitAlphaProcessing(); // needed for pre/post multiply with alpha
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -474,6 +475,7 @@ static int EmitRows(WEBP_CSP_MODE colorspace,
|
||||
//------------------------------------------------------------------------------
|
||||
// Export to YUVA
|
||||
|
||||
// TODO(skal): should be in yuv.c
|
||||
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
|
||||
const WebPDecBuffer* const output) {
|
||||
const WebPYUVABuffer* const buf = &output->u.YUVA;
|
||||
|
@ -9,6 +9,7 @@ common_HEADERS = ../webp/types.h
|
||||
commondir = $(includedir)/webp
|
||||
|
||||
COMMON_SOURCES =
|
||||
COMMON_SOURCES += alpha_processing.c
|
||||
COMMON_SOURCES += cpu.c
|
||||
COMMON_SOURCES += dec.c
|
||||
COMMON_SOURCES += dec_clip_tables.c
|
||||
|
@ -12,7 +12,7 @@
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include "./alpha_processing.h"
|
||||
#include "./dsp.h"
|
||||
|
||||
// Tables can be faster on some platform but incur some extra binary size (~2k).
|
||||
// #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
|
||||
|
||||
void WebPMultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
||||
static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
const uint32_t argb = ptr[x];
|
||||
@ -154,17 +154,8 @@ void WebPMultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
||||
}
|
||||
}
|
||||
|
||||
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 WebPMultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse) {
|
||||
static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
const uint32_t a = alpha[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,
|
||||
const uint8_t* alpha, int alpha_stride,
|
||||
int width, int num_rows, int inverse) {
|
||||
@ -190,7 +201,98 @@ void WebPMultRows(uint8_t* ptr, int stride,
|
||||
}
|
||||
}
|
||||
|
||||
#undef KINV_255
|
||||
#undef HALF
|
||||
#undef MFIX
|
||||
//------------------------------------------------------------------------------
|
||||
// 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) * 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 */];
|
||||
|
||||
// Main functions to be called
|
||||
// Must be called before using the WebPUpsamplers[] (and for premultiplied
|
||||
// colorspaces like rgbA, rgbA4444, etc)
|
||||
void WebPInitUpsamplers(void);
|
||||
// Must be called before using WebPSamplers[]
|
||||
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.
|
||||
// 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)(
|
||||
uint8_t* rgba4444, int w, int h, int stride);
|
||||
|
||||
// To be called first before using the above.
|
||||
void WebPInitPremultiply(void);
|
||||
// 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.
|
||||
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
|
||||
} // extern "C"
|
||||
|
@ -183,92 +183,6 @@ const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
|
||||
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
|
||||
|
||||
@ -284,6 +198,10 @@ void WebPInitUpsamplers(void) {
|
||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
||||
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 (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 WebPInitPremultiplyNEON(void);
|
||||
|
||||
#ifdef FANCY_UPSAMPLING
|
||||
|
||||
@ -249,11 +248,6 @@ void WebPInitUpsamplersNEON(void) {
|
||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||
#endif // WEBP_USE_NEON
|
||||
}
|
||||
|
||||
void WebPInitPremultiplyNEON(void) {
|
||||
#if defined(WEBP_USE_NEON)
|
||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
||||
#endif // WEBP_USE_NEON
|
||||
@ -262,6 +256,6 @@ void WebPInitPremultiplyNEON(void) {
|
||||
#else
|
||||
|
||||
// this empty function is to avoid an empty .o
|
||||
void WebPInitPremultiplyNEON(void) {}
|
||||
void WebPInitUpsamplersNEON(void) {}
|
||||
|
||||
#endif // FANCY_UPSAMPLING
|
||||
|
@ -189,7 +189,6 @@ SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void WebPInitUpsamplersSSE2(void);
|
||||
extern void WebPInitPremultiplySSE2(void);
|
||||
|
||||
#ifdef FANCY_UPSAMPLING
|
||||
|
||||
@ -202,11 +201,6 @@ void WebPInitUpsamplersSSE2(void) {
|
||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||
#endif // WEBP_USE_SSE2
|
||||
}
|
||||
|
||||
void WebPInitPremultiplySSE2(void) {
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
||||
#endif // WEBP_USE_SSE2
|
||||
@ -215,6 +209,6 @@ void WebPInitPremultiplySSE2(void) {
|
||||
#else
|
||||
|
||||
// this empty function is to avoid an empty .o
|
||||
void WebPInitPremultiplySSE2(void) {}
|
||||
void WebPInitUpsamplersSSE2(void) {}
|
||||
|
||||
#endif // FANCY_UPSAMPLING
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "./vp8enci.h"
|
||||
#include "../utils/alpha_processing.h"
|
||||
#include "../utils/random.h"
|
||||
#include "../utils/rescaler.h"
|
||||
#include "../utils/utils.h"
|
||||
@ -402,24 +401,15 @@ static void RescalePlane(const uint8_t* src,
|
||||
}
|
||||
|
||||
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
|
||||
uint32_t* ptr = pic->argb;
|
||||
int y;
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
WebPMultARGBRow(ptr, pic->width, inverse);
|
||||
ptr += pic->argb_stride;
|
||||
}
|
||||
assert(pic->argb != NULL);
|
||||
WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
|
||||
pic->width, pic->height, inverse);
|
||||
}
|
||||
|
||||
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
|
||||
const uint8_t* ptr_a = pic->a;
|
||||
if (ptr_a != NULL) {
|
||||
uint8_t* ptr_y = pic->y;
|
||||
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;
|
||||
}
|
||||
if (pic->a != NULL) {
|
||||
WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
|
||||
pic->width, pic->height, inverse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,6 +445,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
}
|
||||
// If present, we need to rescale alpha first (for AlphaMultiplyY).
|
||||
if (pic->a != NULL) {
|
||||
WebPInitAlphaProcessing();
|
||||
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
||||
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
|
||||
// weighting first (black-matting), scale the RGB values, and remove
|
||||
// the premultiplication afterward (while preserving the alpha channel).
|
||||
WebPInitAlphaProcessing();
|
||||
AlphaMultiplyARGB(pic, 0);
|
||||
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
||||
pic->argb_stride * 4,
|
||||
@ -1367,4 +1359,3 @@ LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
|
||||
#undef LOSSLESS_ENCODE_FUNC
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -9,8 +9,6 @@ common_HEADERS = ../webp/types.h
|
||||
commondir = $(includedir)/webp
|
||||
|
||||
COMMON_SOURCES =
|
||||
COMMON_SOURCES += alpha_processing.c
|
||||
COMMON_SOURCES += alpha_processing.h
|
||||
COMMON_SOURCES += bit_reader.c
|
||||
COMMON_SOURCES += bit_reader.h
|
||||
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…
Reference in New Issue
Block a user