rescaler_utils.c (5945B)
1 // Copyright 2012 Google Inc. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the COPYING file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 // ----------------------------------------------------------------------------- 9 // 10 // Rescaling functions 11 // 12 // Author: Skal (pascal.massimino@gmail.com) 13 14 #include <assert.h> 15 #include <limits.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include "src/dsp/dsp.h" 20 #include "src/webp/types.h" 21 #include "src/utils/rescaler_utils.h" 22 #include "src/utils/utils.h" 23 24 //------------------------------------------------------------------------------ 25 26 int WebPRescalerInit(WebPRescaler* const rescaler, 27 int src_width, int src_height, 28 uint8_t* const dst, 29 int dst_width, int dst_height, int dst_stride, 30 int num_channels, rescaler_t* const work) { 31 const int x_add = src_width, x_sub = dst_width; 32 const int y_add = src_height, y_sub = dst_height; 33 const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work); 34 if (!CheckSizeOverflow(total_size)) return 0; 35 36 rescaler->x_expand = (src_width < dst_width); 37 rescaler->y_expand = (src_height < dst_height); 38 rescaler->src_width = src_width; 39 rescaler->src_height = src_height; 40 rescaler->dst_width = dst_width; 41 rescaler->dst_height = dst_height; 42 rescaler->src_y = 0; 43 rescaler->dst_y = 0; 44 rescaler->dst = dst; 45 rescaler->dst_stride = dst_stride; 46 rescaler->num_channels = num_channels; 47 48 // for 'x_expand', we use bilinear interpolation 49 rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add; 50 rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub; 51 if (!rescaler->x_expand) { // fx_scale is not used otherwise 52 rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub); 53 } 54 // vertical scaling parameters 55 rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add; 56 rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub; 57 rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add; 58 if (!rescaler->y_expand) { 59 // This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast. 60 // Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add 61 // and rescaler->x_add >= 1; 62 const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE; 63 const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add; 64 const uint64_t ratio = num / den; 65 if (ratio != (uint32_t)ratio) { 66 // When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the 67 // current fixed-point precision. This happens when src_height == 68 // rescaler->y_add (which == src_height), and rescaler->x_add == 1. 69 // => We special-case fxy_scale = 0, in WebPRescalerExportRow(). 70 rescaler->fxy_scale = 0; 71 } else { 72 rescaler->fxy_scale = (uint32_t)ratio; 73 } 74 rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub); 75 } else { 76 rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add); 77 // rescaler->fxy_scale is unused here. 78 } 79 rescaler->irow = work; 80 rescaler->frow = work + num_channels * dst_width; 81 memset(work, 0, (size_t)total_size); 82 83 WebPRescalerDspInit(); 84 return 1; 85 } 86 87 int WebPRescalerGetScaledDimensions(int src_width, int src_height, 88 int* const scaled_width, 89 int* const scaled_height) { 90 assert(scaled_width != NULL); 91 assert(scaled_height != NULL); 92 { 93 int width = *scaled_width; 94 int height = *scaled_height; 95 const int max_size = INT_MAX / 2; 96 97 // if width is unspecified, scale original proportionally to height ratio. 98 if (width == 0 && src_height > 0) { 99 width = 100 (int)(((uint64_t)src_width * height + src_height - 1) / src_height); 101 } 102 // if height is unspecified, scale original proportionally to width ratio. 103 if (height == 0 && src_width > 0) { 104 height = 105 (int)(((uint64_t)src_height * width + src_width - 1) / src_width); 106 } 107 // Check if the overall dimensions still make sense. 108 if (width <= 0 || height <= 0 || width > max_size || height > max_size) { 109 return 0; 110 } 111 112 *scaled_width = width; 113 *scaled_height = height; 114 return 1; 115 } 116 } 117 118 //------------------------------------------------------------------------------ 119 // all-in-one calls 120 121 int WebPRescaleNeededLines(const WebPRescaler* const rescaler, 122 int max_num_lines) { 123 const int num_lines = 124 (rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub; 125 return (num_lines > max_num_lines) ? max_num_lines : num_lines; 126 } 127 128 int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines, 129 const uint8_t* src, int src_stride) { 130 int total_imported = 0; 131 while (total_imported < num_lines && 132 !WebPRescalerHasPendingOutput(rescaler)) { 133 if (rescaler->y_expand) { 134 rescaler_t* const tmp = rescaler->irow; 135 rescaler->irow = rescaler->frow; 136 rescaler->frow = tmp; 137 } 138 WebPRescalerImportRow(rescaler, src); 139 if (!rescaler->y_expand) { // Accumulate the contribution of the new row. 140 int x; 141 for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) { 142 rescaler->irow[x] += rescaler->frow[x]; 143 } 144 } 145 ++rescaler->src_y; 146 src += src_stride; 147 ++total_imported; 148 rescaler->y_accum -= rescaler->y_sub; 149 } 150 return total_imported; 151 } 152 153 int WebPRescalerExport(WebPRescaler* const rescaler) { 154 int total_exported = 0; 155 while (WebPRescalerHasPendingOutput(rescaler)) { 156 WebPRescalerExportRow(rescaler); 157 ++total_exported; 158 } 159 return total_exported; 160 } 161 162 //------------------------------------------------------------------------------