mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-13 06:24:27 +02:00
add colorspace for premultiplied alpha
The new modes are MODE_rgbA MODE_bgrA MODE_Argb MODE_rgbA_4444 It's binary incompatible, since the enums changed. While at it, i removed the now unneeded KeepAlpha methods. -> Saved ~12k of code! * made explicit mention that alpha_plane is persistent, so we have access to the full alpha plane data at all time. Incremental decoding of alpha was planned for, but not implemented. So better not dragged this constaint for now and make the code easier until we revisit that. Change-Id: Idaba281a6ca819965ca062d1c23329f36d90c7ff
This commit is contained in:
@ -155,7 +155,6 @@ typedef void (*WebPUpsampleLinePairFunc)(
|
||||
|
||||
// Fancy upsampling functions to convert YUV to RGB(A) modes
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[/* MODE_LAST */];
|
||||
|
||||
// Initializes SSE2 version of the fancy upsamplers.
|
||||
void WebPInitUpsamplersSSE2(void);
|
||||
@ -169,7 +168,6 @@ typedef void (*WebPSampleLinePairFunc)(
|
||||
uint8_t* top_dst, uint8_t* bottom_dst, int len);
|
||||
|
||||
extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
|
||||
extern const WebPSampleLinePairFunc WebPSamplersKeepAlpha[/* MODE_LAST */];
|
||||
|
||||
// YUV444->RGB converters
|
||||
typedef void (*WebPYUV444Converter)(const uint8_t* y,
|
||||
@ -181,6 +179,23 @@ extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
||||
// Main function to be called
|
||||
void WebPInitUpsamplers(void);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Pre-multiply planes with alpha values
|
||||
|
||||
// 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).
|
||||
extern void (*WebPApplyAlphaMultiply)(
|
||||
uint8_t* rgba, int alpha_first, int w, int h, int stride);
|
||||
|
||||
// Same, buf specifically for RGBA4444 format
|
||||
extern void (*WebPApplyAlphaMultiply4444)(
|
||||
uint8_t* rgba4444, int w, int h, int stride);
|
||||
|
||||
// To be called first before using the above.
|
||||
void WebPInitPremultiply(void);
|
||||
|
||||
void WebPInitPremultiplySSE2(void); // should not be called directly.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
@ -19,6 +19,8 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "./lossless.h"
|
||||
#include "../dec/vp8li.h"
|
||||
#include "../dsp/yuv.h"
|
||||
#include "../dsp/dsp.h"
|
||||
|
||||
#ifdef USE_LOSSLESS_ENCODER
|
||||
|
||||
@ -1041,8 +1043,7 @@ static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
|
||||
}
|
||||
|
||||
void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
|
||||
WEBP_CSP_MODE out_colorspace,
|
||||
uint8_t* const rgba) {
|
||||
WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {
|
||||
switch (out_colorspace) {
|
||||
case MODE_RGB:
|
||||
ConvertBGRAToRGB(in_data, num_pixels, rgba);
|
||||
@ -1050,18 +1051,34 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
|
||||
case MODE_RGBA:
|
||||
ConvertBGRAToRGBA(in_data, num_pixels, rgba);
|
||||
break;
|
||||
case MODE_rgbA:
|
||||
ConvertBGRAToRGBA(in_data, num_pixels, rgba);
|
||||
WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
|
||||
break;
|
||||
case MODE_BGR:
|
||||
ConvertBGRAToBGR(in_data, num_pixels, rgba);
|
||||
break;
|
||||
case MODE_BGRA:
|
||||
CopyOrSwap(in_data, num_pixels, rgba, 1);
|
||||
break;
|
||||
case MODE_bgrA:
|
||||
CopyOrSwap(in_data, num_pixels, rgba, 1);
|
||||
WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
|
||||
break;
|
||||
case MODE_ARGB:
|
||||
CopyOrSwap(in_data, num_pixels, rgba, 0);
|
||||
break;
|
||||
case MODE_Argb:
|
||||
CopyOrSwap(in_data, num_pixels, rgba, 0);
|
||||
WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);
|
||||
break;
|
||||
case MODE_RGBA_4444:
|
||||
ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
|
||||
break;
|
||||
case MODE_rgbA_4444:
|
||||
ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
|
||||
WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);
|
||||
break;
|
||||
case MODE_RGB_565:
|
||||
ConvertBGRAToRGB565(in_data, num_pixels, rgba);
|
||||
break;
|
||||
|
@ -23,7 +23,6 @@ extern "C" {
|
||||
|
||||
// Fancy upsampling functions to convert YUV to RGB
|
||||
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
|
||||
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
|
||||
|
||||
// Given samples laid out in a square as:
|
||||
// [a b]
|
||||
@ -100,11 +99,6 @@ UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
||||
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
||||
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||
// These variants don't erase the alpha value
|
||||
UPSAMPLE_FUNC(UpsampleRgbaKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||
UPSAMPLE_FUNC(UpsampleBgraKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||
UPSAMPLE_FUNC(UpsampleRgba4444KeepAlphaLinePair, VP8YuvToRgba4444KeepA, 2)
|
||||
|
||||
#undef LOAD_UV
|
||||
#undef UPSAMPLE_FUNC
|
||||
@ -145,11 +139,6 @@ SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
|
||||
SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
||||
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||
// These variants don't erase the alpha value
|
||||
SAMPLE_FUNC(SampleRgbaKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||
SAMPLE_FUNC(SampleBgraKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||
SAMPLE_FUNC(SampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||
SAMPLE_FUNC(SampleRgba4444KeepAlphaLinePair, VP8YuvToRgba4444KeepA, 2)
|
||||
|
||||
#undef SAMPLE_FUNC
|
||||
|
||||
@ -160,17 +149,11 @@ const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
|
||||
SampleBgraLinePair, // MODE_BGRA
|
||||
SampleArgbLinePair, // MODE_ARGB
|
||||
SampleRgba4444LinePair, // MODE_RGBA_4444
|
||||
SampleRgb565LinePair // MODE_RGB_565
|
||||
};
|
||||
|
||||
const WebPSampleLinePairFunc WebPSamplersKeepAlpha[MODE_LAST] = {
|
||||
SampleRgbLinePair, // MODE_RGB
|
||||
SampleRgbaKeepAlphaLinePair, // MODE_RGBA
|
||||
SampleBgrLinePair, // MODE_BGR
|
||||
SampleBgraKeepAlphaLinePair, // MODE_BGRA
|
||||
SampleArgbKeepAlphaLinePair, // MODE_ARGB
|
||||
SampleRgba4444KeepAlphaLinePair, // MODE_RGBA_4444
|
||||
SampleRgb565LinePair // MODE_RGB_565
|
||||
SampleRgb565LinePair, // MODE_RGB_565
|
||||
SampleRgbaLinePair, // MODE_rgbA
|
||||
SampleBgraLinePair, // MODE_bgrA
|
||||
SampleArgbLinePair, // MODE_Argb
|
||||
SampleRgba4444LinePair // MODE_rgbA_4444
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -200,9 +183,82 @@ const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
|
||||
Yuv444ToBgra, // MODE_BGRA
|
||||
Yuv444ToArgb, // MODE_ARGB
|
||||
Yuv444ToRgba4444, // MODE_RGBA_4444
|
||||
Yuv444ToRgb565 // MODE_RGB_565
|
||||
Yuv444ToRgb565, // MODE_RGB_565
|
||||
Yuv444ToRgba, // MODE_rgbA
|
||||
Yuv444ToBgra, // MODE_bgrA
|
||||
Yuv444ToArgb, // MODE_Argb
|
||||
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_1rst,
|
||||
int w, int h, int stride) {
|
||||
while (h-- > 0) {
|
||||
uint8_t* const rgb = rgba + (alpha_1rst ? 1 : 0);
|
||||
const uint8_t* const alpha = rgba + (alpha_1rst ? 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) * 0x11)
|
||||
#define PREMULTIPLY(x, m) (((x) * (m)) >> 12)
|
||||
|
||||
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 void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
||||
int w, int h, int stride) {
|
||||
while (h-- > 0) {
|
||||
int i;
|
||||
for (i = 0; i < w; ++i) {
|
||||
const uint8_t a = dither_lo(rgba4444[2 * i + 1]);
|
||||
const uint32_t mult = MULTIPLIER(a);
|
||||
const uint8_t r = PREMULTIPLY(dither_hi(rgba4444[2 * i + 0]), mult);
|
||||
const uint8_t g = PREMULTIPLY(dither_lo(rgba4444[2 * i + 0]), mult);
|
||||
const uint8_t b = PREMULTIPLY(dither_hi(rgba4444[2 * i + 1]), mult);
|
||||
rgba4444[2 * i + 0] = (r & 0xf0) | (g & 0x0f);
|
||||
rgba4444[2 * i + 1] = (b & 0xf0) | a;
|
||||
}
|
||||
rgba4444 += stride;
|
||||
}
|
||||
}
|
||||
#undef MULTIPLIER
|
||||
#undef PREMULTIPLY
|
||||
|
||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
|
||||
= ApplyAlphaMultiply;
|
||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
|
||||
= ApplyAlphaMultiply4444;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main call
|
||||
|
||||
@ -216,16 +272,8 @@ void WebPInitUpsamplers(void) {
|
||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
||||
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbaKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgraKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_ARGB] = UpsampleArgbKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGBA_4444] = UpsampleRgba4444KeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB_565] = UpsampleRgb565LinePair;
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo) {
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitUpsamplersSSE2();
|
||||
@ -235,6 +283,26 @@ void WebPInitUpsamplers(void) {
|
||||
#endif // FANCY_UPSAMPLING
|
||||
}
|
||||
|
||||
void WebPInitPremultiply(void) {
|
||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
||||
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
|
||||
|
||||
#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
|
||||
}
|
||||
#endif // FANCY_UPSAMPLING
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -176,9 +176,6 @@ SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3)
|
||||
SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3)
|
||||
SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4)
|
||||
SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
|
||||
// These two don't erase the alpha value
|
||||
SSE2_UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePairSSE2, VP8YuvToRgb, 4)
|
||||
SSE2_UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePairSSE2, VP8YuvToBgr, 4)
|
||||
|
||||
#undef GET_M
|
||||
#undef PACK_AND_STORE
|
||||
@ -190,7 +187,6 @@ SSE2_UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePairSSE2, VP8YuvToBgr, 4)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[/* MODE_LAST */];
|
||||
|
||||
#endif // FANCY_UPSAMPLING
|
||||
|
||||
@ -200,11 +196,13 @@ void WebPInitUpsamplersSSE2(void) {
|
||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
|
||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
|
||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
|
||||
#endif // FANCY_UPSAMPLING
|
||||
}
|
||||
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePairSSE2;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePairSSE2;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePairSSE2;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePairSSE2;
|
||||
void WebPInitPremultiplySSE2(void) {
|
||||
#ifdef FANCY_UPSAMPLING
|
||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
|
||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
|
||||
#endif // FANCY_UPSAMPLING
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,11 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
|
||||
rgba[3] = 0xff;
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t VP8Clip4Bits(uint8_t c) {
|
||||
const uint32_t v = (c + 8) >> 4;
|
||||
return (v > 15) ? 15 : v;
|
||||
}
|
||||
|
||||
// Must be called before everything, to initialize the tables.
|
||||
void VP8YUVInit(void);
|
||||
|
||||
|
Reference in New Issue
Block a user