mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +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.
|
||||
}
|
||||
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);
|
||||
if (io->a == NULL) {
|
||||
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* u_src = io->u;
|
||||
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 last = io->mb_h - 1;
|
||||
int j;
|
||||
@ -185,12 +187,34 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
||||
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;
|
||||
uint8_t* dst = buf->rgba + io->mb_y * buf->stride +
|
||||
(p->output->colorspace == MODE_ARGB ? 0 : 3);
|
||||
const uint8_t* alpha = io->a;
|
||||
if (alpha) {
|
||||
for (j = 0; j < mb_h; ++j) {
|
||||
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;
|
||||
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) {
|
||||
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;
|
||||
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) {
|
||||
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;
|
||||
num_lines_out++;
|
||||
@ -460,7 +504,8 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
||||
int j = 0, pos = 0;
|
||||
while (j < io->mb_h) {
|
||||
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;
|
||||
@ -608,7 +653,9 @@ static int CustomSetup(VP8Io* io) {
|
||||
}
|
||||
if (IsAlphaMode(p->output->colorspace)) {
|
||||
// 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) {
|
||||
const uint8_t* buf;
|
||||
uint32_t buf_size;
|
||||
const uint8_t* alpha_data_tmp;
|
||||
uint32_t alpha_size_tmp;
|
||||
uint32_t vp8_chunk_size;
|
||||
uint32_t bytes_skipped;
|
||||
VP8FrameHeader* frm_hdr;
|
||||
@ -270,10 +272,19 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
|
||||
// Process Pre-VP8 chunks.
|
||||
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) {
|
||||
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.
|
||||
if (buf_size < 4) {
|
||||
|
@ -155,6 +155,7 @@ 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,
|
||||
|
@ -101,7 +101,7 @@ UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
||||
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 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(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||
@ -146,6 +146,11 @@ 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(SampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
|
||||
SAMPLE_FUNC(SampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
|
||||
SAMPLE_FUNC(SampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
|
||||
SAMPLE_FUNC(SampleRgba4444KeepAlphaLinePair, VP8YuvToRgba4444KeepA, 2)
|
||||
|
||||
#undef SAMPLE_FUNC
|
||||
|
||||
@ -159,6 +164,16 @@ const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user