mirror of
https://github.com/webmproject/libwebp.git
synced 2025-02-13 15:32:53 +01:00
Move rescaler methods out of io.c.
(cherry picked from commit b5e9db1824f6efbe0bfb87e94b8d6e88a7973ef7)
This commit is contained in:
parent
6f7bf645b4
commit
3eacee8158
179
src/dec/io.c
179
src/dec/io.c
@ -228,98 +228,6 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Simple picture rescaler
|
|
||||||
|
|
||||||
// TODO(skal): start a common library for encoder and decoder, and factorize
|
|
||||||
// this code in.
|
|
||||||
|
|
||||||
#define RFIX 30
|
|
||||||
#define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
|
|
||||||
|
|
||||||
static void InitRescaler(WebPRescaler* const wrk,
|
|
||||||
int src_width, int src_height,
|
|
||||||
uint8_t* dst,
|
|
||||||
int dst_width, int dst_height, int dst_stride,
|
|
||||||
int x_add, int x_sub, int y_add, int y_sub,
|
|
||||||
int32_t* 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 ?
|
|
||||||
((int64_t)dst_height << RFIX) / (x_sub * src_height) :
|
|
||||||
((int64_t)dst_height << RFIX) / (x_add * src_height);
|
|
||||||
wrk->irow = work;
|
|
||||||
wrk->frow = work + dst_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE void ImportRow(const uint8_t* const src,
|
|
||||||
WebPRescaler* const 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.
|
|
||||||
const int32_t base = src[x_in++];
|
|
||||||
const int32_t frac = base * (-accum);
|
|
||||||
wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
|
|
||||||
// fresh fractional start for next pixel
|
|
||||||
sum = (int)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* const wrk) {
|
|
||||||
int x_out;
|
|
||||||
const int yscale = wrk->fy_scale * (-wrk->y_accum);
|
|
||||||
assert(wrk->y_accum <= 0);
|
|
||||||
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
|
|
||||||
const int frac = (int)MULT(wrk->frow[x_out], yscale);
|
|
||||||
const 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef MULT
|
|
||||||
#undef RFIX
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// YUV rescaling (no final RGB conversion needed)
|
// YUV rescaling (no final RGB conversion needed)
|
||||||
|
|
||||||
@ -327,11 +235,11 @@ static int Rescale(const uint8_t* src, int src_stride,
|
|||||||
int new_lines, WebPRescaler* const wrk) {
|
int new_lines, WebPRescaler* const wrk) {
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
while (new_lines-- > 0) { // import new contribution of one source row.
|
while (new_lines-- > 0) { // import new contribution of one source row.
|
||||||
ImportRow(src, wrk);
|
WebPRescalerImportRow(src, wrk);
|
||||||
src += src_stride;
|
src += src_stride;
|
||||||
wrk->y_accum -= wrk->y_sub;
|
wrk->y_accum -= wrk->y_sub;
|
||||||
while (wrk->y_accum <= 0) { // emit output row(s)
|
while (wrk->y_accum <= 0) { // emit output row(s)
|
||||||
ExportRow(wrk);
|
WebPRescalerExportRow(wrk);
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,23 +290,23 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
work = (int32_t*)p->memory;
|
work = (int32_t*)p->memory;
|
||||||
InitRescaler(&p->scaler_y, io->mb_w, io->mb_h,
|
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
|
||||||
buf->y, out_width, out_height, buf->y_stride,
|
buf->y, out_width, out_height, buf->y_stride,
|
||||||
io->mb_w, out_width, io->mb_h, out_height,
|
io->mb_w, out_width, io->mb_h, out_height,
|
||||||
work);
|
work);
|
||||||
InitRescaler(&p->scaler_u, uv_in_width, uv_in_height,
|
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
|
||||||
buf->u, uv_out_width, uv_out_height, buf->u_stride,
|
buf->u, uv_out_width, uv_out_height, buf->u_stride,
|
||||||
uv_in_width, uv_out_width,
|
uv_in_width, uv_out_width,
|
||||||
uv_in_height, uv_out_height,
|
uv_in_height, uv_out_height,
|
||||||
work + work_size);
|
work + work_size);
|
||||||
InitRescaler(&p->scaler_v, uv_in_width, uv_in_height,
|
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
|
||||||
buf->v, uv_out_width, uv_out_height, buf->v_stride,
|
buf->v, uv_out_width, uv_out_height, buf->v_stride,
|
||||||
uv_in_width, uv_out_width,
|
uv_in_width, uv_out_width,
|
||||||
uv_in_height, uv_out_height,
|
uv_in_height, uv_out_height,
|
||||||
work + work_size + uv_work_size);
|
work + work_size + uv_work_size);
|
||||||
p->emit = EmitRescaledYUV;
|
p->emit = EmitRescaledYUV;
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
InitRescaler(&p->scaler_a, io->mb_w, io->mb_h,
|
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
|
||||||
buf->a, out_width, out_height, buf->a_stride,
|
buf->a, out_width, out_height, buf->a_stride,
|
||||||
io->mb_w, out_width, io->mb_h, out_height,
|
io->mb_w, out_width, io->mb_h, out_height,
|
||||||
work + work_size + 2 * uv_work_size);
|
work + work_size + 2 * uv_work_size);
|
||||||
@ -416,7 +324,7 @@ static int Import(const uint8_t* src, int src_stride,
|
|||||||
int new_lines, WebPRescaler* const wrk) {
|
int new_lines, WebPRescaler* const wrk) {
|
||||||
int num_lines_in = 0;
|
int num_lines_in = 0;
|
||||||
while (num_lines_in < new_lines && wrk->y_accum > 0) {
|
while (num_lines_in < new_lines && wrk->y_accum > 0) {
|
||||||
ImportRow(src, wrk);
|
WebPRescalerImportRow(src, wrk);
|
||||||
src += src_stride;
|
src += src_stride;
|
||||||
++num_lines_in;
|
++num_lines_in;
|
||||||
wrk->y_accum -= wrk->y_sub;
|
wrk->y_accum -= wrk->y_sub;
|
||||||
@ -435,9 +343,9 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
|
|||||||
while (p->scaler_y.y_accum <= 0 && p->scaler_u.y_accum <= 0) {
|
while (p->scaler_y.y_accum <= 0 && p->scaler_u.y_accum <= 0) {
|
||||||
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
|
assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
|
||||||
ExportRow(&p->scaler_y);
|
WebPRescalerExportRow(&p->scaler_y);
|
||||||
ExportRow(&p->scaler_u);
|
WebPRescalerExportRow(&p->scaler_u);
|
||||||
ExportRow(&p->scaler_v);
|
WebPRescalerExportRow(&p->scaler_v);
|
||||||
convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
|
convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
|
||||||
dst, p->scaler_y.dst_width);
|
dst, p->scaler_y.dst_width);
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
@ -475,7 +383,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos) {
|
|||||||
while (p->scaler_a.y_accum <= 0) {
|
while (p->scaler_a.y_accum <= 0) {
|
||||||
int i;
|
int i;
|
||||||
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
ExportRow(&p->scaler_a);
|
WebPRescalerExportRow(&p->scaler_a);
|
||||||
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
||||||
dst[4 * i] = p->scaler_a.dst[i];
|
dst[4 * i] = p->scaler_a.dst[i];
|
||||||
}
|
}
|
||||||
@ -492,7 +400,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
|
|||||||
while (p->scaler_a.y_accum <= 0) {
|
while (p->scaler_a.y_accum <= 0) {
|
||||||
int i;
|
int i;
|
||||||
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
ExportRow(&p->scaler_a);
|
WebPRescalerExportRow(&p->scaler_a);
|
||||||
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
for (i = 0; i < p->scaler_a.dst_width; ++i) {
|
||||||
// Fill in the alpha value (converted to 4 bits).
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
const uint32_t alpha_val = clip((p->scaler_a.dst[i] + 8) >> 4, 15);
|
const uint32_t alpha_val = clip((p->scaler_a.dst[i] + 8) >> 4, 15);
|
||||||
@ -543,22 +451,22 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
}
|
}
|
||||||
work = (int32_t*)p->memory;
|
work = (int32_t*)p->memory;
|
||||||
tmp = (uint8_t*)(work + tmp_size1);
|
tmp = (uint8_t*)(work + tmp_size1);
|
||||||
InitRescaler(&p->scaler_y, io->mb_w, io->mb_h,
|
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
|
||||||
tmp + 0 * out_width, out_width, out_height, 0,
|
tmp + 0 * out_width, out_width, out_height, 0,
|
||||||
io->mb_w, out_width, io->mb_h, out_height,
|
io->mb_w, out_width, io->mb_h, out_height,
|
||||||
work + 0 * work_size);
|
work + 0 * work_size);
|
||||||
InitRescaler(&p->scaler_u, uv_in_width, uv_in_height,
|
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
|
||||||
tmp + 1 * out_width, out_width, out_height, 0,
|
tmp + 1 * out_width, out_width, out_height, 0,
|
||||||
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
|
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
|
||||||
work + 1 * work_size);
|
work + 1 * work_size);
|
||||||
InitRescaler(&p->scaler_v, uv_in_width, uv_in_height,
|
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
|
||||||
tmp + 2 * out_width, out_width, out_height, 0,
|
tmp + 2 * out_width, out_width, out_height, 0,
|
||||||
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
|
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
|
||||||
work + 2 * work_size);
|
work + 2 * work_size);
|
||||||
p->emit = EmitRescaledRGB;
|
p->emit = EmitRescaledRGB;
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
InitRescaler(&p->scaler_a, io->mb_w, io->mb_h,
|
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
|
||||||
tmp + 3 * out_width, out_width, out_height, 0,
|
tmp + 3 * out_width, out_width, out_height, 0,
|
||||||
io->mb_w, out_width, io->mb_h, out_height,
|
io->mb_w, out_width, io->mb_h, out_height,
|
||||||
work + 3 * work_size);
|
work + 3 * work_size);
|
||||||
@ -570,59 +478,6 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Default custom functions
|
// Default custom functions
|
||||||
|
|
||||||
// Setup crop_xxx fields, mb_w and mb_h
|
|
||||||
static int InitFromOptions(const WebPDecoderOptions* const options,
|
|
||||||
VP8Io* const io) {
|
|
||||||
const int W = io->width;
|
|
||||||
const int H = io->height;
|
|
||||||
int x = 0, y = 0, w = W, h = H;
|
|
||||||
|
|
||||||
// Cropping
|
|
||||||
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
|
|
||||||
if (io->use_cropping) {
|
|
||||||
w = options->crop_width;
|
|
||||||
h = options->crop_height;
|
|
||||||
// TODO(skal): take colorspace into account. Don't assume YUV420.
|
|
||||||
x = options->crop_left & ~1;
|
|
||||||
y = options->crop_top & ~1;
|
|
||||||
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
|
|
||||||
return 0; // out of frame boundary error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
io->crop_left = x;
|
|
||||||
io->crop_top = y;
|
|
||||||
io->crop_right = x + w;
|
|
||||||
io->crop_bottom = y + h;
|
|
||||||
io->mb_w = w;
|
|
||||||
io->mb_h = h;
|
|
||||||
|
|
||||||
// Scaling
|
|
||||||
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
|
|
||||||
if (io->use_scaling) {
|
|
||||||
if (options->scaled_width <= 0 || options->scaled_height <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
io->scaled_width = options->scaled_width;
|
|
||||||
io->scaled_height = options->scaled_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter
|
|
||||||
io->bypass_filtering = options && options->bypass_filtering;
|
|
||||||
|
|
||||||
// Fancy upsampler
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
|
||||||
io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (io->use_scaling) {
|
|
||||||
// disable filter (only for large downscaling ratio).
|
|
||||||
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
|
|
||||||
(io->scaled_height < H * 3 / 4);
|
|
||||||
io->fancy_upsampling = 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CustomSetup(VP8Io* io) {
|
static int CustomSetup(VP8Io* io) {
|
||||||
WebPDecParams* const p = (WebPDecParams*)io->opaque;
|
WebPDecParams* const p = (WebPDecParams*)io->opaque;
|
||||||
const int is_rgb = (p->output->colorspace < MODE_YUV);
|
const int is_rgb = (p->output->colorspace < MODE_YUV);
|
||||||
@ -630,7 +485,7 @@ static int CustomSetup(VP8Io* io) {
|
|||||||
p->memory = NULL;
|
p->memory = NULL;
|
||||||
p->emit = NULL;
|
p->emit = NULL;
|
||||||
p->emit_alpha = NULL;
|
p->emit_alpha = NULL;
|
||||||
if (!InitFromOptions(p->options, io)) {
|
if (!WebPIoInitFromOptions(p->options, io)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
140
src/dec/webp.c
140
src/dec/webp.c
@ -609,6 +609,146 @@ VP8StatusCode WebPDecode(const uint8_t* data, uint32_t data_size,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Simple picture rescaler
|
||||||
|
|
||||||
|
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||||
|
VP8Io* const io) {
|
||||||
|
const int W = io->width;
|
||||||
|
const int H = io->height;
|
||||||
|
int x = 0, y = 0, w = W, h = H;
|
||||||
|
|
||||||
|
// Cropping
|
||||||
|
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
|
||||||
|
if (io->use_cropping) {
|
||||||
|
w = options->crop_width;
|
||||||
|
h = options->crop_height;
|
||||||
|
// TODO(skal): take colorspace into account. Don't assume YUV420.
|
||||||
|
x = options->crop_left & ~1;
|
||||||
|
y = options->crop_top & ~1;
|
||||||
|
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
|
||||||
|
return 0; // out of frame boundary error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io->crop_left = x;
|
||||||
|
io->crop_top = y;
|
||||||
|
io->crop_right = x + w;
|
||||||
|
io->crop_bottom = y + h;
|
||||||
|
io->mb_w = w;
|
||||||
|
io->mb_h = h;
|
||||||
|
|
||||||
|
// Scaling
|
||||||
|
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
|
||||||
|
if (io->use_scaling) {
|
||||||
|
if (options->scaled_width <= 0 || options->scaled_height <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
io->scaled_width = options->scaled_width;
|
||||||
|
io->scaled_height = options->scaled_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
io->bypass_filtering = options && options->bypass_filtering;
|
||||||
|
|
||||||
|
// Fancy upsampler
|
||||||
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (io->use_scaling) {
|
||||||
|
// disable filter (only for large downscaling ratio).
|
||||||
|
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
|
||||||
|
(io->scaled_height < H * 3 / 4);
|
||||||
|
io->fancy_upsampling = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RFIX 30
|
||||||
|
#define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
|
||||||
|
|
||||||
|
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||||
|
uint8_t* dst, int dst_width, int dst_height,
|
||||||
|
int dst_stride, int x_add, int x_sub, int y_add,
|
||||||
|
int y_sub, int32_t* 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 ?
|
||||||
|
((int64_t)dst_height << RFIX) / (x_sub * src_height) :
|
||||||
|
((int64_t)dst_height << RFIX) / (x_add * src_height);
|
||||||
|
wrk->irow = work;
|
||||||
|
wrk->frow = work + dst_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPRescalerImportRow(const uint8_t* const src, WebPRescaler* const 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.
|
||||||
|
const int32_t base = src[x_in++];
|
||||||
|
const int32_t frac = base * (-accum);
|
||||||
|
wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
|
||||||
|
// fresh fractional start for next pixel
|
||||||
|
sum = (int)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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPRescalerExportRow(WebPRescaler* const wrk) {
|
||||||
|
int x_out;
|
||||||
|
const int yscale = wrk->fy_scale * (-wrk->y_accum);
|
||||||
|
assert(wrk->y_accum <= 0);
|
||||||
|
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
|
||||||
|
const int frac = (int)MULT(wrk->frow[x_out], yscale);
|
||||||
|
const 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef MULT
|
||||||
|
#undef RFIX
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -159,6 +159,25 @@ void WebPCopyDecBuffer(const WebPDecBuffer* const src,
|
|||||||
// Copy and transfer ownership from src to dst (beware of parameter order!)
|
// Copy and transfer ownership from src to dst (beware of parameter order!)
|
||||||
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
|
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Cropping and rescaling.
|
||||||
|
|
||||||
|
// Setup crop_xxx fields, mb_w and mb_h
|
||||||
|
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||||
|
VP8Io* const io);
|
||||||
|
|
||||||
|
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
|
||||||
|
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||||
|
uint8_t* dst, int dst_width, int dst_height,
|
||||||
|
int dst_stride, int x_add, int x_sub, int y_add,
|
||||||
|
int y_sub, int32_t* work);
|
||||||
|
|
||||||
|
// Import a row of data and save its contribution in the rescaler.
|
||||||
|
void WebPRescalerImportRow(const uint8_t* const src, WebPRescaler* const wrk);
|
||||||
|
|
||||||
|
// Export a row from rescaler.
|
||||||
|
void WebPRescalerExportRow(WebPRescaler* const wrk);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user