//------------------------------------------------------------------------------ // RGBA rescaling // import new contributions until one row is ready to be output, or all input // is consumed. static int Import(byte* src, int src_stride, int new_lines, WebPRescaler* wrk) { int num_lines_in = 0; while (num_lines_in < new_lines && wrk.y_accum > 0) { ImportRow(src, wrk); src += src_stride; ++num_lines_in; wrk.y_accum -= wrk.y_sub; } return num_lines_in; }
//------------------------------------------------------------------------------ // YUV rescaling (no final RGB conversion needed) static int Rescale(byte* src, int src_stride, int new_lines, WebPRescaler* wrk) { int num_lines_out = 0; while (new_lines-- > 0) { // import new contribution of one source row. ImportRow(src, wrk); src += src_stride; wrk.y_accum -= wrk.y_sub; while (wrk.y_accum <= 0) { // emit output row(s) ExportRow(wrk); ++num_lines_out; } } return num_lines_out; }
static void ImportRow(byte* src, WebPRescaler* wrk) { int x_in = 0; int x_out; int accum = 0; if (!wrk.x_expand) { int sum = 0; for (x_out = 0; x_out < wrk.dst_width; ++x_out) { accum += wrk.x_add; for (; accum > 0; accum -= wrk.x_sub) { sum += src[x_in++]; } { // Emit next horizontal pixel. int base = src[x_in++]; int frac = base * (-accum); wrk.frow[x_out] = (sum + base) * wrk.x_sub - frac; // fresh fractional start for next pixel sum = MULT(frac, wrk.fx_scale); } } } else { // simple bilinear interpolation int left = src[0], right = src[0]; for (x_out = 0; x_out < wrk.dst_width; ++x_out) { if (accum < 0) { left = right; right = src[++x_in]; accum += wrk.x_add; } wrk.frow[x_out] = right * wrk.x_add + (left - right) * accum; accum -= wrk.x_sub; } } // Accumulate the new row's contribution for (x_out = 0; x_out < wrk.dst_width; ++x_out) { wrk.irow[x_out] += wrk.frow[x_out]; } }
static void ExportRow(WebPRescaler* wrk) { int x_out; int yscale = wrk.fy_scale * (-wrk.y_accum); assert(wrk.y_accum <= 0); for (x_out = 0; x_out < wrk.dst_width; ++x_out) { int frac = MULT(wrk.frow[x_out], yscale); int v = (int)MULT(wrk.irow[x_out] - frac, wrk.fxy_scale); wrk.dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; wrk.irow[x_out] = frac; // new fractional start } wrk.y_accum += wrk.y_add; wrk.dst += wrk.dst_stride; }
static void InitRescaler(WebPRescaler* wrk, int src_width, int src_height, byte* dst, int dst_width, int dst_height, int dst_stride, int x_add, int x_sub, int y_add, int y_sub, int* work) { wrk.x_expand = (src_width < dst_width); wrk.src_width = src_width; wrk.src_height = src_height; wrk.dst_width = dst_width; wrk.dst_height = dst_height; wrk.dst = dst; wrk.dst_stride = dst_stride; // for 'x_expand', we use bilinear interpolation wrk.x_add = wrk.x_expand ? (x_sub - 1) : x_add - x_sub; wrk.x_sub = wrk.x_expand ? (x_add - 1) : x_sub; wrk.y_accum = y_add; wrk.y_add = y_add; wrk.y_sub = y_sub; wrk.fx_scale = (1 << RFIX) / x_sub; wrk.fy_scale = (1 << RFIX) / y_sub; wrk.fxy_scale = wrk.x_expand ? ((long)dst_height << RFIX) / (x_sub * src_height) : ((long)dst_height << RFIX) / (x_add * src_height); wrk.irow = work; wrk.frow = work + dst_width; }