11e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Copyright 2013 Google Inc. All Rights Reserved. 21e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// 30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license 40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source 50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found 60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may 70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree. 81e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// ----------------------------------------------------------------------------- 91e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// 10af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Implement gradient smoothing: we replace a current alpha value by its 11af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// surrounding average if it's close enough (that is: the change will be less 12af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// than the minimum distance between two quantized level). 13af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// We use sliding window for computing the 2d moving average. 141e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// 151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Author: Skal (pascal.massimino@gmail.com) 161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora 171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#include "./quant_levels_dec.h" 181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora 19af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include <string.h> // for memset 20af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 21af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include "./utils.h" 22af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 23af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// #define USE_DITHERING // uncomment to enable ordered dithering (not vital) 24af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 25af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define FIX 16 // fix-point precision for averaging 26af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define LFIX 2 // extra precision for look-up table 27af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define LUT_SIZE ((1 << (8 + LFIX)) - 1) // look-up table size 28af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 29af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(USE_DITHERING) 30af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 31af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define DFIX 4 // extra precision for ordered dithering 32af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define DSIZE 4 // dithering size (must be a power of two) 33af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// cf. http://en.wikipedia.org/wiki/Ordered_dithering 34af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic const uint8_t kOrderedDither[DSIZE][DSIZE] = { 35af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 0, 8, 2, 10 }, // coefficients are in DFIX fixed-point precision 36af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 12, 4, 14, 6 }, 37af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 3, 11, 1, 9 }, 38af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 15, 7, 13, 5 } 39af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}; 40af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 41af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#else 42af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define DFIX 0 43af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 44af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 45af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroratypedef struct { 46af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int width_, height_; // dimension 47af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int row_; // current input row being processed 48af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint8_t* src_; // input pointer 49af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint8_t* dst_; // output pointer 50af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 51af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int radius_; // filter radius (=delay) 52af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int scale_; // normalization factor, in FIX bits precision 53af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 54af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora void* mem_; // all memory 55af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 56af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // various scratch buffers 57af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* start_; 58af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* cur_; 59af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* end_; 60af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* top_; 61af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* average_; 62af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 63af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // input levels distribution 64af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int num_levels_; // number of quantized levels 65af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int min_, max_; // min and max level values 66af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int min_level_dist_; // smallest distance between two consecutive levels 67af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 68af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int16_t* correction_; // size = 1 + 2*LUT_SIZE -> ~4k memory 69af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} SmoothParams; 70af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 71af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------ 72af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 73af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define CLIP_MASK (int)(~0U << (8 + DFIX)) 74af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic WEBP_INLINE uint8_t clip_8b(int v) { 75af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return (!(v & CLIP_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u; 76af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 77af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 78af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// vertical accumulation 79af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void VFilter(SmoothParams* const p) { 80af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint8_t* src = p->src_; 81af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int w = p->width_; 82af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* const cur = p->cur_; 83af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t* const top = p->top_; 84af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* const out = p->end_; 85af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t sum = 0; // all arithmetic is modulo 16bit 86af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int x; 87af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 88af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (x = 0; x < w; ++x) { 89af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t new_value; 90af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora sum += src[x]; 91af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora new_value = top[x] + sum; 92af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora out[x] = new_value - cur[x]; // vertical sum of 'r' pixels. 93af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora cur[x] = new_value; 94af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 95af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // move input pointers one row down 96af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->top_ = p->cur_; 97af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->cur_ += w; 98af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (p->cur_ == p->end_) p->cur_ = p->start_; // roll-over 99af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // We replicate edges, as it's somewhat easier as a boundary condition. 100af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // That's why we don't update the 'src' pointer on top/bottom area: 101af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (p->row_ >= 0 && p->row_ < p->height_ - 1) { 102af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->src_ += p->width_; 103af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 104af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 105af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 106af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// horizontal accumulation. We use mirror replication of missing pixels, as it's 107af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// a little easier to implement (surprisingly). 108af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void HFilter(SmoothParams* const p) { 109af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t* const in = p->end_; 110af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint16_t* const out = p->average_; 111af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint32_t scale = p->scale_; 112af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int w = p->width_; 113af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int r = p->radius_; 114af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 115af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int x; 116af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (x = 0; x <= r; ++x) { // left mirroring 117af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t delta = in[x + r - 1] + in[r - x]; 118af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora out[x] = (delta * scale) >> FIX; 119af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 120af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (; x < w - r; ++x) { // bulk middle run 121af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t delta = in[x + r] - in[x - r - 1]; 122af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora out[x] = (delta * scale) >> FIX; 123af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 124af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (; x < w; ++x) { // right mirroring 125af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t delta = 126af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 2 * in[w - 1] - in[2 * w - 2 - r - x] - in[x - r - 1]; 127af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora out[x] = (delta * scale) >> FIX; 128af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 129af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 130af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 131af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// emit one filtered output row 132af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void ApplyFilter(SmoothParams* const p) { 133af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint16_t* const average = p->average_; 134af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int w = p->width_; 135af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int16_t* const correction = p->correction_; 136af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(USE_DITHERING) 137af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const uint8_t* const dither = kOrderedDither[p->row_ % DSIZE]; 138af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 139af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint8_t* const dst = p->dst_; 140af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int x; 141af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (x = 0; x < w; ++x) { 142af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int v = dst[x]; 143af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (v < p->max_ && v > p->min_) { 144af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int c = (v << DFIX) + correction[average[x] - (v << LFIX)]; 145af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(USE_DITHERING) 146af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora dst[x] = clip_8b(c + dither[x % DSIZE]); 147af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#else 148af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora dst[x] = clip_8b(c); 149af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 150af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 1518b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora } 152af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->dst_ += w; // advance output pointer 153af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 154af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 155af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------ 156af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Initialize correction table 157af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 158af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void InitCorrectionLUT(int16_t* const lut, int min_dist) { 159af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // The correction curve is: 160af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // f(x) = x for x <= threshold2 161af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // f(x) = 0 for x >= threshold1 162af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // and a linear interpolation for range x=[threshold2, threshold1] 163af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // (along with f(-x) = -f(x) symmetry). 164af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // Note that: threshold2 = 3/4 * threshold1 165af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int threshold1 = min_dist << LFIX; 166af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int threshold2 = (3 * threshold1) >> 2; 167af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int max_threshold = threshold2 << DFIX; 168af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int delta = threshold1 - threshold2; 169af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int i; 170af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (i = 1; i <= LUT_SIZE; ++i) { 171af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int c = (i <= threshold2) ? (i << DFIX) 172af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora : (i < threshold1) ? max_threshold * (threshold1 - i) / delta 173af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora : 0; 174af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora c >>= LFIX; 175af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora lut[+i] = +c; 176af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora lut[-i] = -c; 177af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 178af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora lut[0] = 0; 179af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 180af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 181af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void CountLevels(const uint8_t* const data, int size, 182af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora SmoothParams* const p) { 183af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int i, last_level; 184af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint8_t used_levels[256] = { 0 }; 185af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->min_ = 255; 186af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->max_ = 0; 187af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (i = 0; i < size; ++i) { 188af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int v = data[i]; 189af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (v < p->min_) p->min_ = v; 190af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (v > p->max_) p->max_ = v; 191af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora used_levels[v] = 1; 192af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 193af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // Compute the mininum distance between two non-zero levels. 194af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->min_level_dist_ = p->max_ - p->min_; 195af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora last_level = -1; 196af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (i = 0; i < 256; ++i) { 197af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (used_levels[i]) { 198af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ++p->num_levels_; 199af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (last_level >= 0) { 200af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int level_dist = i - last_level; 201af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (level_dist < p->min_level_dist_) { 202af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->min_level_dist_ = level_dist; 203af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 204af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 205af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora last_level = i; 206af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 207af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 208af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 209af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 210af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Initialize all params. 211af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int InitParams(uint8_t* const data, int width, int height, 212af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int radius, SmoothParams* const p) { 213af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int R = 2 * radius + 1; // total size of the kernel 214af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 215af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start_); 216af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const size_t size_m = width * sizeof(*p->average_); 217af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction_); 218af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const size_t total_size = size_scratch_m + size_m + size_lut; 219af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size); 220af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 221af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (mem == NULL) return 0; 222af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->mem_ = (void*)mem; 223af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 224af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->start_ = (uint16_t*)mem; 225af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->cur_ = p->start_; 226af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->end_ = p->start_ + R * width; 227af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->top_ = p->end_ - width; 228af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora memset(p->top_, 0, width * sizeof(*p->top_)); 229af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora mem += size_scratch_m; 230af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 231af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->average_ = (uint16_t*)mem; 232af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora mem += size_m; 233af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 234af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->width_ = width; 235af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->height_ = height; 236af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->src_ = data; 237af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->dst_ = data; 238af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->radius_ = radius; 239af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->scale_ = (1 << (FIX + LFIX)) / (R * R); // normalization constant 240af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->row_ = -radius; 241af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 242af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // analyze the input distribution so we can best-fit the threshold 243af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora CountLevels(data, width * height, p); 244af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 245af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // correction table 246af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora p->correction_ = ((int16_t*)mem) + LUT_SIZE; 247af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora InitCorrectionLUT(p->correction_, p->min_level_dist_); 248af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 2491e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora return 1; 2501e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora} 2511e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora 252af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void CleanupParams(SmoothParams* const p) { 253af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora WebPSafeFree(p->mem_); 254af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 255af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 256af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPDequantizeLevels(uint8_t* const data, int width, int height, 257af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora int strength) { 258af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const int radius = 4 * strength / 100; 259af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (strength < 0 || strength > 100) return 0; 260af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (data == NULL || width <= 0 || height <= 0) return 0; // bad params 261af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (radius > 0) { 262af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora SmoothParams p; 263af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora memset(&p, 0, sizeof(p)); 264af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (!InitParams(data, width, height, radius, &p)) return 0; 265af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (p.num_levels_ > 2) { 266af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora for (; p.row_ < p.height_; ++p.row_) { 267af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora VFilter(&p); // accumulate average of input 268af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // Need to wait few rows in order to prime the filter, 269af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // before emitting some output. 270af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (p.row_ >= p.radius_) { 271af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora HFilter(&p); 272af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ApplyFilter(&p); 273af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 274af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 275af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 276af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora CleanupParams(&p); 277af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 278af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return 1; 279af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 280