Path: blob/master/thirdparty/libwebp/src/dec/alpha_dec.c
9913 views
// Copyright 2011 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// Alpha-plane decompression.10//11// Author: Skal ([email protected])1213#include <stdlib.h>14#include "src/dec/alphai_dec.h"15#include "src/dec/vp8_dec.h"16#include "src/dec/vp8i_dec.h"17#include "src/dec/vp8li_dec.h"18#include "src/dsp/dsp.h"19#include "src/utils/quant_levels_dec_utils.h"20#include "src/utils/utils.h"21#include "src/webp/format_constants.h"22#include "src/webp/types.h"2324//------------------------------------------------------------------------------25// ALPHDecoder object.2627// Allocates a new alpha decoder instance.28WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {29ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));30return dec;31}3233// Clears and deallocates an alpha decoder instance.34static void ALPHDelete(ALPHDecoder* const dec) {35if (dec != NULL) {36VP8LDelete(dec->vp8l_dec_);37dec->vp8l_dec_ = NULL;38WebPSafeFree(dec);39}40}4142//------------------------------------------------------------------------------43// Decoding.4445// Initialize alpha decoding by parsing the alpha header and decoding the image46// header for alpha data stored using lossless compression.47// Returns false in case of error in alpha header (data too short, invalid48// compression method or filter, error in lossless header data etc).49WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,50size_t data_size, const VP8Io* const src_io,51uint8_t* output) {52int ok = 0;53const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;54const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;55int rsrv;56VP8Io* const io = &dec->io_;5758assert(data != NULL && output != NULL && src_io != NULL);5960VP8FiltersInit();61dec->output_ = output;62dec->width_ = src_io->width;63dec->height_ = src_io->height;64assert(dec->width_ > 0 && dec->height_ > 0);6566if (data_size <= ALPHA_HEADER_LEN) {67return 0;68}6970dec->method_ = (data[0] >> 0) & 0x03;71dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);72dec->pre_processing_ = (data[0] >> 4) & 0x03;73rsrv = (data[0] >> 6) & 0x03;74if (dec->method_ < ALPHA_NO_COMPRESSION ||75dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||76dec->filter_ >= WEBP_FILTER_LAST ||77dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||78rsrv != 0) {79return 0;80}8182// Copy the necessary parameters from src_io to io83if (!VP8InitIo(io)) {84return 0;85}86WebPInitCustomIo(NULL, io);87io->opaque = dec;88io->width = src_io->width;89io->height = src_io->height;9091io->use_cropping = src_io->use_cropping;92io->crop_left = src_io->crop_left;93io->crop_right = src_io->crop_right;94io->crop_top = src_io->crop_top;95io->crop_bottom = src_io->crop_bottom;96// No need to copy the scaling parameters.9798if (dec->method_ == ALPHA_NO_COMPRESSION) {99const size_t alpha_decoded_size = dec->width_ * dec->height_;100ok = (alpha_data_size >= alpha_decoded_size);101} else {102assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);103ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);104}105106return ok;107}108109// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha110// starting from row number 'row'. It assumes that rows up to (row - 1) have111// already been decoded.112// Returns false in case of bitstream error.113WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,114int num_rows) {115ALPHDecoder* const alph_dec = dec->alph_dec_;116const int width = alph_dec->width_;117const int height = alph_dec->io_.crop_bottom;118if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {119int y;120const uint8_t* prev_line = dec->alpha_prev_line_;121const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;122uint8_t* dst = dec->alpha_plane_ + row * width;123assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);124assert(WebPUnfilters[alph_dec->filter_] != NULL);125for (y = 0; y < num_rows; ++y) {126WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);127prev_line = dst;128dst += width;129deltas += width;130}131dec->alpha_prev_line_ = prev_line;132} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION133assert(alph_dec->vp8l_dec_ != NULL);134if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {135return 0;136}137}138139if (row + num_rows >= height) {140dec->is_alpha_decoded_ = 1;141}142return 1;143}144145WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,146const VP8Io* const io) {147const int stride = io->width;148const int height = io->crop_bottom;149const uint64_t alpha_size = (uint64_t)stride * height;150assert(dec->alpha_plane_mem_ == NULL);151dec->alpha_plane_mem_ =152(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));153if (dec->alpha_plane_mem_ == NULL) {154return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,155"Alpha decoder initialization failed.");156}157dec->alpha_plane_ = dec->alpha_plane_mem_;158dec->alpha_prev_line_ = NULL;159return 1;160}161162void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {163assert(dec != NULL);164WebPSafeFree(dec->alpha_plane_mem_);165dec->alpha_plane_mem_ = NULL;166dec->alpha_plane_ = NULL;167ALPHDelete(dec->alph_dec_);168dec->alph_dec_ = NULL;169}170171//------------------------------------------------------------------------------172// Main entry point.173174WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,175const VP8Io* const io,176int row, int num_rows) {177const int width = io->width;178const int height = io->crop_bottom;179180assert(dec != NULL && io != NULL);181182if (row < 0 || num_rows <= 0 || row + num_rows > height) {183return NULL;184}185186if (!dec->is_alpha_decoded_) {187if (dec->alph_dec_ == NULL) { // Initialize decoder.188dec->alph_dec_ = ALPHNew();189if (dec->alph_dec_ == NULL) {190VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,191"Alpha decoder initialization failed.");192return NULL;193}194if (!AllocateAlphaPlane(dec, io)) goto Error;195if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,196io, dec->alpha_plane_)) {197VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_;198VP8SetError(dec,199(vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY200: vp8l_dec->status_,201"Alpha decoder initialization failed.");202goto Error;203}204// if we allowed use of alpha dithering, check whether it's needed at all205if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {206dec->alpha_dithering_ = 0; // disable dithering207} else {208num_rows = height - row; // decode everything in one pass209}210}211212assert(dec->alph_dec_ != NULL);213assert(row + num_rows <= height);214if (!ALPHDecode(dec, row, num_rows)) goto Error;215216if (dec->is_alpha_decoded_) { // finished?217ALPHDelete(dec->alph_dec_);218dec->alph_dec_ = NULL;219if (dec->alpha_dithering_ > 0) {220uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width221+ io->crop_left;222if (!WebPDequantizeLevels(alpha,223io->crop_right - io->crop_left,224io->crop_bottom - io->crop_top,225width, dec->alpha_dithering_)) {226goto Error;227}228}229}230}231232// Return a pointer to the current decoded row.233return dec->alpha_plane_ + row * width;234235Error:236WebPDeallocateAlphaMemory(dec);237return NULL;238}239240241