Home | History | Annotate | Download | only in utils
      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 (at) 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
    153