diff --git a/src/dec/alpha.c b/src/dec/alpha.c index d6c8ac26..f31283c6 100644 --- a/src/dec/alpha.c +++ b/src/dec/alpha.c @@ -52,11 +52,12 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; int rsrv; - int filter; VP8Io* const io = &dec->io_; assert(data != NULL && output != NULL && src_io != NULL); + VP8FiltersInit(); + dec->output_ = output; dec->width_ = src_io->width; dec->height_ = src_io->height; assert(dec->width_ > 0 && dec->height_ > 0); @@ -66,21 +67,17 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, } dec->method_ = (data[0] >> 0) & 0x03; - filter = (data[0] >> 2) & 0x03; + dec->filter_ = (data[0] >> 2) & 0x03; dec->pre_processing_ = (data[0] >> 4) & 0x03; rsrv = (data[0] >> 6) & 0x03; if (dec->method_ < ALPHA_NO_COMPRESSION || dec->method_ > ALPHA_LOSSLESS_COMPRESSION || - filter >= WEBP_FILTER_LAST || + dec->filter_ >= WEBP_FILTER_LAST || dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS || rsrv != 0) { return 0; } - VP8FiltersInit(); - dec->unfilter_func_ = WebPUnfilters[filter]; - dec->output_ = output; - // Copy the necessary parameters from src_io to io VP8InitIo(io); WebPInitCustomIo(NULL, io); @@ -121,8 +118,9 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) { assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN + offset + num_pixels); memcpy(dec->alpha_plane_ + offset, dec->alpha_data_ + ALPHA_HEADER_LEN + offset, num_pixels); - if (alph_dec->unfilter_func_ != NULL) { - alph_dec->unfilter_func_(width, height, width, row, num_rows, output); + if (WebPUnfilters[alph_dec->filter_] != NULL) { + WebPUnfilters[alph_dec->filter_](width, height, width, + row, num_rows, output); } } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION assert(alph_dec->vp8l_dec_ != NULL); diff --git a/src/dec/alphai.h b/src/dec/alphai.h index bf2febcd..1e817c81 100644 --- a/src/dec/alphai.h +++ b/src/dec/alphai.h @@ -28,7 +28,7 @@ struct ALPHDecoder { int width_; int height_; int method_; - WebPUnfilterFunc unfilter_func_; + WEBP_FILTER_TYPE filter_; int pre_processing_; struct VP8LDecoder* vp8l_dec_; VP8Io io_; diff --git a/src/dec/vp8l.c b/src/dec/vp8l.c index 8ff76158..7736184d 100644 --- a/src/dec/vp8l.c +++ b/src/dec/vp8l.c @@ -714,27 +714,6 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows, } } -// Special method for paletted alpha data. -static void ApplyInverseTransformsAlpha(VP8LDecoder* const dec, int num_rows, - const uint8_t* const rows) { - const ALPHDecoder* const alph_dec = (const ALPHDecoder*)dec->io_->opaque; - const int width = dec->io_->width; - uint8_t* const output = alph_dec->output_; - const int start_row = dec->last_row_; - const int end_row = start_row + num_rows; - const uint8_t* rows_in = rows; - uint8_t* rows_out = output + width * start_row; - VP8LTransform* const transform = &dec->transforms_[0]; - assert(dec->next_transform_ == 1); - assert(transform->type_ == COLOR_INDEXING_TRANSFORM); - VP8LColorIndexInverseTransformAlpha(transform, start_row, end_row, rows_in, - rows_out); - if (alph_dec->unfilter_func_ != NULL) { - alph_dec->unfilter_func_(width, dec->io_->height, width, - start_row, num_rows, output); - } -} - // Processes (transforms, scales & color-converts) the rows decoded after the // last call. static void ProcessRows(VP8LDecoder* const dec, int row) { @@ -793,12 +772,32 @@ static int Is8bOptimizable(const VP8LMetadata* const hdr) { } static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int row) { - const uint8_t* const in = - (uint8_t*)dec->pixels_ + dec->width_ * dec->last_row_; - const int num_rows = row - dec->last_row_; + // For vertical and gradient filtering, we need to decode the part above the + // crop_top row, in order to have the correct spatial predictors. + const ALPHDecoder* const alph_dec = (const ALPHDecoder*)dec->io_->opaque; + const int top_row = + (alph_dec->filter_ == WEBP_FILTER_NONE || + alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top + : dec->last_row_; + const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_; assert(row <= dec->io_->crop_bottom); - if (num_rows > 0) { - ApplyInverseTransformsAlpha(dec, num_rows, in); + if (row > first_row) { + // Special method for paletted alpha data. We only process the cropped area. + const int width = dec->io_->width; + uint8_t* const out = alph_dec->output_ + width * first_row; + const uint8_t* const in = + (uint8_t*)dec->pixels_ + dec->width_ * first_row; + VP8LTransform* const transform = &dec->transforms_[0]; + assert(dec->next_transform_ == 1); + assert(transform->type_ == COLOR_INDEXING_TRANSFORM); + VP8LColorIndexInverseTransformAlpha(transform, first_row, row, + in, out); + if (alph_dec->filter_ != WEBP_FILTER_NONE) { + assert(WebPUnfilters[alph_dec->filter_] != NULL); + WebPUnfilters[alph_dec->filter_](width, dec->io_->height, width, + first_row, row - first_row, + alph_dec->output_); + } } dec->last_row_ = dec->last_out_row_ = row; } @@ -1469,9 +1468,10 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { int i; ApplyInverseTransforms(dec, num_rows, in); for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; - if (alph_dec->unfilter_func_ != NULL) { - alph_dec->unfilter_func_(width, dec->io_->height, width, - dec->last_row_, num_rows, output); + if (alph_dec->filter_ != WEBP_FILTER_NONE) { + assert(WebPUnfilters[alph_dec->filter_] != NULL); + WebPUnfilters[alph_dec->filter_](width, dec->io_->height, width, + dec->last_row_, num_rows, output); } } dec->last_row_ = dec->last_out_row_ = row;