Path: blob/master/thirdparty/libwebp/src/dec/alpha_dec.c
21147 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 <assert.h>14#include <stdlib.h>1516#include "src/dec/alphai_dec.h"17#include "src/dec/vp8_dec.h"18#include "src/dec/vp8i_dec.h"19#include "src/dec/vp8li_dec.h"20#include "src/dec/webpi_dec.h"21#include "src/dsp/dsp.h"22#include "src/utils/quant_levels_dec_utils.h"23#include "src/utils/utils.h"24#include "src/webp/decode.h"25#include "src/webp/format_constants.h"26#include "src/webp/types.h"2728//------------------------------------------------------------------------------29// ALPHDecoder object.3031// Allocates a new alpha decoder instance.32WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {33ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));34return dec;35}3637// Clears and deallocates an alpha decoder instance.38static void ALPHDelete(ALPHDecoder* const dec) {39if (dec != NULL) {40VP8LDelete(dec->vp8l_dec);41dec->vp8l_dec = NULL;42WebPSafeFree(dec);43}44}4546//------------------------------------------------------------------------------47// Decoding.4849// Initialize alpha decoding by parsing the alpha header and decoding the image50// header for alpha data stored using lossless compression.51// Returns false in case of error in alpha header (data too short, invalid52// compression method or filter, error in lossless header data etc).53WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,54size_t data_size, const VP8Io* const src_io,55uint8_t* output) {56int ok = 0;57const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;58const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;59int rsrv;60VP8Io* const io = &dec->io;6162assert(data != NULL && output != NULL && src_io != NULL);6364VP8FiltersInit();65dec->output = output;66dec->width = src_io->width;67dec->height = src_io->height;68assert(dec->width > 0 && dec->height > 0);6970if (data_size <= ALPHA_HEADER_LEN) {71return 0;72}7374dec->method = (data[0] >> 0) & 0x03;75dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);76dec->pre_processing = (data[0] >> 4) & 0x03;77rsrv = (data[0] >> 6) & 0x03;78if (dec->method < ALPHA_NO_COMPRESSION ||79dec->method > ALPHA_LOSSLESS_COMPRESSION ||80dec->filter >= WEBP_FILTER_LAST ||81dec->pre_processing > ALPHA_PREPROCESSED_LEVELS ||82rsrv != 0) {83return 0;84}8586// Copy the necessary parameters from src_io to io87if (!VP8InitIo(io)) {88return 0;89}90WebPInitCustomIo(NULL, io);91io->opaque = dec;92io->width = src_io->width;93io->height = src_io->height;9495io->use_cropping = src_io->use_cropping;96io->crop_left = src_io->crop_left;97io->crop_right = src_io->crop_right;98io->crop_top = src_io->crop_top;99io->crop_bottom = src_io->crop_bottom;100// No need to copy the scaling parameters.101102if (dec->method == ALPHA_NO_COMPRESSION) {103const size_t alpha_decoded_size = dec->width * dec->height;104ok = (alpha_data_size >= alpha_decoded_size);105} else {106assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);107ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);108}109110return ok;111}112113// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha114// starting from row number 'row'. It assumes that rows up to (row - 1) have115// already been decoded.116// Returns false in case of bitstream error.117WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,118int num_rows) {119ALPHDecoder* const alph_dec = dec->alph_dec;120const int width = alph_dec->width;121const int height = alph_dec->io.crop_bottom;122if (alph_dec->method == ALPHA_NO_COMPRESSION) {123int y;124const uint8_t* prev_line = dec->alpha_prev_line;125const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width;126uint8_t* dst = dec->alpha_plane + row * width;127assert(deltas <= &dec->alpha_data[dec->alpha_data_size]);128assert(WebPUnfilters[alph_dec->filter] != NULL);129for (y = 0; y < num_rows; ++y) {130WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width);131prev_line = dst;132dst += width;133deltas += width;134}135dec->alpha_prev_line = prev_line;136} else { // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION137assert(alph_dec->vp8l_dec != NULL);138if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {139return 0;140}141}142143if (row + num_rows >= height) {144dec->is_alpha_decoded = 1;145}146return 1;147}148149WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,150const VP8Io* const io) {151const int stride = io->width;152const int height = io->crop_bottom;153const uint64_t alpha_size = (uint64_t)stride * height;154assert(dec->alpha_plane_mem == NULL);155dec->alpha_plane_mem =156(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane));157if (dec->alpha_plane_mem == NULL) {158return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,159"Alpha decoder initialization failed.");160}161dec->alpha_plane = dec->alpha_plane_mem;162dec->alpha_prev_line = NULL;163return 1;164}165166void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {167assert(dec != NULL);168WebPSafeFree(dec->alpha_plane_mem);169dec->alpha_plane_mem = NULL;170dec->alpha_plane = NULL;171ALPHDelete(dec->alph_dec);172dec->alph_dec = NULL;173}174175//------------------------------------------------------------------------------176// Main entry point.177178WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,179const VP8Io* const io,180int row, int num_rows) {181const int width = io->width;182const int height = io->crop_bottom;183184assert(dec != NULL && io != NULL);185186if (row < 0 || num_rows <= 0 || row + num_rows > height) {187return NULL;188}189190if (!dec->is_alpha_decoded) {191if (dec->alph_dec == NULL) { // Initialize decoder.192dec->alph_dec = ALPHNew();193if (dec->alph_dec == NULL) {194VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,195"Alpha decoder initialization failed.");196return NULL;197}198if (!AllocateAlphaPlane(dec, io)) goto Error;199if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size,200io, dec->alpha_plane)) {201VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec;202VP8SetError(dec,203(vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY204: vp8l_dec->status,205"Alpha decoder initialization failed.");206goto Error;207}208// if we allowed use of alpha dithering, check whether it's needed at all209if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) {210dec->alpha_dithering = 0; // disable dithering211} else {212num_rows = height - row; // decode everything in one pass213}214}215216assert(dec->alph_dec != NULL);217assert(row + num_rows <= height);218if (!ALPHDecode(dec, row, num_rows)) goto Error;219220if (dec->is_alpha_decoded) { // finished?221ALPHDelete(dec->alph_dec);222dec->alph_dec = NULL;223if (dec->alpha_dithering > 0) {224uint8_t* const alpha = dec->alpha_plane + io->crop_top * width225+ io->crop_left;226if (!WebPDequantizeLevels(alpha,227io->crop_right - io->crop_left,228io->crop_bottom - io->crop_top,229width, dec->alpha_dithering)) {230goto Error;231}232}233}234}235236// Return a pointer to the current decoded row.237return dec->alpha_plane + row * width;238239Error:240WebPDeallocateAlphaMemory(dec);241return NULL;242}243244245