Home | History | Annotate | Download | only in enc
      1 // Copyright 2012 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 // main entry for the lossless encoder.
     11 //
     12 // Author: Vikas Arora (vikaas.arora (at) gmail.com)
     13 //
     14 
     15 #include <assert.h>
     16 #include <stdlib.h>
     17 
     18 #include "./backward_references_enc.h"
     19 #include "./histogram_enc.h"
     20 #include "./vp8i_enc.h"
     21 #include "./vp8li_enc.h"
     22 #include "../dsp/lossless.h"
     23 #include "../dsp/lossless_common.h"
     24 #include "../utils/bit_writer_utils.h"
     25 #include "../utils/huffman_encode_utils.h"
     26 #include "../utils/utils.h"
     27 #include "../webp/format_constants.h"
     28 
     29 #include "./delta_palettization_enc.h"
     30 
     31 #define PALETTE_KEY_RIGHT_SHIFT   22  // Key for 1K buffer.
     32 // Maximum number of histogram images (sub-blocks).
     33 #define MAX_HUFF_IMAGE_SIZE       2600
     34 
     35 // Palette reordering for smaller sum of deltas (and for smaller storage).
     36 
     37 static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
     38   const uint32_t a = WebPMemToUint32((uint8_t*)p1);
     39   const uint32_t b = WebPMemToUint32((uint8_t*)p2);
     40   assert(a != b);
     41   return (a < b) ? -1 : 1;
     42 }
     43 
     44 static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
     45   return (v <= 128) ? v : (256 - v);
     46 }
     47 
     48 // Computes a value that is related to the entropy created by the
     49 // palette entry diff.
     50 //
     51 // Note that the last & 0xff is a no-operation in the next statement, but
     52 // removed by most compilers and is here only for regularity of the code.
     53 static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
     54   const uint32_t diff = VP8LSubPixels(col1, col2);
     55   const int kMoreWeightForRGBThanForAlpha = 9;
     56   uint32_t score;
     57   score =  PaletteComponentDistance((diff >>  0) & 0xff);
     58   score += PaletteComponentDistance((diff >>  8) & 0xff);
     59   score += PaletteComponentDistance((diff >> 16) & 0xff);
     60   score *= kMoreWeightForRGBThanForAlpha;
     61   score += PaletteComponentDistance((diff >> 24) & 0xff);
     62   return score;
     63 }
     64 
     65 static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
     66   const uint32_t tmp = *col1;
     67   *col1 = *col2;
     68   *col2 = tmp;
     69 }
     70 
     71 static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
     72   // Find greedily always the closest color of the predicted color to minimize
     73   // deltas in the palette. This reduces storage needs since the
     74   // palette is stored with delta encoding.
     75   uint32_t predict = 0x00000000;
     76   int i, k;
     77   for (i = 0; i < num_colors; ++i) {
     78     int best_ix = i;
     79     uint32_t best_score = ~0U;
     80     for (k = i; k < num_colors; ++k) {
     81       const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
     82       if (best_score > cur_score) {
     83         best_score = cur_score;
     84         best_ix = k;
     85       }
     86     }
     87     SwapColor(&palette[best_ix], &palette[i]);
     88     predict = palette[i];
     89   }
     90 }
     91 
     92 // The palette has been sorted by alpha. This function checks if the other
     93 // components of the palette have a monotonic development with regards to
     94 // position in the palette. If all have monotonic development, there is
     95 // no benefit to re-organize them greedily. A monotonic development
     96 // would be spotted in green-only situations (like lossy alpha) or gray-scale
     97 // images.
     98 static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
     99   uint32_t predict = 0x000000;
    100   int i;
    101   uint8_t sign_found = 0x00;
    102   for (i = 0; i < num_colors; ++i) {
    103     const uint32_t diff = VP8LSubPixels(palette[i], predict);
    104     const uint8_t rd = (diff >> 16) & 0xff;
    105     const uint8_t gd = (diff >>  8) & 0xff;
    106     const uint8_t bd = (diff >>  0) & 0xff;
    107     if (rd != 0x00) {
    108       sign_found |= (rd < 0x80) ? 1 : 2;
    109     }
    110     if (gd != 0x00) {
    111       sign_found |= (gd < 0x80) ? 8 : 16;
    112     }
    113     if (bd != 0x00) {
    114       sign_found |= (bd < 0x80) ? 64 : 128;
    115     }
    116     predict = palette[i];
    117   }
    118   return (sign_found & (sign_found << 1)) != 0;  // two consequent signs.
    119 }
    120 
    121 // -----------------------------------------------------------------------------
    122 // Palette
    123 
    124 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
    125 // creates a palette and returns true, else returns false.
    126 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
    127                                    int low_effort,
    128                                    uint32_t palette[MAX_PALETTE_SIZE],
    129                                    int* const palette_size) {
    130   const int num_colors = WebPGetColorPalette(pic, palette);
    131   if (num_colors > MAX_PALETTE_SIZE) return 0;
    132   *palette_size = num_colors;
    133   qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
    134   if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
    135     GreedyMinimizeDeltas(palette, num_colors);
    136   }
    137   return 1;
    138 }
    139 
    140 // These five modes are evaluated and their respective entropy is computed.
    141 typedef enum {
    142   kDirect = 0,
    143   kSpatial = 1,
    144   kSubGreen = 2,
    145   kSpatialSubGreen = 3,
    146   kPalette = 4,
    147   kNumEntropyIx = 5
    148 } EntropyIx;
    149 
    150 typedef enum {
    151   kHistoAlpha = 0,
    152   kHistoAlphaPred,
    153   kHistoGreen,
    154   kHistoGreenPred,
    155   kHistoRed,
    156   kHistoRedPred,
    157   kHistoBlue,
    158   kHistoBluePred,
    159   kHistoRedSubGreen,
    160   kHistoRedPredSubGreen,
    161   kHistoBlueSubGreen,
    162   kHistoBluePredSubGreen,
    163   kHistoPalette,
    164   kHistoTotal  // Must be last.
    165 } HistoIx;
    166 
    167 static void AddSingleSubGreen(int p, uint32_t* const r, uint32_t* const b) {
    168   const int green = p >> 8;  // The upper bits are masked away later.
    169   ++r[((p >> 16) - green) & 0xff];
    170   ++b[((p >>  0) - green) & 0xff];
    171 }
    172 
    173 static void AddSingle(uint32_t p,
    174                       uint32_t* const a, uint32_t* const r,
    175                       uint32_t* const g, uint32_t* const b) {
    176   ++a[(p >> 24) & 0xff];
    177   ++r[(p >> 16) & 0xff];
    178   ++g[(p >>  8) & 0xff];
    179   ++b[(p >>  0) & 0xff];
    180 }
    181 
    182 static WEBP_INLINE uint32_t HashPix(uint32_t pix) {
    183   // Note that masking with 0xffffffffu is for preventing an
    184   // 'unsigned int overflow' warning. Doesn't impact the compiled code.
    185   return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24;
    186 }
    187 
    188 static int AnalyzeEntropy(const uint32_t* argb,
    189                           int width, int height, int argb_stride,
    190                           int use_palette,
    191                           EntropyIx* const min_entropy_ix,
    192                           int* const red_and_blue_always_zero) {
    193   // Allocate histogram set with cache_bits = 0.
    194   uint32_t* const histo =
    195       (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
    196   if (histo != NULL) {
    197     int i, x, y;
    198     const uint32_t* prev_row = argb;
    199     const uint32_t* curr_row = argb + argb_stride;
    200     for (y = 1; y < height; ++y) {
    201       uint32_t prev_pix = curr_row[0];
    202       for (x = 1; x < width; ++x) {
    203         const uint32_t pix = curr_row[x];
    204         const uint32_t pix_diff = VP8LSubPixels(pix, prev_pix);
    205         if ((pix_diff == 0) || (pix == prev_row[x])) continue;
    206         prev_pix = pix;
    207         AddSingle(pix,
    208                   &histo[kHistoAlpha * 256],
    209                   &histo[kHistoRed * 256],
    210                   &histo[kHistoGreen * 256],
    211                   &histo[kHistoBlue * 256]);
    212         AddSingle(pix_diff,
    213                   &histo[kHistoAlphaPred * 256],
    214                   &histo[kHistoRedPred * 256],
    215                   &histo[kHistoGreenPred * 256],
    216                   &histo[kHistoBluePred * 256]);
    217         AddSingleSubGreen(pix,
    218                           &histo[kHistoRedSubGreen * 256],
    219                           &histo[kHistoBlueSubGreen * 256]);
    220         AddSingleSubGreen(pix_diff,
    221                           &histo[kHistoRedPredSubGreen * 256],
    222                           &histo[kHistoBluePredSubGreen * 256]);
    223         {
    224           // Approximate the palette by the entropy of the multiplicative hash.
    225           const uint32_t hash = HashPix(pix);
    226           ++histo[kHistoPalette * 256 + hash];
    227         }
    228       }
    229       prev_row = curr_row;
    230       curr_row += argb_stride;
    231     }
    232     {
    233       double entropy_comp[kHistoTotal];
    234       double entropy[kNumEntropyIx];
    235       int k;
    236       int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
    237       int j;
    238       // Let's add one zero to the predicted histograms. The zeros are removed
    239       // too efficiently by the pix_diff == 0 comparison, at least one of the
    240       // zeros is likely to exist.
    241       ++histo[kHistoRedPredSubGreen * 256];
    242       ++histo[kHistoBluePredSubGreen * 256];
    243       ++histo[kHistoRedPred * 256];
    244       ++histo[kHistoGreenPred * 256];
    245       ++histo[kHistoBluePred * 256];
    246       ++histo[kHistoAlphaPred * 256];
    247 
    248       for (j = 0; j < kHistoTotal; ++j) {
    249         entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256, NULL);
    250       }
    251       entropy[kDirect] = entropy_comp[kHistoAlpha] +
    252           entropy_comp[kHistoRed] +
    253           entropy_comp[kHistoGreen] +
    254           entropy_comp[kHistoBlue];
    255       entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
    256           entropy_comp[kHistoRedPred] +
    257           entropy_comp[kHistoGreenPred] +
    258           entropy_comp[kHistoBluePred];
    259       entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
    260           entropy_comp[kHistoRedSubGreen] +
    261           entropy_comp[kHistoGreen] +
    262           entropy_comp[kHistoBlueSubGreen];
    263       entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
    264           entropy_comp[kHistoRedPredSubGreen] +
    265           entropy_comp[kHistoGreenPred] +
    266           entropy_comp[kHistoBluePredSubGreen];
    267       // Palette mode seems more efficient in a breakeven case. Bias with 1.0.
    268       entropy[kPalette] = entropy_comp[kHistoPalette] - 1.0;
    269 
    270       *min_entropy_ix = kDirect;
    271       for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
    272         if (entropy[*min_entropy_ix] > entropy[k]) {
    273           *min_entropy_ix = (EntropyIx)k;
    274         }
    275       }
    276       *red_and_blue_always_zero = 1;
    277       // Let's check if the histogram of the chosen entropy mode has
    278       // non-zero red and blue values. If all are zero, we can later skip
    279       // the cross color optimization.
    280       {
    281         static const uint8_t kHistoPairs[5][2] = {
    282           { kHistoRed, kHistoBlue },
    283           { kHistoRedPred, kHistoBluePred },
    284           { kHistoRedSubGreen, kHistoBlueSubGreen },
    285           { kHistoRedPredSubGreen, kHistoBluePredSubGreen },
    286           { kHistoRed, kHistoBlue }
    287         };
    288         const uint32_t* const red_histo =
    289             &histo[256 * kHistoPairs[*min_entropy_ix][0]];
    290         const uint32_t* const blue_histo =
    291             &histo[256 * kHistoPairs[*min_entropy_ix][1]];
    292         for (i = 1; i < 256; ++i) {
    293           if ((red_histo[i] | blue_histo[i]) != 0) {
    294             *red_and_blue_always_zero = 0;
    295             break;
    296           }
    297         }
    298       }
    299     }
    300     WebPSafeFree(histo);
    301     return 1;
    302   } else {
    303     return 0;
    304   }
    305 }
    306 
    307 static int GetHistoBits(int method, int use_palette, int width, int height) {
    308   // Make tile size a function of encoding method (Range: 0 to 6).
    309   int histo_bits = (use_palette ? 9 : 7) - method;
    310   while (1) {
    311     const int huff_image_size = VP8LSubSampleSize(width, histo_bits) *
    312                                 VP8LSubSampleSize(height, histo_bits);
    313     if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
    314     ++histo_bits;
    315   }
    316   return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
    317          (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
    318 }
    319 
    320 static int GetTransformBits(int method, int histo_bits) {
    321   const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
    322   const int res =
    323       (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits;
    324   assert(res <= MAX_TRANSFORM_BITS);
    325   return res;
    326 }
    327 
    328 static int AnalyzeAndInit(VP8LEncoder* const enc) {
    329   const WebPPicture* const pic = enc->pic_;
    330   const int width = pic->width;
    331   const int height = pic->height;
    332   const int pix_cnt = width * height;
    333   const WebPConfig* const config = enc->config_;
    334   const int method = config->method;
    335   const int low_effort = (config->method == 0);
    336   // we round the block size up, so we're guaranteed to have
    337   // at max MAX_REFS_BLOCK_PER_IMAGE blocks used:
    338   int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
    339   assert(pic != NULL && pic->argb != NULL);
    340 
    341   enc->use_cross_color_ = 0;
    342   enc->use_predict_ = 0;
    343   enc->use_subtract_green_ = 0;
    344   enc->use_palette_ =
    345       AnalyzeAndCreatePalette(pic, low_effort,
    346                               enc->palette_, &enc->palette_size_);
    347 
    348   // TODO(jyrki): replace the decision to be based on an actual estimate
    349   // of entropy, or even spatial variance of entropy.
    350   enc->histo_bits_ = GetHistoBits(method, enc->use_palette_,
    351                                   pic->width, pic->height);
    352   enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_);
    353 
    354   if (low_effort) {
    355     // AnalyzeEntropy is somewhat slow.
    356     enc->use_predict_ = !enc->use_palette_;
    357     enc->use_subtract_green_ = !enc->use_palette_;
    358     enc->use_cross_color_ = 0;
    359   } else {
    360     int red_and_blue_always_zero;
    361     EntropyIx min_entropy_ix;
    362     if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride,
    363                         enc->use_palette_, &min_entropy_ix,
    364                         &red_and_blue_always_zero)) {
    365       return 0;
    366     }
    367     enc->use_palette_ = (min_entropy_ix == kPalette);
    368     enc->use_subtract_green_ =
    369         (min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen);
    370     enc->use_predict_ =
    371         (min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen);
    372     enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
    373   }
    374 
    375   if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
    376 
    377   // palette-friendly input typically uses less literals
    378   //  -> reduce block size a bit
    379   if (enc->use_palette_) refs_block_size /= 2;
    380   VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size);
    381   VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size);
    382 
    383   return 1;
    384 }
    385 
    386 // Returns false in case of memory error.
    387 static int GetHuffBitLengthsAndCodes(
    388     const VP8LHistogramSet* const histogram_image,
    389     HuffmanTreeCode* const huffman_codes) {
    390   int i, k;
    391   int ok = 0;
    392   uint64_t total_length_size = 0;
    393   uint8_t* mem_buf = NULL;
    394   const int histogram_image_size = histogram_image->size;
    395   int max_num_symbols = 0;
    396   uint8_t* buf_rle = NULL;
    397   HuffmanTree* huff_tree = NULL;
    398 
    399   // Iterate over all histograms and get the aggregate number of codes used.
    400   for (i = 0; i < histogram_image_size; ++i) {
    401     const VP8LHistogram* const histo = histogram_image->histograms[i];
    402     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
    403     for (k = 0; k < 5; ++k) {
    404       const int num_symbols =
    405           (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
    406           (k == 4) ? NUM_DISTANCE_CODES : 256;
    407       codes[k].num_symbols = num_symbols;
    408       total_length_size += num_symbols;
    409     }
    410   }
    411 
    412   // Allocate and Set Huffman codes.
    413   {
    414     uint16_t* codes;
    415     uint8_t* lengths;
    416     mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
    417                                        sizeof(*lengths) + sizeof(*codes));
    418     if (mem_buf == NULL) goto End;
    419 
    420     codes = (uint16_t*)mem_buf;
    421     lengths = (uint8_t*)&codes[total_length_size];
    422     for (i = 0; i < 5 * histogram_image_size; ++i) {
    423       const int bit_length = huffman_codes[i].num_symbols;
    424       huffman_codes[i].codes = codes;
    425       huffman_codes[i].code_lengths = lengths;
    426       codes += bit_length;
    427       lengths += bit_length;
    428       if (max_num_symbols < bit_length) {
    429         max_num_symbols = bit_length;
    430       }
    431     }
    432   }
    433 
    434   buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols);
    435   huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols,
    436                                            sizeof(*huff_tree));
    437   if (buf_rle == NULL || huff_tree == NULL) goto End;
    438 
    439   // Create Huffman trees.
    440   for (i = 0; i < histogram_image_size; ++i) {
    441     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
    442     VP8LHistogram* const histo = histogram_image->histograms[i];
    443     VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0);
    444     VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1);
    445     VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2);
    446     VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3);
    447     VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4);
    448   }
    449   ok = 1;
    450  End:
    451   WebPSafeFree(huff_tree);
    452   WebPSafeFree(buf_rle);
    453   if (!ok) {
    454     WebPSafeFree(mem_buf);
    455     memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
    456   }
    457   return ok;
    458 }
    459 
    460 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
    461     VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
    462   // RFC 1951 will calm you down if you are worried about this funny sequence.
    463   // This sequence is tuned from that, but more weighted for lower symbol count,
    464   // and more spiking histograms.
    465   static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
    466     17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
    467   };
    468   int i;
    469   // Throw away trailing zeros:
    470   int codes_to_store = CODE_LENGTH_CODES;
    471   for (; codes_to_store > 4; --codes_to_store) {
    472     if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
    473       break;
    474     }
    475   }
    476   VP8LPutBits(bw, codes_to_store - 4, 4);
    477   for (i = 0; i < codes_to_store; ++i) {
    478     VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3);
    479   }
    480 }
    481 
    482 static void ClearHuffmanTreeIfOnlyOneSymbol(
    483     HuffmanTreeCode* const huffman_code) {
    484   int k;
    485   int count = 0;
    486   for (k = 0; k < huffman_code->num_symbols; ++k) {
    487     if (huffman_code->code_lengths[k] != 0) {
    488       ++count;
    489       if (count > 1) return;
    490     }
    491   }
    492   for (k = 0; k < huffman_code->num_symbols; ++k) {
    493     huffman_code->code_lengths[k] = 0;
    494     huffman_code->codes[k] = 0;
    495   }
    496 }
    497 
    498 static void StoreHuffmanTreeToBitMask(
    499     VP8LBitWriter* const bw,
    500     const HuffmanTreeToken* const tokens, const int num_tokens,
    501     const HuffmanTreeCode* const huffman_code) {
    502   int i;
    503   for (i = 0; i < num_tokens; ++i) {
    504     const int ix = tokens[i].code;
    505     const int extra_bits = tokens[i].extra_bits;
    506     VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]);
    507     switch (ix) {
    508       case 16:
    509         VP8LPutBits(bw, extra_bits, 2);
    510         break;
    511       case 17:
    512         VP8LPutBits(bw, extra_bits, 3);
    513         break;
    514       case 18:
    515         VP8LPutBits(bw, extra_bits, 7);
    516         break;
    517     }
    518   }
    519 }
    520 
    521 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
    522 static void StoreFullHuffmanCode(VP8LBitWriter* const bw,
    523                                  HuffmanTree* const huff_tree,
    524                                  HuffmanTreeToken* const tokens,
    525                                  const HuffmanTreeCode* const tree) {
    526   uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
    527   uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
    528   const int max_tokens = tree->num_symbols;
    529   int num_tokens;
    530   HuffmanTreeCode huffman_code;
    531   huffman_code.num_symbols = CODE_LENGTH_CODES;
    532   huffman_code.code_lengths = code_length_bitdepth;
    533   huffman_code.codes = code_length_bitdepth_symbols;
    534 
    535   VP8LPutBits(bw, 0, 1);
    536   num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
    537   {
    538     uint32_t histogram[CODE_LENGTH_CODES] = { 0 };
    539     uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 };
    540     int i;
    541     for (i = 0; i < num_tokens; ++i) {
    542       ++histogram[tokens[i].code];
    543     }
    544 
    545     VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code);
    546   }
    547 
    548   StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
    549   ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
    550   {
    551     int trailing_zero_bits = 0;
    552     int trimmed_length = num_tokens;
    553     int write_trimmed_length;
    554     int length;
    555     int i = num_tokens;
    556     while (i-- > 0) {
    557       const int ix = tokens[i].code;
    558       if (ix == 0 || ix == 17 || ix == 18) {
    559         --trimmed_length;   // discount trailing zeros
    560         trailing_zero_bits += code_length_bitdepth[ix];
    561         if (ix == 17) {
    562           trailing_zero_bits += 3;
    563         } else if (ix == 18) {
    564           trailing_zero_bits += 7;
    565         }
    566       } else {
    567         break;
    568       }
    569     }
    570     write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
    571     length = write_trimmed_length ? trimmed_length : num_tokens;
    572     VP8LPutBits(bw, write_trimmed_length, 1);
    573     if (write_trimmed_length) {
    574       const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
    575       const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
    576       VP8LPutBits(bw, nbitpairs - 1, 3);
    577       assert(trimmed_length >= 2);
    578       VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2);
    579     }
    580     StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
    581   }
    582 }
    583 
    584 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
    585 static void StoreHuffmanCode(VP8LBitWriter* const bw,
    586                              HuffmanTree* const huff_tree,
    587                              HuffmanTreeToken* const tokens,
    588                              const HuffmanTreeCode* const huffman_code) {
    589   int i;
    590   int count = 0;
    591   int symbols[2] = { 0, 0 };
    592   const int kMaxBits = 8;
    593   const int kMaxSymbol = 1 << kMaxBits;
    594 
    595   // Check whether it's a small tree.
    596   for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
    597     if (huffman_code->code_lengths[i] != 0) {
    598       if (count < 2) symbols[count] = i;
    599       ++count;
    600     }
    601   }
    602 
    603   if (count == 0) {   // emit minimal tree for empty cases
    604     // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
    605     VP8LPutBits(bw, 0x01, 4);
    606   } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
    607     VP8LPutBits(bw, 1, 1);  // Small tree marker to encode 1 or 2 symbols.
    608     VP8LPutBits(bw, count - 1, 1);
    609     if (symbols[0] <= 1) {
    610       VP8LPutBits(bw, 0, 1);  // Code bit for small (1 bit) symbol value.
    611       VP8LPutBits(bw, symbols[0], 1);
    612     } else {
    613       VP8LPutBits(bw, 1, 1);
    614       VP8LPutBits(bw, symbols[0], 8);
    615     }
    616     if (count == 2) {
    617       VP8LPutBits(bw, symbols[1], 8);
    618     }
    619   } else {
    620     StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code);
    621   }
    622 }
    623 
    624 static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw,
    625                              const HuffmanTreeCode* const code,
    626                              int code_index) {
    627   const int depth = code->code_lengths[code_index];
    628   const int symbol = code->codes[code_index];
    629   VP8LPutBits(bw, symbol, depth);
    630 }
    631 
    632 static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
    633     VP8LBitWriter* const bw,
    634     const HuffmanTreeCode* const code,
    635     int code_index,
    636     int bits,
    637     int n_bits) {
    638   const int depth = code->code_lengths[code_index];
    639   const int symbol = code->codes[code_index];
    640   VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
    641 }
    642 
    643 static WebPEncodingError StoreImageToBitMask(
    644     VP8LBitWriter* const bw, int width, int histo_bits,
    645     VP8LBackwardRefs* const refs,
    646     const uint16_t* histogram_symbols,
    647     const HuffmanTreeCode* const huffman_codes) {
    648   const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
    649   const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
    650   // x and y trace the position in the image.
    651   int x = 0;
    652   int y = 0;
    653   int tile_x = x & tile_mask;
    654   int tile_y = y & tile_mask;
    655   int histogram_ix = histogram_symbols[0];
    656   const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
    657   VP8LRefsCursor c = VP8LRefsCursorInit(refs);
    658   while (VP8LRefsCursorOk(&c)) {
    659     const PixOrCopy* const v = c.cur_pos;
    660     if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
    661       tile_x = x & tile_mask;
    662       tile_y = y & tile_mask;
    663       histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize +
    664                                        (x >> histo_bits)];
    665       codes = huffman_codes + 5 * histogram_ix;
    666     }
    667     if (PixOrCopyIsLiteral(v)) {
    668       static const int order[] = { 1, 2, 0, 3 };
    669       int k;
    670       for (k = 0; k < 4; ++k) {
    671         const int code = PixOrCopyLiteral(v, order[k]);
    672         WriteHuffmanCode(bw, codes + k, code);
    673       }
    674     } else if (PixOrCopyIsCacheIdx(v)) {
    675       const int code = PixOrCopyCacheIdx(v);
    676       const int literal_ix = 256 + NUM_LENGTH_CODES + code;
    677       WriteHuffmanCode(bw, codes, literal_ix);
    678     } else {
    679       int bits, n_bits;
    680       int code;
    681 
    682       const int distance = PixOrCopyDistance(v);
    683       VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
    684       WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits);
    685 
    686       // Don't write the distance with the extra bits code since
    687       // the distance can be up to 18 bits of extra bits, and the prefix
    688       // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits.
    689       // TODO(jyrki): optimize this further.
    690       VP8LPrefixEncode(distance, &code, &n_bits, &bits);
    691       WriteHuffmanCode(bw, codes + 4, code);
    692       VP8LPutBits(bw, bits, n_bits);
    693     }
    694     x += PixOrCopyLength(v);
    695     while (x >= width) {
    696       x -= width;
    697       ++y;
    698     }
    699     VP8LRefsCursorNext(&c);
    700   }
    701   return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
    702 }
    703 
    704 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
    705 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
    706                                               const uint32_t* const argb,
    707                                               VP8LHashChain* const hash_chain,
    708                                               VP8LBackwardRefs refs_array[2],
    709                                               int width, int height,
    710                                               int quality, int low_effort) {
    711   int i;
    712   int max_tokens = 0;
    713   WebPEncodingError err = VP8_ENC_OK;
    714   VP8LBackwardRefs* refs;
    715   HuffmanTreeToken* tokens = NULL;
    716   HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
    717   const uint16_t histogram_symbols[1] = { 0 };    // only one tree, one symbol
    718   int cache_bits = 0;
    719   VP8LHistogramSet* histogram_image = NULL;
    720   HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
    721         3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
    722   if (huff_tree == NULL) {
    723     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    724     goto Error;
    725   }
    726 
    727   // Calculate backward references from ARGB image.
    728   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
    729                          low_effort)) {
    730     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    731     goto Error;
    732   }
    733   refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits,
    734                                    hash_chain, refs_array);
    735   if (refs == NULL) {
    736     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    737     goto Error;
    738   }
    739   histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
    740   if (histogram_image == NULL) {
    741     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    742     goto Error;
    743   }
    744 
    745   // Build histogram image and symbols from backward references.
    746   VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
    747 
    748   // Create Huffman bit lengths and codes for each histogram image.
    749   assert(histogram_image->size == 1);
    750   if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
    751     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    752     goto Error;
    753   }
    754 
    755   // No color cache, no Huffman image.
    756   VP8LPutBits(bw, 0, 1);
    757 
    758   // Find maximum number of symbols for the huffman tree-set.
    759   for (i = 0; i < 5; ++i) {
    760     HuffmanTreeCode* const codes = &huffman_codes[i];
    761     if (max_tokens < codes->num_symbols) {
    762       max_tokens = codes->num_symbols;
    763     }
    764   }
    765 
    766   tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
    767   if (tokens == NULL) {
    768     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    769     goto Error;
    770   }
    771 
    772   // Store Huffman codes.
    773   for (i = 0; i < 5; ++i) {
    774     HuffmanTreeCode* const codes = &huffman_codes[i];
    775     StoreHuffmanCode(bw, huff_tree, tokens, codes);
    776     ClearHuffmanTreeIfOnlyOneSymbol(codes);
    777   }
    778 
    779   // Store actual literals.
    780   err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
    781                             huffman_codes);
    782 
    783  Error:
    784   WebPSafeFree(tokens);
    785   WebPSafeFree(huff_tree);
    786   VP8LFreeHistogramSet(histogram_image);
    787   WebPSafeFree(huffman_codes[0].codes);
    788   return err;
    789 }
    790 
    791 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
    792                                              const uint32_t* const argb,
    793                                              VP8LHashChain* const hash_chain,
    794                                              VP8LBackwardRefs refs_array[2],
    795                                              int width, int height, int quality,
    796                                              int low_effort,
    797                                              int use_cache, int* cache_bits,
    798                                              int histogram_bits,
    799                                              size_t init_byte_position,
    800                                              int* const hdr_size,
    801                                              int* const data_size) {
    802   WebPEncodingError err = VP8_ENC_OK;
    803   const uint32_t histogram_image_xysize =
    804       VP8LSubSampleSize(width, histogram_bits) *
    805       VP8LSubSampleSize(height, histogram_bits);
    806   VP8LHistogramSet* histogram_image = NULL;
    807   VP8LHistogramSet* tmp_histos = NULL;
    808   int histogram_image_size = 0;
    809   size_t bit_array_size = 0;
    810   HuffmanTree* huff_tree = NULL;
    811   HuffmanTreeToken* tokens = NULL;
    812   HuffmanTreeCode* huffman_codes = NULL;
    813   VP8LBackwardRefs refs;
    814   VP8LBackwardRefs* best_refs;
    815   uint16_t* const histogram_symbols =
    816       (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
    817                                 sizeof(*histogram_symbols));
    818   assert(histogram_bits >= MIN_HUFFMAN_BITS);
    819   assert(histogram_bits <= MAX_HUFFMAN_BITS);
    820   assert(hdr_size != NULL);
    821   assert(data_size != NULL);
    822 
    823   VP8LBackwardRefsInit(&refs, refs_array[0].block_size_);
    824   if (histogram_symbols == NULL) {
    825     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    826     goto Error;
    827   }
    828 
    829   if (use_cache) {
    830     // If the value is different from zero, it has been set during the
    831     // palette analysis.
    832     if (*cache_bits == 0) *cache_bits = MAX_COLOR_CACHE_BITS;
    833   } else {
    834     *cache_bits = 0;
    835   }
    836   // 'best_refs' is the reference to the best backward refs and points to one
    837   // of refs_array[0] or refs_array[1].
    838   // Calculate backward references from ARGB image.
    839   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
    840                          low_effort)) {
    841     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    842     goto Error;
    843   }
    844   best_refs = VP8LGetBackwardReferences(width, height, argb, quality,
    845                                         low_effort, cache_bits, hash_chain,
    846                                         refs_array);
    847   if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) {
    848     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    849     goto Error;
    850   }
    851   histogram_image =
    852       VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
    853   tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits);
    854   if (histogram_image == NULL || tmp_histos == NULL) {
    855     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    856     goto Error;
    857   }
    858 
    859   // Build histogram image and symbols from backward references.
    860   if (!VP8LGetHistoImageSymbols(width, height, &refs, quality, low_effort,
    861                                 histogram_bits, *cache_bits, histogram_image,
    862                                 tmp_histos, histogram_symbols)) {
    863     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    864     goto Error;
    865   }
    866   // Create Huffman bit lengths and codes for each histogram image.
    867   histogram_image_size = histogram_image->size;
    868   bit_array_size = 5 * histogram_image_size;
    869   huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
    870                                                    sizeof(*huffman_codes));
    871   // Note: some histogram_image entries may point to tmp_histos[], so the latter
    872   // need to outlive the following call to GetHuffBitLengthsAndCodes().
    873   if (huffman_codes == NULL ||
    874       !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
    875     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    876     goto Error;
    877   }
    878   // Free combined histograms.
    879   VP8LFreeHistogramSet(histogram_image);
    880   histogram_image = NULL;
    881 
    882   // Free scratch histograms.
    883   VP8LFreeHistogramSet(tmp_histos);
    884   tmp_histos = NULL;
    885 
    886   // Color Cache parameters.
    887   if (*cache_bits > 0) {
    888     VP8LPutBits(bw, 1, 1);
    889     VP8LPutBits(bw, *cache_bits, 4);
    890   } else {
    891     VP8LPutBits(bw, 0, 1);
    892   }
    893 
    894   // Huffman image + meta huffman.
    895   {
    896     const int write_histogram_image = (histogram_image_size > 1);
    897     VP8LPutBits(bw, write_histogram_image, 1);
    898     if (write_histogram_image) {
    899       uint32_t* const histogram_argb =
    900           (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
    901                                     sizeof(*histogram_argb));
    902       int max_index = 0;
    903       uint32_t i;
    904       if (histogram_argb == NULL) {
    905         err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    906         goto Error;
    907       }
    908       for (i = 0; i < histogram_image_xysize; ++i) {
    909         const int symbol_index = histogram_symbols[i] & 0xffff;
    910         histogram_argb[i] = (symbol_index << 8);
    911         if (symbol_index >= max_index) {
    912           max_index = symbol_index + 1;
    913         }
    914       }
    915       histogram_image_size = max_index;
    916 
    917       VP8LPutBits(bw, histogram_bits - 2, 3);
    918       err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
    919                                  VP8LSubSampleSize(width, histogram_bits),
    920                                  VP8LSubSampleSize(height, histogram_bits),
    921                                  quality, low_effort);
    922       WebPSafeFree(histogram_argb);
    923       if (err != VP8_ENC_OK) goto Error;
    924     }
    925   }
    926 
    927   // Store Huffman codes.
    928   {
    929     int i;
    930     int max_tokens = 0;
    931     huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES,
    932                                              sizeof(*huff_tree));
    933     if (huff_tree == NULL) {
    934       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    935       goto Error;
    936     }
    937     // Find maximum number of symbols for the huffman tree-set.
    938     for (i = 0; i < 5 * histogram_image_size; ++i) {
    939       HuffmanTreeCode* const codes = &huffman_codes[i];
    940       if (max_tokens < codes->num_symbols) {
    941         max_tokens = codes->num_symbols;
    942       }
    943     }
    944     tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens,
    945                                                sizeof(*tokens));
    946     if (tokens == NULL) {
    947       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
    948       goto Error;
    949     }
    950     for (i = 0; i < 5 * histogram_image_size; ++i) {
    951       HuffmanTreeCode* const codes = &huffman_codes[i];
    952       StoreHuffmanCode(bw, huff_tree, tokens, codes);
    953       ClearHuffmanTreeIfOnlyOneSymbol(codes);
    954     }
    955   }
    956 
    957   *hdr_size = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
    958   // Store actual literals.
    959   err = StoreImageToBitMask(bw, width, histogram_bits, &refs,
    960                             histogram_symbols, huffman_codes);
    961   *data_size =
    962         (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
    963 
    964  Error:
    965   WebPSafeFree(tokens);
    966   WebPSafeFree(huff_tree);
    967   VP8LFreeHistogramSet(histogram_image);
    968   VP8LFreeHistogramSet(tmp_histos);
    969   VP8LBackwardRefsClear(&refs);
    970   if (huffman_codes != NULL) {
    971     WebPSafeFree(huffman_codes->codes);
    972     WebPSafeFree(huffman_codes);
    973   }
    974   WebPSafeFree(histogram_symbols);
    975   return err;
    976 }
    977 
    978 // -----------------------------------------------------------------------------
    979 // Transforms
    980 
    981 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
    982                                VP8LBitWriter* const bw) {
    983   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
    984   VP8LPutBits(bw, SUBTRACT_GREEN, 2);
    985   VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
    986 }
    987 
    988 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
    989                                             int width, int height,
    990                                             int quality, int low_effort,
    991                                             int used_subtract_green,
    992                                             VP8LBitWriter* const bw) {
    993   const int pred_bits = enc->transform_bits_;
    994   const int transform_width = VP8LSubSampleSize(width, pred_bits);
    995   const int transform_height = VP8LSubSampleSize(height, pred_bits);
    996   // we disable near-lossless quantization if palette is used.
    997   const int near_lossless_strength = enc->use_palette_ ? 100
    998                                    : enc->config_->near_lossless;
    999 
   1000   VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
   1001                     enc->argb_scratch_, enc->transform_data_,
   1002                     near_lossless_strength, enc->config_->exact,
   1003                     used_subtract_green);
   1004   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
   1005   VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
   1006   assert(pred_bits >= 2);
   1007   VP8LPutBits(bw, pred_bits - 2, 3);
   1008   return EncodeImageNoHuffman(bw, enc->transform_data_,
   1009                               (VP8LHashChain*)&enc->hash_chain_,
   1010                               (VP8LBackwardRefs*)enc->refs_,  // cast const away
   1011                               transform_width, transform_height,
   1012                               quality, low_effort);
   1013 }
   1014 
   1015 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
   1016                                                int width, int height,
   1017                                                int quality, int low_effort,
   1018                                                VP8LBitWriter* const bw) {
   1019   const int ccolor_transform_bits = enc->transform_bits_;
   1020   const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
   1021   const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
   1022 
   1023   VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
   1024                           enc->argb_, enc->transform_data_);
   1025   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
   1026   VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
   1027   assert(ccolor_transform_bits >= 2);
   1028   VP8LPutBits(bw, ccolor_transform_bits - 2, 3);
   1029   return EncodeImageNoHuffman(bw, enc->transform_data_,
   1030                               (VP8LHashChain*)&enc->hash_chain_,
   1031                               (VP8LBackwardRefs*)enc->refs_,  // cast const away
   1032                               transform_width, transform_height,
   1033                               quality, low_effort);
   1034 }
   1035 
   1036 // -----------------------------------------------------------------------------
   1037 
   1038 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
   1039                                          size_t riff_size, size_t vp8l_size) {
   1040   uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
   1041     'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
   1042     'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
   1043   };
   1044   PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
   1045   PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
   1046   if (!pic->writer(riff, sizeof(riff), pic)) {
   1047     return VP8_ENC_ERROR_BAD_WRITE;
   1048   }
   1049   return VP8_ENC_OK;
   1050 }
   1051 
   1052 static int WriteImageSize(const WebPPicture* const pic,
   1053                           VP8LBitWriter* const bw) {
   1054   const int width = pic->width - 1;
   1055   const int height = pic->height - 1;
   1056   assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
   1057 
   1058   VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS);
   1059   VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS);
   1060   return !bw->error_;
   1061 }
   1062 
   1063 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
   1064   VP8LPutBits(bw, has_alpha, 1);
   1065   VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS);
   1066   return !bw->error_;
   1067 }
   1068 
   1069 static WebPEncodingError WriteImage(const WebPPicture* const pic,
   1070                                     VP8LBitWriter* const bw,
   1071                                     size_t* const coded_size) {
   1072   WebPEncodingError err = VP8_ENC_OK;
   1073   const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
   1074   const size_t webpll_size = VP8LBitWriterNumBytes(bw);
   1075   const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
   1076   const size_t pad = vp8l_size & 1;
   1077   const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
   1078 
   1079   err = WriteRiffHeader(pic, riff_size, vp8l_size);
   1080   if (err != VP8_ENC_OK) goto Error;
   1081 
   1082   if (!pic->writer(webpll_data, webpll_size, pic)) {
   1083     err = VP8_ENC_ERROR_BAD_WRITE;
   1084     goto Error;
   1085   }
   1086 
   1087   if (pad) {
   1088     const uint8_t pad_byte[1] = { 0 };
   1089     if (!pic->writer(pad_byte, 1, pic)) {
   1090       err = VP8_ENC_ERROR_BAD_WRITE;
   1091       goto Error;
   1092     }
   1093   }
   1094   *coded_size = CHUNK_HEADER_SIZE + riff_size;
   1095   return VP8_ENC_OK;
   1096 
   1097  Error:
   1098   return err;
   1099 }
   1100 
   1101 // -----------------------------------------------------------------------------
   1102 
   1103 static void ClearTransformBuffer(VP8LEncoder* const enc) {
   1104   WebPSafeFree(enc->transform_mem_);
   1105   enc->transform_mem_ = NULL;
   1106   enc->transform_mem_size_ = 0;
   1107 }
   1108 
   1109 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
   1110 // prediction and transform data.
   1111 // Flags influencing the memory allocated:
   1112 //  enc->transform_bits_
   1113 //  enc->use_predict_, enc->use_cross_color_
   1114 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
   1115                                                  int width, int height) {
   1116   WebPEncodingError err = VP8_ENC_OK;
   1117   const uint64_t image_size = width * height;
   1118   // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
   1119   // pixel in each, plus 2 regular scanlines of bytes.
   1120   // TODO(skal): Clean up by using arithmetic in bytes instead of words.
   1121   const uint64_t argb_scratch_size =
   1122       enc->use_predict_
   1123           ? (width + 1) * 2 +
   1124             (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t)
   1125           : 0;
   1126   const uint64_t transform_data_size =
   1127       (enc->use_predict_ || enc->use_cross_color_)
   1128           ? VP8LSubSampleSize(width, enc->transform_bits_) *
   1129                 VP8LSubSampleSize(height, enc->transform_bits_)
   1130           : 0;
   1131   const uint64_t max_alignment_in_words =
   1132       (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
   1133   const uint64_t mem_size =
   1134       image_size + max_alignment_in_words +
   1135       argb_scratch_size + max_alignment_in_words +
   1136       transform_data_size;
   1137   uint32_t* mem = enc->transform_mem_;
   1138   if (mem == NULL || mem_size > enc->transform_mem_size_) {
   1139     ClearTransformBuffer(enc);
   1140     mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
   1141     if (mem == NULL) {
   1142       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1143       goto Error;
   1144     }
   1145     enc->transform_mem_ = mem;
   1146     enc->transform_mem_size_ = (size_t)mem_size;
   1147   }
   1148   enc->argb_ = mem;
   1149   mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
   1150   enc->argb_scratch_ = mem;
   1151   mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
   1152   enc->transform_data_ = mem;
   1153 
   1154   enc->current_width_ = width;
   1155  Error:
   1156   return err;
   1157 }
   1158 
   1159 static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
   1160   WebPEncodingError err = VP8_ENC_OK;
   1161   const WebPPicture* const picture = enc->pic_;
   1162   const int width = picture->width;
   1163   const int height = picture->height;
   1164   int y;
   1165   err = AllocateTransformBuffer(enc, width, height);
   1166   if (err != VP8_ENC_OK) return err;
   1167   for (y = 0; y < height; ++y) {
   1168     memcpy(enc->argb_ + y * width,
   1169            picture->argb + y * picture->argb_stride,
   1170            width * sizeof(*enc->argb_));
   1171   }
   1172   assert(enc->current_width_ == width);
   1173   return VP8_ENC_OK;
   1174 }
   1175 
   1176 // -----------------------------------------------------------------------------
   1177 
   1178 static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
   1179                                         int hi) {
   1180   int low = 0;
   1181   if (sorted[low] == color) return low;  // loop invariant: sorted[low] != color
   1182   while (1) {
   1183     const int mid = (low + hi) >> 1;
   1184     if (sorted[mid] == color) {
   1185       return mid;
   1186     } else if (sorted[mid] < color) {
   1187       low = mid;
   1188     } else {
   1189       hi = mid;
   1190     }
   1191   }
   1192 }
   1193 
   1194 #define APPLY_PALETTE_GREEDY_MAX 4
   1195 
   1196 static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
   1197                                               int palette_size,
   1198                                               uint32_t color) {
   1199   (void)palette_size;
   1200   assert(palette_size < APPLY_PALETTE_GREEDY_MAX);
   1201   assert(3 == APPLY_PALETTE_GREEDY_MAX - 1);
   1202   if (color == palette[0]) return 0;
   1203   if (color == palette[1]) return 1;
   1204   if (color == palette[2]) return 2;
   1205   return 3;
   1206 }
   1207 
   1208 static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) {
   1209   // Focus on the green color.
   1210   return (color >> 8) & 0xff;
   1211 }
   1212 
   1213 #define PALETTE_INV_SIZE_BITS 11
   1214 #define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS)
   1215 
   1216 static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) {
   1217   // Forget about alpha.
   1218   return ((color & 0x00ffffffu) * 4222244071u) >> (32 - PALETTE_INV_SIZE_BITS);
   1219 }
   1220 
   1221 static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
   1222   // Forget about alpha.
   1223   return (color & 0x00ffffffu) * ((1u << 31) - 1) >>
   1224          (32 - PALETTE_INV_SIZE_BITS);
   1225 }
   1226 
   1227 // Sort palette in increasing order and prepare an inverse mapping array.
   1228 static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
   1229                                 uint32_t sorted[], uint32_t idx_map[]) {
   1230   int i;
   1231   memcpy(sorted, palette, num_colors * sizeof(*sorted));
   1232   qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
   1233   for (i = 0; i < num_colors; ++i) {
   1234     idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
   1235   }
   1236 }
   1237 
   1238 // Use 1 pixel cache for ARGB pixels.
   1239 #define APPLY_PALETTE_FOR(COLOR_INDEX) do {         \
   1240   uint32_t prev_pix = palette[0];                   \
   1241   uint32_t prev_idx = 0;                            \
   1242   for (y = 0; y < height; ++y) {                    \
   1243     for (x = 0; x < width; ++x) {                   \
   1244       const uint32_t pix = src[x];                  \
   1245       if (pix != prev_pix) {                        \
   1246         prev_idx = COLOR_INDEX;                     \
   1247         prev_pix = pix;                             \
   1248       }                                             \
   1249       tmp_row[x] = prev_idx;                        \
   1250     }                                               \
   1251     VP8LBundleColorMap(tmp_row, width, xbits, dst); \
   1252     src += src_stride;                              \
   1253     dst += dst_stride;                              \
   1254   }                                                 \
   1255 } while (0)
   1256 
   1257 // Remap argb values in src[] to packed palettes entries in dst[]
   1258 // using 'row' as a temporary buffer of size 'width'.
   1259 // We assume that all src[] values have a corresponding entry in the palette.
   1260 // Note: src[] can be the same as dst[]
   1261 static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
   1262                                       uint32_t* dst, uint32_t dst_stride,
   1263                                       const uint32_t* palette, int palette_size,
   1264                                       int width, int height, int xbits) {
   1265   // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
   1266   // made to work in-place.
   1267   uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
   1268   int x, y;
   1269 
   1270   if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
   1271 
   1272   if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
   1273     APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix));
   1274   } else {
   1275     int i, j;
   1276     uint16_t buffer[PALETTE_INV_SIZE];
   1277     uint32_t (*const hash_functions[])(uint32_t) = {
   1278         ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2
   1279     };
   1280 
   1281     // Try to find a perfect hash function able to go from a color to an index
   1282     // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go
   1283     // from color to index in palette.
   1284     for (i = 0; i < 3; ++i) {
   1285       int use_LUT = 1;
   1286       // Set each element in buffer to max uint16_t.
   1287       memset(buffer, 0xff, sizeof(buffer));
   1288       for (j = 0; j < palette_size; ++j) {
   1289         const uint32_t ind = hash_functions[i](palette[j]);
   1290         if (buffer[ind] != 0xffffu) {
   1291           use_LUT = 0;
   1292           break;
   1293         } else {
   1294           buffer[ind] = j;
   1295         }
   1296       }
   1297       if (use_LUT) break;
   1298     }
   1299 
   1300     if (i == 0) {
   1301       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]);
   1302     } else if (i == 1) {
   1303       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]);
   1304     } else if (i == 2) {
   1305       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]);
   1306     } else {
   1307       uint32_t idx_map[MAX_PALETTE_SIZE];
   1308       uint32_t palette_sorted[MAX_PALETTE_SIZE];
   1309       PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map);
   1310       APPLY_PALETTE_FOR(
   1311           idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]);
   1312     }
   1313   }
   1314   WebPSafeFree(tmp_row);
   1315   return VP8_ENC_OK;
   1316 }
   1317 #undef APPLY_PALETTE_FOR
   1318 #undef PALETTE_INV_SIZE_BITS
   1319 #undef PALETTE_INV_SIZE
   1320 #undef APPLY_PALETTE_GREEDY_MAX
   1321 
   1322 // Note: Expects "enc->palette_" to be set properly.
   1323 static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
   1324                                              int in_place) {
   1325   WebPEncodingError err = VP8_ENC_OK;
   1326   const WebPPicture* const pic = enc->pic_;
   1327   const int width = pic->width;
   1328   const int height = pic->height;
   1329   const uint32_t* const palette = enc->palette_;
   1330   const uint32_t* src = in_place ? enc->argb_ : pic->argb;
   1331   const int src_stride = in_place ? enc->current_width_ : pic->argb_stride;
   1332   const int palette_size = enc->palette_size_;
   1333   int xbits;
   1334 
   1335   // Replace each input pixel by corresponding palette index.
   1336   // This is done line by line.
   1337   if (palette_size <= 4) {
   1338     xbits = (palette_size <= 2) ? 3 : 2;
   1339   } else {
   1340     xbits = (palette_size <= 16) ? 1 : 0;
   1341   }
   1342 
   1343   err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
   1344   if (err != VP8_ENC_OK) return err;
   1345 
   1346   err = ApplyPalette(src, src_stride,
   1347                      enc->argb_, enc->current_width_,
   1348                      palette, palette_size, width, height, xbits);
   1349   return err;
   1350 }
   1351 
   1352 // Save palette_[] to bitstream.
   1353 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
   1354                                        VP8LEncoder* const enc) {
   1355   int i;
   1356   uint32_t tmp_palette[MAX_PALETTE_SIZE];
   1357   const int palette_size = enc->palette_size_;
   1358   const uint32_t* const palette = enc->palette_;
   1359   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
   1360   VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2);
   1361   assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE);
   1362   VP8LPutBits(bw, palette_size - 1, 8);
   1363   for (i = palette_size - 1; i >= 1; --i) {
   1364     tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
   1365   }
   1366   tmp_palette[0] = palette[0];
   1367   return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_,
   1368                               palette_size, 1, 20 /* quality */, low_effort);
   1369 }
   1370 
   1371 #ifdef WEBP_EXPERIMENTAL_FEATURES
   1372 
   1373 static WebPEncodingError EncodeDeltaPalettePredictorImage(
   1374     VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality,
   1375     int low_effort) {
   1376   const WebPPicture* const pic = enc->pic_;
   1377   const int width = pic->width;
   1378   const int height = pic->height;
   1379 
   1380   const int pred_bits = 5;
   1381   const int transform_width = VP8LSubSampleSize(width, pred_bits);
   1382   const int transform_height = VP8LSubSampleSize(height, pred_bits);
   1383   const int pred = 7;   // default is Predictor7 (Top/Left Average)
   1384   const int tiles_per_row = VP8LSubSampleSize(width, pred_bits);
   1385   const int tiles_per_col = VP8LSubSampleSize(height, pred_bits);
   1386   uint32_t* predictors;
   1387   int tile_x, tile_y;
   1388   WebPEncodingError err = VP8_ENC_OK;
   1389 
   1390   predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row,
   1391                                          sizeof(*predictors));
   1392   if (predictors == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
   1393 
   1394   for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
   1395     for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
   1396       predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
   1397     }
   1398   }
   1399 
   1400   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
   1401   VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
   1402   VP8LPutBits(bw, pred_bits - 2, 3);
   1403   err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_,
   1404                              (VP8LBackwardRefs*)enc->refs_,  // cast const away
   1405                              transform_width, transform_height,
   1406                              quality, low_effort);
   1407   WebPSafeFree(predictors);
   1408   return err;
   1409 }
   1410 
   1411 #endif // WEBP_EXPERIMENTAL_FEATURES
   1412 
   1413 // -----------------------------------------------------------------------------
   1414 // VP8LEncoder
   1415 
   1416 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
   1417                                    const WebPPicture* const picture) {
   1418   VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
   1419   if (enc == NULL) {
   1420     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
   1421     return NULL;
   1422   }
   1423   enc->config_ = config;
   1424   enc->pic_ = picture;
   1425 
   1426   VP8LEncDspInit();
   1427 
   1428   return enc;
   1429 }
   1430 
   1431 static void VP8LEncoderDelete(VP8LEncoder* enc) {
   1432   if (enc != NULL) {
   1433     VP8LHashChainClear(&enc->hash_chain_);
   1434     VP8LBackwardRefsClear(&enc->refs_[0]);
   1435     VP8LBackwardRefsClear(&enc->refs_[1]);
   1436     ClearTransformBuffer(enc);
   1437     WebPSafeFree(enc);
   1438   }
   1439 }
   1440 
   1441 // -----------------------------------------------------------------------------
   1442 // Main call
   1443 
   1444 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
   1445                                    const WebPPicture* const picture,
   1446                                    VP8LBitWriter* const bw, int use_cache) {
   1447   WebPEncodingError err = VP8_ENC_OK;
   1448   const int quality = (int)config->quality;
   1449   const int low_effort = (config->method == 0);
   1450   const int width = picture->width;
   1451   const int height = picture->height;
   1452   VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
   1453   const size_t byte_position = VP8LBitWriterNumBytes(bw);
   1454   int use_near_lossless = 0;
   1455   int hdr_size = 0;
   1456   int data_size = 0;
   1457   int use_delta_palette = 0;
   1458 
   1459   if (enc == NULL) {
   1460     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1461     goto Error;
   1462   }
   1463 
   1464   // ---------------------------------------------------------------------------
   1465   // Analyze image (entropy, num_palettes etc)
   1466 
   1467   if (!AnalyzeAndInit(enc)) {
   1468     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1469     goto Error;
   1470   }
   1471 
   1472   // Apply near-lossless preprocessing.
   1473   use_near_lossless =
   1474       (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_;
   1475   if (use_near_lossless) {
   1476     if (!VP8ApplyNearLossless(width, height, picture->argb,
   1477                               config->near_lossless)) {
   1478       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1479       goto Error;
   1480     }
   1481   }
   1482 
   1483 #ifdef WEBP_EXPERIMENTAL_FEATURES
   1484   if (config->use_delta_palette) {
   1485     enc->use_predict_ = 1;
   1486     enc->use_cross_color_ = 0;
   1487     enc->use_subtract_green_ = 0;
   1488     enc->use_palette_ = 1;
   1489     err = MakeInputImageCopy(enc);
   1490     if (err != VP8_ENC_OK) goto Error;
   1491     err = WebPSearchOptimalDeltaPalette(enc);
   1492     if (err != VP8_ENC_OK) goto Error;
   1493     if (enc->use_palette_) {
   1494       err = AllocateTransformBuffer(enc, width, height);
   1495       if (err != VP8_ENC_OK) goto Error;
   1496       err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort);
   1497       if (err != VP8_ENC_OK) goto Error;
   1498       use_delta_palette = 1;
   1499     }
   1500   }
   1501 #endif  // WEBP_EXPERIMENTAL_FEATURES
   1502 
   1503   // Encode palette
   1504   if (enc->use_palette_) {
   1505     err = EncodePalette(bw, low_effort, enc);
   1506     if (err != VP8_ENC_OK) goto Error;
   1507     err = MapImageFromPalette(enc, use_delta_palette);
   1508     if (err != VP8_ENC_OK) goto Error;
   1509     // If using a color cache, do not have it bigger than the number of colors.
   1510     if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
   1511       enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
   1512     }
   1513   }
   1514   if (!use_delta_palette) {
   1515     // In case image is not packed.
   1516     if (enc->argb_ == NULL) {
   1517       err = MakeInputImageCopy(enc);
   1518       if (err != VP8_ENC_OK) goto Error;
   1519     }
   1520 
   1521     // -------------------------------------------------------------------------
   1522     // Apply transforms and write transform data.
   1523 
   1524     if (enc->use_subtract_green_) {
   1525       ApplySubtractGreen(enc, enc->current_width_, height, bw);
   1526     }
   1527 
   1528     if (enc->use_predict_) {
   1529       err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
   1530                                low_effort, enc->use_subtract_green_, bw);
   1531       if (err != VP8_ENC_OK) goto Error;
   1532     }
   1533 
   1534     if (enc->use_cross_color_) {
   1535       err = ApplyCrossColorFilter(enc, enc->current_width_,
   1536                                   height, quality, low_effort, bw);
   1537       if (err != VP8_ENC_OK) goto Error;
   1538     }
   1539   }
   1540 
   1541   VP8LPutBits(bw, !TRANSFORM_PRESENT, 1);  // No more transforms.
   1542 
   1543   // ---------------------------------------------------------------------------
   1544   // Encode and write the transformed image.
   1545   err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
   1546                             enc->current_width_, height, quality, low_effort,
   1547                             use_cache, &enc->cache_bits_, enc->histo_bits_,
   1548                             byte_position, &hdr_size, &data_size);
   1549   if (err != VP8_ENC_OK) goto Error;
   1550 
   1551   if (picture->stats != NULL) {
   1552     WebPAuxStats* const stats = picture->stats;
   1553     stats->lossless_features = 0;
   1554     if (enc->use_predict_) stats->lossless_features |= 1;
   1555     if (enc->use_cross_color_) stats->lossless_features |= 2;
   1556     if (enc->use_subtract_green_) stats->lossless_features |= 4;
   1557     if (enc->use_palette_) stats->lossless_features |= 8;
   1558     stats->histogram_bits = enc->histo_bits_;
   1559     stats->transform_bits = enc->transform_bits_;
   1560     stats->cache_bits = enc->cache_bits_;
   1561     stats->palette_size = enc->palette_size_;
   1562     stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
   1563     stats->lossless_hdr_size = hdr_size;
   1564     stats->lossless_data_size = data_size;
   1565   }
   1566 
   1567  Error:
   1568   VP8LEncoderDelete(enc);
   1569   return err;
   1570 }
   1571 
   1572 int VP8LEncodeImage(const WebPConfig* const config,
   1573                     const WebPPicture* const picture) {
   1574   int width, height;
   1575   int has_alpha;
   1576   size_t coded_size;
   1577   int percent = 0;
   1578   int initial_size;
   1579   WebPEncodingError err = VP8_ENC_OK;
   1580   VP8LBitWriter bw;
   1581 
   1582   if (picture == NULL) return 0;
   1583 
   1584   if (config == NULL || picture->argb == NULL) {
   1585     err = VP8_ENC_ERROR_NULL_PARAMETER;
   1586     WebPEncodingSetError(picture, err);
   1587     return 0;
   1588   }
   1589 
   1590   width = picture->width;
   1591   height = picture->height;
   1592   // Initialize BitWriter with size corresponding to 16 bpp to photo images and
   1593   // 8 bpp for graphical images.
   1594   initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
   1595       width * height : width * height * 2;
   1596   if (!VP8LBitWriterInit(&bw, initial_size)) {
   1597     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1598     goto Error;
   1599   }
   1600 
   1601   if (!WebPReportProgress(picture, 1, &percent)) {
   1602  UserAbort:
   1603     err = VP8_ENC_ERROR_USER_ABORT;
   1604     goto Error;
   1605   }
   1606   // Reset stats (for pure lossless coding)
   1607   if (picture->stats != NULL) {
   1608     WebPAuxStats* const stats = picture->stats;
   1609     memset(stats, 0, sizeof(*stats));
   1610     stats->PSNR[0] = 99.f;
   1611     stats->PSNR[1] = 99.f;
   1612     stats->PSNR[2] = 99.f;
   1613     stats->PSNR[3] = 99.f;
   1614     stats->PSNR[4] = 99.f;
   1615   }
   1616 
   1617   // Write image size.
   1618   if (!WriteImageSize(picture, &bw)) {
   1619     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1620     goto Error;
   1621   }
   1622 
   1623   has_alpha = WebPPictureHasTransparency(picture);
   1624   // Write the non-trivial Alpha flag and lossless version.
   1625   if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
   1626     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1627     goto Error;
   1628   }
   1629 
   1630   if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
   1631 
   1632   // Encode main image stream.
   1633   err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/);
   1634   if (err != VP8_ENC_OK) goto Error;
   1635 
   1636   // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
   1637   if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
   1638 
   1639   // Finish the RIFF chunk.
   1640   err = WriteImage(picture, &bw, &coded_size);
   1641   if (err != VP8_ENC_OK) goto Error;
   1642 
   1643   if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
   1644 
   1645   // Save size.
   1646   if (picture->stats != NULL) {
   1647     picture->stats->coded_size += (int)coded_size;
   1648     picture->stats->lossless_size = (int)coded_size;
   1649   }
   1650 
   1651   if (picture->extra_info != NULL) {
   1652     const int mb_w = (width + 15) >> 4;
   1653     const int mb_h = (height + 15) >> 4;
   1654     memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
   1655   }
   1656 
   1657  Error:
   1658   if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
   1659   VP8LBitWriterWipeOut(&bw);
   1660   if (err != VP8_ENC_OK) {
   1661     WebPEncodingSetError(picture, err);
   1662     return 0;
   1663   }
   1664   return 1;
   1665 }
   1666 
   1667 //------------------------------------------------------------------------------
   1668