5 * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz>
11 #include "core/GP_Pixmap.h"
12 #include "core/GP_GetPutPixel.h"
13 #include "core/GP_Gamma.h"
15 #include "core/GP_Debug.h"
17 #include "GP_Resize.h"
19 @ def fetch_rows(pt, y):
20 for (x = 0; x < src->w; x++) {
21 GP_Pixel pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, x, {{ y }});
22 @ for c in pt.chanslist:
23 {{ c.name }}[x] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
28 @ def sum_rows(pt, mult):
29 for (x = 0; x < dst->w; x++) {
30 /* Get first left pixel */
31 @ for c in pt.chanslist:
32 uint32_t {{ c.name }}_middle = 0;
33 uint32_t {{ c.name }}_first = {{ c.name }}[xmap[x]] * (MULT - xoff[x]);
35 /* Sum middle pixels */
36 for (j = xmap[x]+1; j < xmap[x+1]; j++) {
37 @ for c in pt.chanslist:
38 {{ c.name }}_middle += {{ c.name }}[j];
41 /* Add it all together with last pixel on the right */
42 @ for c in pt.chanslist:
43 {{ c.name }}_res[x] += ({{ c.name }}_middle * (MULT / DIV) +
44 ({{ c.name }}[xmap[x+1]] * xoff[x+1] +
45 {{ c.name }}_first) / DIV) * {{ mult }} / DIV;
50 @ for pt in pixeltypes:
51 @ if not pt.is_unknown() and not pt.is_palette():
52 static int resize_lin_lf_{{ pt.name }}(const GP_Pixmap *src, GP_Pixmap *dst,
53 GP_ProgressCallback *callback)
55 uint32_t xmap[dst->w + 1];
56 uint32_t ymap[dst->h + 1];
57 uint32_t xoff[dst->w + 1];
58 uint32_t yoff[dst->h + 1];
59 @ for c in pt.chanslist:
60 uint32_t {{ c.name }}[src->w];
64 @ # Reduce fixed point bits for > 8 bits per channel (fixed 16 bit Grayscale)
65 @ if pt.chanslist[0].size > 8:
73 /* Pre-compute mapping for interpolation */
74 for (i = 0; i <= dst->w; i++) {
75 xmap[i] = ((uint64_t)i * src->w) / dst->w;
76 xoff[i] = ((uint64_t)MULT * (i * src->w))/dst->w - MULT * xmap[i];
79 for (i = 0; i <= dst->h; i++) {
80 ymap[i] = ((uint64_t)i * src->h) / dst->h;
81 yoff[i] = ((uint64_t)MULT * (i * src->h))/dst->h - MULT * ymap[i];
84 /* Compute pixel area for the final normalization */
85 uint32_t div = (((uint64_t)(xmap[1] * MULT + xoff[1]) * ((uint64_t)ymap[1] * MULT + yoff[1]) + DIV/2) / DIV + DIV/2)/DIV;
87 /* Prefetch first row */
88 {@ fetch_rows(pt, 0) @}
90 for (y = 0; y < dst->h; y++) {
91 @ for c in pt.chanslist:
92 uint32_t {{ c.name }}_res[dst->w];
95 @ for c in pt.chanslist:
96 memset({{ c.name }}_res, 0, sizeof({{ c.name }}_res));
100 {@ sum_rows(pt, '(MULT-yoff[y])') @}
103 for (i = ymap[y]+1; i < ymap[y+1]; i++) {
104 {@ fetch_rows(pt, 'i') @}
105 {@ sum_rows(pt, 'MULT') @}
110 {@ fetch_rows(pt, 'ymap[y+1]') @}
111 {@ sum_rows(pt, 'yoff[y+1]') @}
114 for (x = 0; x < dst->w; x++) {
115 @ for c in pt.chanslist:
116 uint32_t {{ c.name }}_p = ({{ c.name }}_res[x] + div/2) / div;
118 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x, y,
119 GP_Pixel_CREATE_{{ pt.name }}({{ arr_to_params(pt.chan_names, '', '_p') }}));
122 if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
126 GP_ProgressCallbackDone(callback);
132 @ for pt in pixeltypes:
133 @ if not pt.is_unknown() and not pt.is_palette():
134 static int resize_lin{{ pt.name }}(const GP_Pixmap *src, GP_Pixmap *dst,
135 GP_ProgressCallback *callback)
137 uint32_t xmap[dst->w + 1];
138 uint32_t ymap[dst->h + 1];
139 uint8_t xoff[dst->w + 1];
140 uint8_t yoff[dst->h + 1];
143 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
144 src->w, src->h, dst->w, dst->h,
145 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
147 /* Pre-compute mapping for interpolation */
148 uint32_t xstep = ((src->w - 1) << 16) / (dst->w - 1);
150 for (i = 0; i < dst->w + 1; i++) {
151 uint32_t val = i * xstep;
153 xoff[i] = (val >> 8) & 0xff;
156 uint32_t ystep = ((src->h - 1) << 16) / (dst->h - 1);
158 for (i = 0; i < dst->h + 1; i++) {
159 uint32_t val = i * ystep;
161 yoff[i] = (val >> 8) & 0xff;
165 for (y = 0; y < dst->h; y++) {
166 for (x = 0; x < dst->w; x++) {
167 GP_Pixel pix00, pix01, pix10, pix11;
168 GP_Coord x0, x1, y0, y1;
169 @ for c in pt.chanslist:
170 uint32_t {{ c[0] }}, {{ c[0] }}0, {{ c[0] }}1;
176 if (x1 >= (GP_Coord)src->w)
182 if (y1 >= (GP_Coord)src->h)
185 pix00 = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, x0, y0);
186 pix10 = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, x1, y0);
187 pix01 = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, x0, y1);
188 pix11 = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, x1, y1);
190 @ for c in pt.chanslist:
191 {{ c.name }}0 = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix00) * (255 - xoff[x]);
194 @ for c in pt.chanslist:
195 {{ c.name }}0 += GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix10) * xoff[x];
198 @ for c in pt.chanslist:
199 {{ c.name }}1 = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix01) * (255 - xoff[x]);
202 @ for c in pt.chanslist:
203 {{ c.name }}1 += GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix11) * xoff[x];
206 @ for c in pt.chanslist:
207 {{ c.name }} = ({{ c.name }}1 * yoff[y] + {{ c.name }}0 * (255 - yoff[y]) + (1<<15)) >> 16;
210 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x, y,
211 GP_Pixel_CREATE_{{ pt.name }}({{ arr_to_params(pt.chan_names) }}));
214 if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
218 GP_ProgressCallbackDone(callback);
224 static int resize_lin(const GP_Pixmap *src, GP_Pixmap *dst,
225 GP_ProgressCallback *callback)
227 switch (src->pixel_type) {
228 @ for pt in pixeltypes:
229 @ if not pt.is_unknown() and not pt.is_palette():
230 case GP_PIXEL_{{ pt.name }}:
231 return resize_lin{{ pt.name }}(src, dst, callback);
235 GP_WARN("Invalid pixel type %s",
236 GP_PixelTypeName(src->pixel_type));
242 int GP_FilterResizeLinearInt(const GP_Pixmap *src, GP_Pixmap *dst,
243 GP_ProgressCallback *callback)
245 if (src->pixel_type != dst->pixel_type) {
246 GP_WARN("The src and dst pixel types must match");
251 return resize_lin(src, dst, callback);
254 static int resize_lin_lf(const GP_Pixmap *src, GP_Pixmap *dst,
255 GP_ProgressCallback *callback)
257 float x_rat = 1.00 * dst->w / src->w;
258 float y_rat = 1.00 * dst->h / src->h;
260 if (x_rat < 1.00 && y_rat < 1.00) {
262 GP_DEBUG(1, "Downscaling image %ux%u -> %ux%u %2.2f %2.2f",
263 src->w, src->h, dst->w, dst->h, x_rat, y_rat);
265 switch (src->pixel_type) {
266 @ for pt in pixeltypes:
267 @ if not pt.is_unknown() and not pt.is_palette():
268 case GP_PIXEL_{{ pt.name }}:
269 return resize_lin_lf_{{ pt.name }}(src, dst, callback);
273 GP_WARN("Invalid pixel type %s",
274 GP_PixelTypeName(src->pixel_type));
280 //TODO: x_rat > 1.00 && y_rat < 1.00
281 //TODO: x_rat < 1.00 && y_rat > 1.00
283 return resize_lin(src, dst, callback);
286 int GP_FilterResizeLinearLFInt(const GP_Pixmap *src, GP_Pixmap *dst,
287 GP_ProgressCallback *callback)
289 if (src->pixel_type != dst->pixel_type) {
290 GP_WARN("The src and dst pixel types must match");
295 return resize_lin_lf(src, dst, callback);