mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
add support for RGB565, ARGB4444 and ARGB colorspace (decoder)
RGB565 and ARGB4444 are only supported through the advanced decoding API. ARGB being somewhat generic, there's an easy WebPDecodeARGB() new function for convenience. Patch by Vikas Arora (vikaas dot arora at gmail dot com) Change-Id: Ic7b6f72bd70aca458d14e7fdd23679212430ebca
This commit is contained in:
parent
c915fb2aa7
commit
19db59f80f
@ -20,6 +20,9 @@ extern "C" {
|
||||
//-----------------------------------------------------------------------------
|
||||
// WebPDecBuffer
|
||||
|
||||
// Number of bytes per pixel for the different color-spaces.
|
||||
static const int kModeBpp[MODE_LAST] = { 3, 4, 3, 4, 4, 2, 2, 1, 1 };
|
||||
|
||||
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
|
||||
int ok = 1;
|
||||
WEBP_CSP_MODE mode = buffer->colorspace;
|
||||
@ -44,11 +47,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
|
||||
} else { // RGB checks
|
||||
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
||||
ok &= (buf->stride * height <= buf->size);
|
||||
if (mode == MODE_RGB || mode == MODE_BGR) {
|
||||
ok &= (buf->stride >= width * 3);
|
||||
} else if (mode == MODE_RGBA || mode == MODE_BGRA) {
|
||||
ok &= (buf->stride >= width * 4);
|
||||
}
|
||||
ok &= (buf->stride >= width * kModeBpp[mode]);
|
||||
}
|
||||
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
@ -70,9 +69,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||
uint64_t size, a_size = 0, total_size;
|
||||
// We need memory and it hasn't been allocated yet.
|
||||
// => initialize output buffer, now that dimensions are known.
|
||||
stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
|
||||
: (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
|
||||
: w;
|
||||
stride = w * kModeBpp[mode];
|
||||
size = (uint64_t)stride * h;
|
||||
|
||||
if (mode >= MODE_YUV) {
|
||||
|
93
src/dec/io.c
93
src/dec/io.c
@ -21,9 +21,6 @@ extern "C" {
|
||||
|
||||
#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support
|
||||
|
||||
// mask to apply to WEBP_CSP_MODE, to know if there's alpha channel or not.
|
||||
#define MODE_ALPHA_MASK 1
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Fancy upsampler
|
||||
|
||||
@ -101,27 +98,38 @@ UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
|
||||
UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
|
||||
UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
|
||||
UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgb4444LinePair, VP8YuvToArgb4444, 2)
|
||||
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||
// These two don't erase the alpha value
|
||||
UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||
UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgb4444KeepAlphaLinePair, VP8YuvToArgb4444KeepA, 2)
|
||||
|
||||
#undef LOAD_UV
|
||||
#undef UPSAMPLE_FUNC
|
||||
|
||||
// Fancy upsampling functions to convert YUV to RGB
|
||||
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_BGRA + 1];
|
||||
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_BGRA + 1];
|
||||
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
|
||||
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
|
||||
|
||||
static void InitUpsamplers(void) {
|
||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
|
||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
|
||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
||||
WebPUpsamplers[MODE_ARGB_4444] = UpsampleArgb4444LinePair;
|
||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
||||
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_ARGB] = UpsampleArgbKeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_ARGB_4444] = UpsampleArgb4444KeepAlphaLinePair;
|
||||
WebPUpsamplersKeepAlpha[MODE_RGB_565] = UpsampleRgb565LinePair;
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8DecGetCPUInfo) {
|
||||
@ -162,10 +170,13 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||
}
|
||||
|
||||
// All variants implemented.
|
||||
SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
|
||||
SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
|
||||
SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
|
||||
SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
|
||||
SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
|
||||
SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
|
||||
SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
|
||||
SAMPLE_FUNC(SampleArgb4444LinePair, VP8YuvToArgb4444, 2)
|
||||
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||
|
||||
#undef SAMPLE_FUNC
|
||||
|
||||
@ -175,11 +186,14 @@ typedef void (*SampleLinePairFunc)(
|
||||
const uint8_t* u, const uint8_t* v,
|
||||
uint8_t* top_dst, uint8_t* bottom_dst, int len);
|
||||
|
||||
static const SampleLinePairFunc kSamplers[MODE_BGRA + 1] = {
|
||||
SampleRgbLinePair, // MODE_RGB
|
||||
SampleRgbaLinePair, // MODE_RGBA
|
||||
SampleBgrLinePair, // MODE_BGR
|
||||
SampleBgraLinePair // MODE_BGRA
|
||||
static const SampleLinePairFunc kSamplers[MODE_LAST] = {
|
||||
SampleRgbLinePair, // MODE_RGB
|
||||
SampleRgbaLinePair, // MODE_RGBA
|
||||
SampleBgrLinePair, // MODE_BGR
|
||||
SampleBgraLinePair, // MODE_BGRA
|
||||
SampleArgbLinePair, // MODE_ARGB
|
||||
SampleArgb4444LinePair, // MODE_ARGB_4444
|
||||
SampleRgb565LinePair // MODE_RGB_565
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -192,21 +206,27 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||
for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
|
||||
}
|
||||
|
||||
YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
|
||||
YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
|
||||
YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
|
||||
YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
|
||||
YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
|
||||
YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
|
||||
YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
|
||||
YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
|
||||
YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4)
|
||||
YUV444_FUNC(Yuv444ToArgb4444, VP8YuvToArgb4444, 2)
|
||||
YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2)
|
||||
|
||||
#undef YUV444_FUNC
|
||||
|
||||
typedef void (*YUV444Func)(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||
uint8_t* dst, int len);
|
||||
|
||||
static const YUV444Func kYUV444Converters[MODE_BGRA + 1] = {
|
||||
Yuv444ToRgb, // MODE_RGB
|
||||
Yuv444ToRgba, // MODE_RGBA
|
||||
Yuv444ToBgr, // MODE_BGR
|
||||
Yuv444ToBgra // MODE_BGRA
|
||||
static const YUV444Func kYUV444Converters[MODE_LAST] = {
|
||||
Yuv444ToRgb, // MODE_RGB
|
||||
Yuv444ToRgba, // MODE_RGBA
|
||||
Yuv444ToBgr, // MODE_BGR
|
||||
Yuv444ToBgra, // MODE_BGRA
|
||||
Yuv444ToArgb, // MODE_ARGB
|
||||
Yuv444ToArgb4444, // MODE_ARGB_4444
|
||||
Yuv444ToRgb565 // MODE_RGB_565
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -517,8 +537,13 @@ static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IsAlphaMode(WEBP_CSP_MODE mode) {
|
||||
return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
|
||||
mode == MODE_ARGB_4444 || mode == MODE_YUVA);
|
||||
}
|
||||
|
||||
static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const int has_alpha = (p->output->colorspace & MODE_ALPHA_MASK);
|
||||
const int has_alpha = IsAlphaMode(p->output->colorspace);
|
||||
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
|
||||
const int out_width = io->scaled_width;
|
||||
const int out_height = io->scaled_height;
|
||||
@ -653,7 +678,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
||||
}
|
||||
|
||||
static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const int has_alpha = (p->output->colorspace & MODE_ALPHA_MASK);
|
||||
const int has_alpha = IsAlphaMode(p->output->colorspace);
|
||||
const int out_width = io->scaled_width;
|
||||
const int out_height = io->scaled_height;
|
||||
const int uv_in_width = (io->mb_w + 1) >> 1;
|
||||
@ -793,7 +818,7 @@ static int CustomSetup(VP8Io* io) {
|
||||
p->emit = EmitYUV;
|
||||
}
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
if (p->output->colorspace & MODE_ALPHA_MASK) {
|
||||
if (IsAlphaMode(p->output->colorspace)) {
|
||||
// We need transparency output
|
||||
p->emit_alpha = is_rgb ? EmitAlphaRGB : EmitAlphaYUV;
|
||||
}
|
||||
|
@ -224,6 +224,11 @@ uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
|
||||
return Decode(MODE_RGBA, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size,
|
||||
int* width, int* height) {
|
||||
return Decode(MODE_ARGB, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
|
||||
int* width, int* height) {
|
||||
return Decode(MODE_BGR, data, data_size, width, height, NULL);
|
||||
|
@ -67,8 +67,8 @@ typedef void (*WebPUpsampleLinePairFunc)(
|
||||
uint8_t* top_dst, uint8_t* bottom_dst, int len);
|
||||
|
||||
// Upsampler functions to be used to convert YUV to RGB(A) modes
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_BGRA + 1];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_BGRA + 1];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
|
||||
|
||||
// Initializes SSE2 version of the fancy upsamplers.
|
||||
void WebPInitUpsamplersSSE2(void);
|
||||
|
@ -20,6 +20,7 @@ enum { YUV_HALF = 1 << (YUV_FIX - 1) };
|
||||
int16_t VP8kVToR[256], VP8kUToB[256];
|
||||
int32_t VP8kVToG[256], VP8kUToG[256];
|
||||
uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
||||
uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
||||
|
||||
static int done = 0;
|
||||
|
||||
@ -37,6 +38,7 @@ void VP8YUVInit(void) {
|
||||
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
|
||||
const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
|
||||
VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
|
||||
VP8kClip4Bits[i - YUV_RANGE_MIN] = (VP8kClip[i - YUV_RANGE_MIN] + 8) >> 4;
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ enum { YUV_FIX = 16, // fixed-point precision
|
||||
extern int16_t VP8kVToR[256], VP8kUToB[256];
|
||||
extern int32_t VP8kVToG[256], VP8kUToG[256];
|
||||
extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
||||
extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
||||
|
||||
static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const rgb) {
|
||||
@ -36,6 +37,46 @@ static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
|
||||
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
|
||||
}
|
||||
|
||||
static inline void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const rgb) {
|
||||
const int r_off = VP8kVToR[v];
|
||||
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
|
||||
const int b_off = VP8kUToB[u];
|
||||
rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
|
||||
(VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
|
||||
rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
|
||||
(VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
|
||||
}
|
||||
|
||||
static inline void VP8YuvToArgbKeepA(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const argb) {
|
||||
// Don't update Aplha (argb[0])
|
||||
VP8YuvToRgb(y, u, v, argb + 1);
|
||||
}
|
||||
|
||||
static inline void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const argb) {
|
||||
argb[0] = 0xff;
|
||||
VP8YuvToArgbKeepA(y, u, v, argb);
|
||||
}
|
||||
|
||||
static inline void VP8YuvToArgb4444KeepA(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const argb) {
|
||||
const int r_off = VP8kVToR[v];
|
||||
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
|
||||
const int b_off = VP8kUToB[u];
|
||||
// Don't update Aplha (first 4 bits of argb[0])
|
||||
argb[0] = VP8kClip4Bits[y + r_off - YUV_RANGE_MIN];
|
||||
argb[1] = ((VP8kClip[y + g_off - YUV_RANGE_MIN] & 0xf0) |
|
||||
VP8kClip4Bits[y + b_off - YUV_RANGE_MIN]);
|
||||
}
|
||||
|
||||
static inline void VP8YuvToArgb4444(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const argb) {
|
||||
argb[0] = 0xf0;
|
||||
VP8YuvToArgb4444KeepA(y, u, v, argb);
|
||||
}
|
||||
|
||||
static inline void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
|
||||
uint8_t* const bgr) {
|
||||
const int r_off = VP8kVToR[v];
|
||||
|
@ -42,6 +42,10 @@ uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
|
||||
uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Same as WebPDecodeRGBA, but returning ARGB data.
|
||||
uint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// This variant decode to BGR instead of RGB.
|
||||
uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
|
||||
int* width, int* height);
|
||||
@ -102,7 +106,11 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
|
||||
// Colorspaces
|
||||
typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
|
||||
MODE_BGR = 2, MODE_BGRA = 3,
|
||||
MODE_YUV = 4, MODE_YUVA = 5 // yuv 4:2:0
|
||||
MODE_ARGB = 4, MODE_ARGB_4444 = 5,
|
||||
MODE_RGB_565 = 6,
|
||||
// YUV modes must come after RGB ones.
|
||||
MODE_YUV = 7, MODE_YUVA = 8, // yuv 4:2:0
|
||||
MODE_LAST = 9
|
||||
} WEBP_CSP_MODE;
|
||||
|
||||
// Generic structure for describing the sample buffer.
|
||||
|
Loading…
Reference in New Issue
Block a user