/src/libwebp/src/utils/rescaler_utils.c
Line  | Count  | Source (jump to first uncovered line)  | 
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  | 0  |                      int num_channels, rescaler_t* const work) { | 
31  | 0  |   const int x_add = src_width, x_sub = dst_width;  | 
32  | 0  |   const int y_add = src_height, y_sub = dst_height;  | 
33  | 0  |   const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work);  | 
34  | 0  |   if (!CheckSizeOverflow(total_size)) return 0;  | 
35  |  |  | 
36  | 0  |   rescaler->x_expand = (src_width < dst_width);  | 
37  | 0  |   rescaler->y_expand = (src_height < dst_height);  | 
38  | 0  |   rescaler->src_width = src_width;  | 
39  | 0  |   rescaler->src_height = src_height;  | 
40  | 0  |   rescaler->dst_width = dst_width;  | 
41  | 0  |   rescaler->dst_height = dst_height;  | 
42  | 0  |   rescaler->src_y = 0;  | 
43  | 0  |   rescaler->dst_y = 0;  | 
44  | 0  |   rescaler->dst = dst;  | 
45  | 0  |   rescaler->dst_stride = dst_stride;  | 
46  | 0  |   rescaler->num_channels = num_channels;  | 
47  |  |  | 
48  |  |   // for 'x_expand', we use bilinear interpolation  | 
49  | 0  |   rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add;  | 
50  | 0  |   rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub;  | 
51  | 0  |   if (!rescaler->x_expand) {  // fx_scale is not used otherwise | 
52  | 0  |     rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub);  | 
53  | 0  |   }  | 
54  |  |   // vertical scaling parameters  | 
55  | 0  |   rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add;  | 
56  | 0  |   rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub;  | 
57  | 0  |   rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add;  | 
58  | 0  |   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  | 0  |     const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE;  | 
63  | 0  |     const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add;  | 
64  | 0  |     const uint64_t ratio = num / den;  | 
65  | 0  |     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  | 0  |       rescaler->fxy_scale = 0;  | 
71  | 0  |     } else { | 
72  | 0  |       rescaler->fxy_scale = (uint32_t)ratio;  | 
73  | 0  |     }  | 
74  | 0  |     rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub);  | 
75  | 0  |   } else { | 
76  | 0  |     rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add);  | 
77  |  |     // rescaler->fxy_scale is unused here.  | 
78  | 0  |   }  | 
79  | 0  |   rescaler->irow = work;  | 
80  | 0  |   rescaler->frow = work + num_channels * dst_width;  | 
81  | 0  |   memset(work, 0, (size_t)total_size);  | 
82  |  | 
  | 
83  | 0  |   WebPRescalerDspInit();  | 
84  | 0  |   return 1;  | 
85  | 0  | }  | 
86  |  |  | 
87  |  | int WebPRescalerGetScaledDimensions(int src_width, int src_height,  | 
88  |  |                                     int* const scaled_width,  | 
89  | 0  |                                     int* const scaled_height) { | 
90  | 0  |   assert(scaled_width != NULL);  | 
91  | 0  |   assert(scaled_height != NULL);  | 
92  | 0  |   { | 
93  | 0  |     int width = *scaled_width;  | 
94  | 0  |     int height = *scaled_height;  | 
95  | 0  |     const int max_size = INT_MAX / 2;  | 
96  |  |  | 
97  |  |     // if width is unspecified, scale original proportionally to height ratio.  | 
98  | 0  |     if (width == 0 && src_height > 0) { | 
99  | 0  |       width =  | 
100  | 0  |           (int)(((uint64_t)src_width * height + src_height - 1) / src_height);  | 
101  | 0  |     }  | 
102  |  |     // if height is unspecified, scale original proportionally to width ratio.  | 
103  | 0  |     if (height == 0 && src_width > 0) { | 
104  | 0  |       height =  | 
105  | 0  |           (int)(((uint64_t)src_height * width + src_width - 1) / src_width);  | 
106  | 0  |     }  | 
107  |  |     // Check if the overall dimensions still make sense.  | 
108  | 0  |     if (width <= 0 || height <= 0 || width > max_size || height > max_size) { | 
109  | 0  |       return 0;  | 
110  | 0  |     }  | 
111  |  |  | 
112  | 0  |     *scaled_width = width;  | 
113  | 0  |     *scaled_height = height;  | 
114  | 0  |     return 1;  | 
115  | 0  |   }  | 
116  | 0  | }  | 
117  |  |  | 
118  |  | //------------------------------------------------------------------------------  | 
119  |  | // all-in-one calls  | 
120  |  |  | 
121  |  | int WebPRescaleNeededLines(const WebPRescaler* const rescaler,  | 
122  | 0  |                            int max_num_lines) { | 
123  | 0  |   const int num_lines =  | 
124  | 0  |       (rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub;  | 
125  | 0  |   return (num_lines > max_num_lines) ? max_num_lines : num_lines;  | 
126  | 0  | }  | 
127  |  |  | 
128  |  | int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines,  | 
129  | 0  |                        const uint8_t* src, int src_stride) { | 
130  | 0  |   int total_imported = 0;  | 
131  | 0  |   while (total_imported < num_lines &&  | 
132  | 0  |          !WebPRescalerHasPendingOutput(rescaler)) { | 
133  | 0  |     if (rescaler->y_expand) { | 
134  | 0  |       rescaler_t* const tmp = rescaler->irow;  | 
135  | 0  |       rescaler->irow = rescaler->frow;  | 
136  | 0  |       rescaler->frow = tmp;  | 
137  | 0  |     }  | 
138  | 0  |     WebPRescalerImportRow(rescaler, src);  | 
139  | 0  |     if (!rescaler->y_expand) {    // Accumulate the contribution of the new row. | 
140  | 0  |       int x;  | 
141  | 0  |       for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) { | 
142  | 0  |         rescaler->irow[x] += rescaler->frow[x];  | 
143  | 0  |       }  | 
144  | 0  |     }  | 
145  | 0  |     ++rescaler->src_y;  | 
146  | 0  |     src += src_stride;  | 
147  | 0  |     ++total_imported;  | 
148  | 0  |     rescaler->y_accum -= rescaler->y_sub;  | 
149  | 0  |   }  | 
150  | 0  |   return total_imported;  | 
151  | 0  | }  | 
152  |  |  | 
153  | 0  | int WebPRescalerExport(WebPRescaler* const rescaler) { | 
154  | 0  |   int total_exported = 0;  | 
155  | 0  |   while (WebPRescalerHasPendingOutput(rescaler)) { | 
156  | 0  |     WebPRescalerExportRow(rescaler);  | 
157  | 0  |     ++total_exported;  | 
158  | 0  |   }  | 
159  | 0  |   return total_exported;  | 
160  | 0  | }  | 
161  |  |  | 
162  |  | //------------------------------------------------------------------------------  |