mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-13 14:34:33 +02:00
fix rescaler vertical interpolation
* vertical expansion now uses bilinear interpolation * heavily assumes that the alpha plane is decoded in full, not row-by-row * split the RescalerExportRow and RescalerImportRow methods into Shrink and Expand variants. * MIPS implementation of ExportRowExpand is missing. There's room for extra speed optim and code re-org, but let's keep that for later patches. addresses https://code.google.com/p/webp/issues/detail?id=254 Change-Id: I8f12b855342bf07dd467fe85e4fde5fd814effdb
This commit is contained in:
committed by
James Zern
parent
cd82440ec7
commit
5ff0079ece
@ -22,7 +22,7 @@
|
||||
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels, int32_t* const work) {
|
||||
int num_channels, rescaler_t* const work) {
|
||||
const int x_add = src_width, x_sub = dst_width;
|
||||
const int y_add = src_height, y_sub = dst_height;
|
||||
wrk->x_expand = (src_width < dst_width);
|
||||
@ -31,6 +31,8 @@ void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||
wrk->src_height = src_height;
|
||||
wrk->dst_width = dst_width;
|
||||
wrk->dst_height = dst_height;
|
||||
wrk->src_y = 0;
|
||||
wrk->dst_y = 0;
|
||||
wrk->dst = dst;
|
||||
wrk->dst_stride = dst_stride;
|
||||
wrk->num_channels = num_channels;
|
||||
@ -39,18 +41,20 @@ void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||
wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
|
||||
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
|
||||
if (!wrk->x_expand) { // fx_scale is not used otherwise
|
||||
wrk->fx_scale = (1 << WEBP_RESCALER_RFIX) / wrk->x_sub;
|
||||
wrk->fx_scale = WEBP_RESCALER_ONE / wrk->x_sub;
|
||||
}
|
||||
|
||||
// vertical scaling parameters
|
||||
wrk->y_accum = y_add;
|
||||
wrk->y_add = y_add;
|
||||
wrk->y_sub = y_sub;
|
||||
wrk->fy_scale = (1 << WEBP_RESCALER_RFIX) / wrk->y_sub;
|
||||
|
||||
wrk->fxy_scale =
|
||||
((int64_t)dst_height << WEBP_RESCALER_RFIX) / (wrk->x_add * wrk->y_add);
|
||||
|
||||
wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
|
||||
wrk->y_sub = wrk->y_expand ? y_sub - 1: y_sub;
|
||||
wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
|
||||
if (!wrk->y_expand) {
|
||||
wrk->fy_scale = WEBP_RESCALER_ONE / wrk->y_sub;
|
||||
wrk->fxy_scale = ((uint64_t)dst_height << WEBP_RESCALER_RFIX)
|
||||
/ (wrk->x_add * wrk->y_add);
|
||||
} else {
|
||||
wrk->fy_scale = WEBP_RESCALER_ONE / wrk->x_add;
|
||||
wrk->fxy_scale = WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_sub);
|
||||
}
|
||||
wrk->irow = work;
|
||||
wrk->frow = work + num_channels * dst_width;
|
||||
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
|
||||
@ -98,10 +102,21 @@ int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
|
||||
const uint8_t* src, int src_stride) {
|
||||
int total_imported = 0;
|
||||
while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
|
||||
int channel;
|
||||
int x, channel;
|
||||
if (wrk->y_expand) {
|
||||
rescaler_t* const tmp = wrk->irow;
|
||||
wrk->irow = wrk->frow;
|
||||
wrk->frow = tmp;
|
||||
}
|
||||
for (channel = 0; channel < wrk->num_channels; ++channel) {
|
||||
WebPRescalerImportRow(wrk, src, channel);
|
||||
}
|
||||
if (!wrk->y_expand) { // Accumulate the contribution of the new row.
|
||||
for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
|
||||
wrk->irow[x] += wrk->frow[x];
|
||||
}
|
||||
}
|
||||
++wrk->src_y;
|
||||
src += src_stride;
|
||||
++total_imported;
|
||||
wrk->y_accum -= wrk->y_sub;
|
||||
@ -112,7 +127,7 @@ int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
|
||||
int WebPRescalerExport(WebPRescaler* const rescaler) {
|
||||
int total_exported = 0;
|
||||
while (WebPRescalerHasPendingOutput(rescaler)) {
|
||||
WebPRescalerExportRow(rescaler, 0);
|
||||
WebPRescalerExportRow(rescaler);
|
||||
++total_exported;
|
||||
}
|
||||
return total_exported;
|
||||
|
@ -21,23 +21,27 @@ extern "C" {
|
||||
#include "../webp/types.h"
|
||||
|
||||
#define WEBP_RESCALER_RFIX 30 // fixed-point precision for multiplies
|
||||
#define WEBP_RESCALER_ONE (1u << WEBP_RESCALER_RFIX)
|
||||
|
||||
// Structure used for on-the-fly rescaling
|
||||
typedef int32_t rescaler_t; // type for side-buffer
|
||||
typedef struct WebPRescaler WebPRescaler;
|
||||
struct WebPRescaler {
|
||||
int x_expand; // true if we're expanding in the x direction
|
||||
int y_expand; // true if we're expanding in the y direction
|
||||
int num_channels; // bytes to jump between pixels
|
||||
int fy_scale, fx_scale; // fixed-point scaling factor
|
||||
int64_t fxy_scale; // ''
|
||||
uint32_t fx_scale; // fixed-point scaling factors
|
||||
uint32_t fy_scale; // ''
|
||||
uint64_t fxy_scale; // ''
|
||||
int y_accum; // vertical accumulator
|
||||
int y_add, y_sub; // vertical increments
|
||||
int x_add, x_sub; // horizontal increments
|
||||
int src_width, src_height; // source dimensions
|
||||
int dst_width, dst_height; // destination dimensions
|
||||
int src_y, dst_y; // row counters for input and output
|
||||
uint8_t* dst;
|
||||
int dst_stride;
|
||||
int32_t* irow, *frow; // work buffer
|
||||
rescaler_t* irow, *frow; // work buffer
|
||||
};
|
||||
|
||||
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
|
||||
@ -46,7 +50,7 @@ void WebPRescalerInit(WebPRescaler* const rescaler,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels,
|
||||
int32_t* const work);
|
||||
rescaler_t* const work);
|
||||
|
||||
// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
|
||||
// will be calculated preserving the aspect ratio, otherwise the values are
|
||||
@ -66,15 +70,26 @@ int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
|
||||
int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows,
|
||||
const uint8_t* src, int src_stride);
|
||||
|
||||
// Return true if there is pending output rows ready.
|
||||
static WEBP_INLINE
|
||||
int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
|
||||
return (rescaler->y_accum <= 0);
|
||||
}
|
||||
|
||||
// Export as many rows as possible. Return the numbers of rows written.
|
||||
int WebPRescalerExport(WebPRescaler* const rescaler);
|
||||
|
||||
// Return true if input is finished
|
||||
static WEBP_INLINE
|
||||
int WebPRescalerInputDone(const WebPRescaler* const rescaler) {
|
||||
return (rescaler->src_y >= rescaler->src_height);
|
||||
}
|
||||
// Return true if output is finished
|
||||
static WEBP_INLINE
|
||||
int WebPRescalerOutputDone(const WebPRescaler* const rescaler) {
|
||||
return (rescaler->dst_y >= rescaler->dst_height);
|
||||
}
|
||||
|
||||
// Return true if there are pending output rows ready.
|
||||
static WEBP_INLINE
|
||||
int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
|
||||
return !WebPRescalerOutputDone(rescaler) && (rescaler->y_accum <= 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Reference in New Issue
Block a user