OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 // |
| 3 // This code is licensed under the same terms as WebM: |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
| 6 // ----------------------------------------------------------------------------- |
| 7 // |
| 8 // Rescaling functions |
| 9 // |
| 10 // Author: Skal (pascal.massimino@gmail.com) |
| 11 |
| 12 #include <assert.h> |
| 13 #include <stdlib.h> |
| 14 #include "./rescaler.h" |
| 15 |
| 16 //------------------------------------------------------------------------------ |
| 17 |
| 18 #if defined(__cplusplus) || defined(c_plusplus) |
| 19 extern "C" { |
| 20 #endif |
| 21 |
| 22 #define RFIX 30 |
| 23 #define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) |
| 24 |
| 25 void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, |
| 26 uint8_t* const dst, int dst_width, int dst_height, |
| 27 int dst_stride, int num_channels, int x_add, int x_sub, |
| 28 int y_add, int y_sub, int32_t* const work) { |
| 29 wrk->x_expand = (src_width < dst_width); |
| 30 wrk->src_width = src_width; |
| 31 wrk->src_height = src_height; |
| 32 wrk->dst_width = dst_width; |
| 33 wrk->dst_height = dst_height; |
| 34 wrk->dst = dst; |
| 35 wrk->dst_stride = dst_stride; |
| 36 wrk->num_channels = num_channels; |
| 37 // for 'x_expand', we use bilinear interpolation |
| 38 wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; |
| 39 wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; |
| 40 wrk->y_accum = y_add; |
| 41 wrk->y_add = y_add; |
| 42 wrk->y_sub = y_sub; |
| 43 wrk->fx_scale = (1 << RFIX) / x_sub; |
| 44 wrk->fy_scale = (1 << RFIX) / y_sub; |
| 45 wrk->fxy_scale = wrk->x_expand ? |
| 46 ((int64_t)dst_height << RFIX) / (x_sub * src_height) : |
| 47 ((int64_t)dst_height << RFIX) / (x_add * src_height); |
| 48 wrk->irow = work; |
| 49 wrk->frow = work + num_channels * dst_width; |
| 50 } |
| 51 |
| 52 void WebPRescalerImportRow(WebPRescaler* const wrk, |
| 53 const uint8_t* const src, int channel) { |
| 54 const int x_stride = wrk->num_channels; |
| 55 const int x_out_max = wrk->dst_width * wrk->num_channels; |
| 56 int x_in = channel; |
| 57 int x_out; |
| 58 int accum = 0; |
| 59 if (!wrk->x_expand) { |
| 60 int sum = 0; |
| 61 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
| 62 accum += wrk->x_add; |
| 63 for (; accum > 0; accum -= wrk->x_sub) { |
| 64 sum += src[x_in]; |
| 65 x_in += x_stride; |
| 66 } |
| 67 { // Emit next horizontal pixel. |
| 68 const int32_t base = src[x_in]; |
| 69 const int32_t frac = base * (-accum); |
| 70 x_in += x_stride; |
| 71 wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; |
| 72 // fresh fractional start for next pixel |
| 73 sum = (int)MULT_FIX(frac, wrk->fx_scale); |
| 74 } |
| 75 } |
| 76 } else { // simple bilinear interpolation |
| 77 int left = src[channel], right = src[channel]; |
| 78 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
| 79 if (accum < 0) { |
| 80 left = right; |
| 81 x_in += x_stride; |
| 82 right = src[x_in]; |
| 83 accum += wrk->x_add; |
| 84 } |
| 85 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; |
| 86 accum -= wrk->x_sub; |
| 87 } |
| 88 } |
| 89 // Accumulate the new row's contribution |
| 90 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
| 91 wrk->irow[x_out] += wrk->frow[x_out]; |
| 92 } |
| 93 } |
| 94 |
| 95 uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) { |
| 96 if (wrk->y_accum <= 0) { |
| 97 int x_out; |
| 98 uint8_t* const dst = wrk->dst; |
| 99 int32_t* const irow = wrk->irow; |
| 100 const int32_t* const frow = wrk->frow; |
| 101 const int yscale = wrk->fy_scale * (-wrk->y_accum); |
| 102 const int x_out_max = wrk->dst_width * wrk->num_channels; |
| 103 |
| 104 for (x_out = 0; x_out < x_out_max; ++x_out) { |
| 105 const int frac = (int)MULT_FIX(frow[x_out], yscale); |
| 106 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); |
| 107 dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; |
| 108 irow[x_out] = frac; // new fractional start |
| 109 } |
| 110 wrk->y_accum += wrk->y_add; |
| 111 wrk->dst += wrk->dst_stride; |
| 112 return dst; |
| 113 } else { |
| 114 return NULL; |
| 115 } |
| 116 } |
| 117 |
| 118 #undef MULT_FIX |
| 119 #undef RFIX |
| 120 |
| 121 //------------------------------------------------------------------------------ |
| 122 // all-in-one calls |
| 123 |
| 124 int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, |
| 125 const uint8_t* src, int src_stride) { |
| 126 int total_imported = 0; |
| 127 while (total_imported < num_lines && wrk->y_accum > 0) { |
| 128 int channel; |
| 129 for (channel = 0; channel < wrk->num_channels; ++channel) { |
| 130 WebPRescalerImportRow(wrk, src, channel); |
| 131 } |
| 132 src += src_stride; |
| 133 ++total_imported; |
| 134 wrk->y_accum -= wrk->y_sub; |
| 135 } |
| 136 return total_imported; |
| 137 } |
| 138 |
| 139 int WebPRescalerExport(WebPRescaler* const rescaler) { |
| 140 int total_exported = 0; |
| 141 while (WebPRescalerHasPendingOutput(rescaler)) { |
| 142 WebPRescalerExportRow(rescaler); |
| 143 ++total_exported; |
| 144 } |
| 145 return total_exported; |
| 146 } |
| 147 |
| 148 //------------------------------------------------------------------------------ |
| 149 |
| 150 #if defined(__cplusplus) || defined(c_plusplus) |
| 151 } // extern "C" |
| 152 #endif |
OLD | NEW |