mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Some bug-fixes for images with alpha.
- Fix the off-by-one diff when cropping with simple-filter. - Fix a bug in incremental decoding in case of alpha. - In VP8FinishRow(), do not decode alpha when y_start > y_end. - Correct output of alpha channel for MODE_ARGB. - Correct output of alpha channel for MODE_RGBA_4444. Change-Id: I785763a2a704b973cc742ad93ffbb53699d1fc0a
This commit is contained in:
parent
273a12a013
commit
8666a93aae
@ -365,7 +365,7 @@ int VP8FinishRow(VP8Decoder* const dec, VP8Io* io) {
|
|||||||
y_end = io->crop_bottom; // make sure we don't overflow on last row.
|
y_end = io->crop_bottom; // make sure we don't overflow on last row.
|
||||||
}
|
}
|
||||||
io->a = NULL;
|
io->a = NULL;
|
||||||
if (dec->alpha_data_) {
|
if (dec->alpha_data_ && y_start < y_end) {
|
||||||
io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start);
|
io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start);
|
||||||
if (io->a == NULL) {
|
if (io->a == NULL) {
|
||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
|
61
src/dec/io.c
61
src/dec/io.c
@ -51,7 +51,9 @@ static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const uint8_t* y_src = io->y;
|
const uint8_t* y_src = io->y;
|
||||||
const uint8_t* u_src = io->u;
|
const uint8_t* u_src = io->u;
|
||||||
const uint8_t* v_src = io->v;
|
const uint8_t* v_src = io->v;
|
||||||
const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace];
|
const WebPSampleLinePairFunc sample =
|
||||||
|
io->a ? WebPSamplersKeepAlpha[output->colorspace]
|
||||||
|
: WebPSamplers[output->colorspace];
|
||||||
const int mb_w = io->mb_w;
|
const int mb_w = io->mb_w;
|
||||||
const int last = io->mb_h - 1;
|
const int last = io->mb_h - 1;
|
||||||
int j;
|
int j;
|
||||||
@ -185,12 +187,34 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const int mb_h = io->mb_h;
|
const int mb_h = io->mb_h;
|
||||||
int i, j;
|
int i, j;
|
||||||
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
|
uint8_t* dst = buf->rgba + io->mb_y * buf->stride +
|
||||||
|
(p->output->colorspace == MODE_ARGB ? 0 : 3);
|
||||||
const uint8_t* alpha = io->a;
|
const uint8_t* alpha = io->a;
|
||||||
if (alpha) {
|
if (alpha) {
|
||||||
for (j = 0; j < mb_h; ++j) {
|
for (j = 0; j < mb_h; ++j) {
|
||||||
for (i = 0; i < mb_w; ++i) {
|
for (i = 0; i < mb_w; ++i) {
|
||||||
dst[4 * i + 3] = alpha[i];
|
dst[4 * i] = alpha[i];
|
||||||
|
}
|
||||||
|
alpha += io->width;
|
||||||
|
dst += buf->stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
|
const int mb_w = io->mb_w;
|
||||||
|
const int mb_h = io->mb_h;
|
||||||
|
int i, j;
|
||||||
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
|
uint8_t* dst = buf->rgba + io->mb_y * buf->stride + 1;
|
||||||
|
const uint8_t* alpha = io->a;
|
||||||
|
if (alpha) {
|
||||||
|
for (j = 0; j < mb_h; ++j) {
|
||||||
|
for (i = 0; i < mb_w; ++i) {
|
||||||
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
|
const uint8_t alpha_val = (alpha[i] + 8) >> 4;
|
||||||
|
dst[2 * i] = (dst[2 * i] & 0xf0) | alpha_val;
|
||||||
}
|
}
|
||||||
alpha += io->width;
|
alpha += io->width;
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
@ -440,14 +464,34 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
|
|
||||||
static int ExportAlpha(WebPDecParams* const p, int y_pos) {
|
static int ExportAlpha(WebPDecParams* const p, int y_pos) {
|
||||||
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
|
uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride +
|
||||||
|
(p->output->colorspace == MODE_ARGB ? 0 : 3);
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
while (p->scaler_a.y_accum <= 0) {
|
while (p->scaler_a.y_accum <= 0) {
|
||||||
int i;
|
int i;
|
||||||
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
ExportRow(&p->scaler_a);
|
ExportRow(&p->scaler_a);
|
||||||
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
||||||
dst[4 * i + 3] = p->scaler_a.dst[i];
|
dst[4 * i] = p->scaler_a.dst[i];
|
||||||
|
}
|
||||||
|
dst += buf->stride;
|
||||||
|
num_lines_out++;
|
||||||
|
}
|
||||||
|
return num_lines_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
|
||||||
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
|
uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride + 1;
|
||||||
|
int num_lines_out = 0;
|
||||||
|
while (p->scaler_a.y_accum <= 0) {
|
||||||
|
int i;
|
||||||
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
|
ExportRow(&p->scaler_a);
|
||||||
|
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
||||||
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
|
const uint8_t alpha_val = (p->scaler_a.dst[i] + 8) >> 4;
|
||||||
|
dst[2 * i] = (dst[2 * i] & 0xf0) | alpha_val;
|
||||||
}
|
}
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
num_lines_out++;
|
num_lines_out++;
|
||||||
@ -460,7 +504,8 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
int j = 0, pos = 0;
|
int j = 0, pos = 0;
|
||||||
while (j < io->mb_h) {
|
while (j < io->mb_h) {
|
||||||
j += Import(io->a + j * io->width, io->width, io->mb_h - j, &p->scaler_a);
|
j += Import(io->a + j * io->width, io->width, io->mb_h - j, &p->scaler_a);
|
||||||
pos += ExportAlpha(p, pos);
|
pos += (p->output->colorspace == MODE_RGBA_4444) ?
|
||||||
|
ExportAlphaRGBA4444(p, pos) : ExportAlpha(p, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -608,7 +653,9 @@ static int CustomSetup(VP8Io* io) {
|
|||||||
}
|
}
|
||||||
if (IsAlphaMode(p->output->colorspace)) {
|
if (IsAlphaMode(p->output->colorspace)) {
|
||||||
// We need transparency output
|
// We need transparency output
|
||||||
p->emit_alpha = is_rgb ? EmitAlphaRGB : EmitAlphaYUV;
|
p->emit_alpha =
|
||||||
|
is_rgb ? (p->output->colorspace == MODE_RGBA_4444 ?
|
||||||
|
EmitAlphaRGBA4444 : EmitAlphaRGB) : EmitAlphaYUV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +249,8 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
|
|||||||
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||||
const uint8_t* buf;
|
const uint8_t* buf;
|
||||||
uint32_t buf_size;
|
uint32_t buf_size;
|
||||||
|
const uint8_t* alpha_data_tmp;
|
||||||
|
uint32_t alpha_size_tmp;
|
||||||
uint32_t vp8_chunk_size;
|
uint32_t vp8_chunk_size;
|
||||||
uint32_t bytes_skipped;
|
uint32_t bytes_skipped;
|
||||||
VP8FrameHeader* frm_hdr;
|
VP8FrameHeader* frm_hdr;
|
||||||
@ -270,10 +272,19 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
|
|
||||||
// Process Pre-VP8 chunks.
|
// Process Pre-VP8 chunks.
|
||||||
status = WebPParseHeaders(&buf, &buf_size, &vp8_chunk_size, &bytes_skipped,
|
status = WebPParseHeaders(&buf, &buf_size, &vp8_chunk_size, &bytes_skipped,
|
||||||
&dec->alpha_data_, &dec->alpha_data_size_);
|
&alpha_data_tmp, &alpha_size_tmp);
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return VP8SetError(dec, status, "Incorrect/incomplete header.");
|
return VP8SetError(dec, status, "Incorrect/incomplete header.");
|
||||||
}
|
}
|
||||||
|
if (dec->alpha_data_ == NULL) {
|
||||||
|
assert(dec->alpha_data_size_ == 0);
|
||||||
|
// We have NOT set alpha data yet. Set it now.
|
||||||
|
// (This is to ensure that dec->alpha_data_ is NOT reset to NULL if
|
||||||
|
// WebPParseHeaders() is called more than once, as in incremental decoding
|
||||||
|
// case.)
|
||||||
|
dec->alpha_data_ = alpha_data_tmp;
|
||||||
|
dec->alpha_data_size_ = alpha_size_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
// Process the VP8 frame header.
|
// Process the VP8 frame header.
|
||||||
if (buf_size < 4) {
|
if (buf_size < 4) {
|
||||||
|
@ -155,6 +155,7 @@ typedef void (*WebPSampleLinePairFunc)(
|
|||||||
uint8_t* top_dst, uint8_t* bottom_dst, int len);
|
uint8_t* top_dst, uint8_t* bottom_dst, int len);
|
||||||
|
|
||||||
extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
|
extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
|
||||||
|
extern const WebPSampleLinePairFunc WebPSamplersKeepAlpha[/* MODE_LAST */];
|
||||||
|
|
||||||
// YUV444->RGB converters
|
// YUV444->RGB converters
|
||||||
typedef void (*WebPYUV444Converter)(const uint8_t* y,
|
typedef void (*WebPYUV444Converter)(const uint8_t* y,
|
||||||
|
@ -101,7 +101,7 @@ UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
|||||||
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
||||||
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||||
// These two don't erase the alpha value
|
// These variants don't erase the alpha value
|
||||||
UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
|
UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||||
@ -146,6 +146,11 @@ SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
|
|||||||
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
|
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
|
||||||
SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
||||||
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
|
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
|
||||||
|
// These variants don't erase the alpha value
|
||||||
|
SAMPLE_FUNC(SampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||||
|
SAMPLE_FUNC(SampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||||
|
SAMPLE_FUNC(SampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||||
|
SAMPLE_FUNC(SampleRgba4444KeepAlphaLinePair, VP8YuvToRgba4444KeepA, 2)
|
||||||
|
|
||||||
#undef SAMPLE_FUNC
|
#undef SAMPLE_FUNC
|
||||||
|
|
||||||
@ -159,6 +164,16 @@ const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
|
|||||||
SampleRgb565LinePair // MODE_RGB_565
|
SampleRgb565LinePair // MODE_RGB_565
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const WebPSampleLinePairFunc WebPSamplersKeepAlpha[MODE_LAST] = {
|
||||||
|
SampleRgbLinePair, // MODE_RGB
|
||||||
|
SampleRgbKeepAlphaLinePair, // MODE_RGBA
|
||||||
|
SampleBgrLinePair, // MODE_BGR
|
||||||
|
SampleBgrKeepAlphaLinePair, // MODE_BGRA
|
||||||
|
SampleArgbKeepAlphaLinePair, // MODE_ARGB
|
||||||
|
SampleRgba4444KeepAlphaLinePair, // MODE_RGBA_4444
|
||||||
|
SampleRgb565LinePair // MODE_RGB_565
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// YUV444 converter
|
// YUV444 converter
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user