Path: blob/master/thirdparty/libwebp/src/utils/rescaler_utils.c
21257 views
// Copyright 2012 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// Rescaling functions10//11// Author: Skal ([email protected])1213#include <assert.h>14#include <limits.h>15#include <stdlib.h>16#include <string.h>1718#include "src/dsp/dsp.h"19#include "src/webp/types.h"20#include "src/utils/rescaler_utils.h"21#include "src/utils/utils.h"2223//------------------------------------------------------------------------------2425int WebPRescalerInit(WebPRescaler* const rescaler,26int src_width, int src_height,27uint8_t* const dst,28int dst_width, int dst_height, int dst_stride,29int num_channels, rescaler_t* const work) {30const int x_add = src_width, x_sub = dst_width;31const int y_add = src_height, y_sub = dst_height;32const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work);33if (!CheckSizeOverflow(total_size)) return 0;3435rescaler->x_expand = (src_width < dst_width);36rescaler->y_expand = (src_height < dst_height);37rescaler->src_width = src_width;38rescaler->src_height = src_height;39rescaler->dst_width = dst_width;40rescaler->dst_height = dst_height;41rescaler->src_y = 0;42rescaler->dst_y = 0;43rescaler->dst = dst;44rescaler->dst_stride = dst_stride;45rescaler->num_channels = num_channels;4647// for 'x_expand', we use bilinear interpolation48rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add;49rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub;50if (!rescaler->x_expand) { // fx_scale is not used otherwise51rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub);52}53// vertical scaling parameters54rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add;55rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub;56rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add;57if (!rescaler->y_expand) {58// This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.59// Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add60// and rescaler->x_add >= 1;61const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE;62const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add;63const uint64_t ratio = num / den;64if (ratio != (uint32_t)ratio) {65// When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the66// current fixed-point precision. This happens when src_height ==67// rescaler->y_add (which == src_height), and rescaler->x_add == 1.68// => We special-case fxy_scale = 0, in WebPRescalerExportRow().69rescaler->fxy_scale = 0;70} else {71rescaler->fxy_scale = (uint32_t)ratio;72}73rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub);74} else {75rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add);76// rescaler->fxy_scale is unused here.77}78rescaler->irow = work;79rescaler->frow = work + num_channels * dst_width;80memset(work, 0, (size_t)total_size);8182WebPRescalerDspInit();83return 1;84}8586int WebPRescalerGetScaledDimensions(int src_width, int src_height,87int* const scaled_width,88int* const scaled_height) {89assert(scaled_width != NULL);90assert(scaled_height != NULL);91{92int width = *scaled_width;93int height = *scaled_height;94const int max_size = INT_MAX / 2;9596// if width is unspecified, scale original proportionally to height ratio.97if (width == 0 && src_height > 0) {98width =99(int)(((uint64_t)src_width * height + src_height - 1) / src_height);100}101// if height is unspecified, scale original proportionally to width ratio.102if (height == 0 && src_width > 0) {103height =104(int)(((uint64_t)src_height * width + src_width - 1) / src_width);105}106// Check if the overall dimensions still make sense.107if (width <= 0 || height <= 0 || width > max_size || height > max_size) {108return 0;109}110111*scaled_width = width;112*scaled_height = height;113return 1;114}115}116117//------------------------------------------------------------------------------118// all-in-one calls119120int WebPRescaleNeededLines(const WebPRescaler* const rescaler,121int max_num_lines) {122const int num_lines =123(rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub;124return (num_lines > max_num_lines) ? max_num_lines : num_lines;125}126127int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines,128const uint8_t* src, int src_stride) {129int total_imported = 0;130while (total_imported < num_lines &&131!WebPRescalerHasPendingOutput(rescaler)) {132if (rescaler->y_expand) {133rescaler_t* const tmp = rescaler->irow;134rescaler->irow = rescaler->frow;135rescaler->frow = tmp;136}137WebPRescalerImportRow(rescaler, src);138if (!rescaler->y_expand) { // Accumulate the contribution of the new row.139int x;140for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) {141rescaler->irow[x] += rescaler->frow[x];142}143}144++rescaler->src_y;145src += src_stride;146++total_imported;147rescaler->y_accum -= rescaler->y_sub;148}149return total_imported;150}151152int WebPRescalerExport(WebPRescaler* const rescaler) {153int total_exported = 0;154while (WebPRescalerHasPendingOutput(rescaler)) {155WebPRescalerExportRow(rescaler);156++total_exported;157}158return total_exported;159}160161//------------------------------------------------------------------------------162163164