go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

alpha_dec.c (8294B)


      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Alpha-plane decompression.
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 
     17 #include "src/dec/alphai_dec.h"
     18 #include "src/dec/vp8_dec.h"
     19 #include "src/dec/vp8i_dec.h"
     20 #include "src/dec/vp8li_dec.h"
     21 #include "src/dec/webpi_dec.h"
     22 #include "src/dsp/dsp.h"
     23 #include "src/utils/quant_levels_dec_utils.h"
     24 #include "src/utils/utils.h"
     25 #include "src/webp/decode.h"
     26 #include "src/webp/format_constants.h"
     27 #include "src/webp/types.h"
     28 
     29 //------------------------------------------------------------------------------
     30 // ALPHDecoder object.
     31 
     32 // Allocates a new alpha decoder instance.
     33 WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
     34   ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
     35   return dec;
     36 }
     37 
     38 // Clears and deallocates an alpha decoder instance.
     39 static void ALPHDelete(ALPHDecoder* const dec) {
     40   if (dec != NULL) {
     41     VP8LDelete(dec->vp8l_dec);
     42     dec->vp8l_dec = NULL;
     43     WebPSafeFree(dec);
     44   }
     45 }
     46 
     47 //------------------------------------------------------------------------------
     48 // Decoding.
     49 
     50 // Initialize alpha decoding by parsing the alpha header and decoding the image
     51 // header for alpha data stored using lossless compression.
     52 // Returns false in case of error in alpha header (data too short, invalid
     53 // compression method or filter, error in lossless header data etc).
     54 WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
     55                                    size_t data_size, const VP8Io* const src_io,
     56                                    uint8_t* output) {
     57   int ok = 0;
     58   const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
     59   const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
     60   int rsrv;
     61   VP8Io* const io = &dec->io;
     62 
     63   assert(data != NULL && output != NULL && src_io != NULL);
     64 
     65   VP8FiltersInit();
     66   dec->output = output;
     67   dec->width = src_io->width;
     68   dec->height = src_io->height;
     69   assert(dec->width > 0 && dec->height > 0);
     70 
     71   if (data_size <= ALPHA_HEADER_LEN) {
     72     return 0;
     73   }
     74 
     75   dec->method = (data[0] >> 0) & 0x03;
     76   dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
     77   dec->pre_processing = (data[0] >> 4) & 0x03;
     78   rsrv = (data[0] >> 6) & 0x03;
     79   if (dec->method < ALPHA_NO_COMPRESSION ||
     80       dec->method > ALPHA_LOSSLESS_COMPRESSION ||
     81       dec->filter >= WEBP_FILTER_LAST ||
     82       dec->pre_processing > ALPHA_PREPROCESSED_LEVELS ||
     83       rsrv != 0) {
     84     return 0;
     85   }
     86 
     87   // Copy the necessary parameters from src_io to io
     88   if (!VP8InitIo(io)) {
     89     return 0;
     90   }
     91   WebPInitCustomIo(NULL, io);
     92   io->opaque = dec;
     93   io->width = src_io->width;
     94   io->height = src_io->height;
     95 
     96   io->use_cropping = src_io->use_cropping;
     97   io->crop_left = src_io->crop_left;
     98   io->crop_right = src_io->crop_right;
     99   io->crop_top = src_io->crop_top;
    100   io->crop_bottom = src_io->crop_bottom;
    101   // No need to copy the scaling parameters.
    102 
    103   if (dec->method == ALPHA_NO_COMPRESSION) {
    104     const size_t alpha_decoded_size = dec->width * dec->height;
    105     ok = (alpha_data_size >= alpha_decoded_size);
    106   } else {
    107     assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
    108     ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
    109   }
    110 
    111   return ok;
    112 }
    113 
    114 // Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
    115 // starting from row number 'row'. It assumes that rows up to (row - 1) have
    116 // already been decoded.
    117 // Returns false in case of bitstream error.
    118 WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
    119                                      int num_rows) {
    120   ALPHDecoder* const alph_dec = dec->alph_dec;
    121   const int width = alph_dec->width;
    122   const int height = alph_dec->io.crop_bottom;
    123   if (alph_dec->method == ALPHA_NO_COMPRESSION) {
    124     int y;
    125     const uint8_t* prev_line = dec->alpha_prev_line;
    126     const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width;
    127     uint8_t* dst = dec->alpha_plane + row * width;
    128     assert(deltas <= &dec->alpha_data[dec->alpha_data_size]);
    129     assert(WebPUnfilters[alph_dec->filter] != NULL);
    130     for (y = 0; y < num_rows; ++y) {
    131       WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width);
    132       prev_line = dst;
    133       dst += width;
    134       deltas += width;
    135     }
    136     dec->alpha_prev_line = prev_line;
    137   } else {  // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION
    138     assert(alph_dec->vp8l_dec != NULL);
    139     if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
    140       return 0;
    141     }
    142   }
    143 
    144   if (row + num_rows >= height) {
    145     dec->is_alpha_decoded = 1;
    146   }
    147   return 1;
    148 }
    149 
    150 WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
    151                                              const VP8Io* const io) {
    152   const int stride = io->width;
    153   const int height = io->crop_bottom;
    154   const uint64_t alpha_size = (uint64_t)stride * height;
    155   assert(dec->alpha_plane_mem == NULL);
    156   dec->alpha_plane_mem =
    157       (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane));
    158   if (dec->alpha_plane_mem == NULL) {
    159     return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
    160                        "Alpha decoder initialization failed.");
    161   }
    162   dec->alpha_plane = dec->alpha_plane_mem;
    163   dec->alpha_prev_line = NULL;
    164   return 1;
    165 }
    166 
    167 void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
    168   assert(dec != NULL);
    169   WebPSafeFree(dec->alpha_plane_mem);
    170   dec->alpha_plane_mem = NULL;
    171   dec->alpha_plane = NULL;
    172   ALPHDelete(dec->alph_dec);
    173   dec->alph_dec = NULL;
    174 }
    175 
    176 //------------------------------------------------------------------------------
    177 // Main entry point.
    178 
    179 WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
    180                                                      const VP8Io* const io,
    181                                                      int row, int num_rows) {
    182   const int width = io->width;
    183   const int height = io->crop_bottom;
    184 
    185   assert(dec != NULL && io != NULL);
    186 
    187   if (row < 0 || num_rows <= 0 || row + num_rows > height) {
    188     return NULL;
    189   }
    190 
    191   if (!dec->is_alpha_decoded) {
    192     if (dec->alph_dec == NULL) {    // Initialize decoder.
    193       dec->alph_dec = ALPHNew();
    194       if (dec->alph_dec == NULL) {
    195         VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
    196                     "Alpha decoder initialization failed.");
    197         return NULL;
    198       }
    199       if (!AllocateAlphaPlane(dec, io)) goto Error;
    200       if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size,
    201                     io, dec->alpha_plane)) {
    202         VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec;
    203         VP8SetError(dec,
    204                     (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
    205                                        : vp8l_dec->status,
    206                     "Alpha decoder initialization failed.");
    207         goto Error;
    208       }
    209       // if we allowed use of alpha dithering, check whether it's needed at all
    210       if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) {
    211         dec->alpha_dithering = 0;    // disable dithering
    212       } else {
    213         num_rows = height - row;     // decode everything in one pass
    214       }
    215     }
    216 
    217     assert(dec->alph_dec != NULL);
    218     assert(row + num_rows <= height);
    219     if (!ALPHDecode(dec, row, num_rows)) goto Error;
    220 
    221     if (dec->is_alpha_decoded) {   // finished?
    222       ALPHDelete(dec->alph_dec);
    223       dec->alph_dec = NULL;
    224       if (dec->alpha_dithering > 0) {
    225         uint8_t* const alpha = dec->alpha_plane + io->crop_top * width
    226                              + io->crop_left;
    227         if (!WebPDequantizeLevels(alpha,
    228                                   io->crop_right - io->crop_left,
    229                                   io->crop_bottom - io->crop_top,
    230                                   width, dec->alpha_dithering)) {
    231           goto Error;
    232         }
    233       }
    234     }
    235   }
    236 
    237   // Return a pointer to the current decoded row.
    238   return dec->alpha_plane + row * width;
    239 
    240  Error:
    241   WebPDeallocateAlphaMemory(dec);
    242   return NULL;
    243 }