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"
14 #include "core/GP_Clamp.h"
15 #include "core/GP_Debug.h"
19 #include "GP_Resize.h"
23 #define MUL_I(a, b) ({ \
31 ((a)[0] + (a)[1] + (a)[2] + (a)[3])
33 @ for pt in pixeltypes:
34 @ if not pt.is_unknown() and not pt.is_palette():
35 static int resize_cubic_{{ pt.name }}(const GP_Pixmap *src,
36 GP_Pixmap *dst, GP_ProgressCallback *callback)
38 @ for c in pt.chanslist:
39 int32_t col_{{ c.name }}[src->w];
44 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
45 src->w, src->h, dst->w, dst->h,
46 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
48 {@ fetch_gamma_tables(pt, "src") @}
50 /* pre-generate x mapping and constants */
51 int32_t xmap[dst->w][4];
52 int32_t xmap_c[dst->w][4];
54 for (i = 0; i < dst->w; i++) {
55 float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
57 xmap[i][0] = floor(x - 1);
62 xmap_c[i][0] = cubic_int((xmap[i][0] - x) * MUL + 0.5);
63 xmap_c[i][1] = cubic_int((xmap[i][1] - x) * MUL + 0.5);
64 xmap_c[i][2] = cubic_int((xmap[i][2] - x) * MUL + 0.5);
65 xmap_c[i][3] = cubic_int((xmap[i][3] - x) * MUL + 0.5);
67 xmap[i][0] = GP_MAX(xmap[i][0], 0);
68 xmap[i][2] = GP_MIN(xmap[i][2], (int)src->w - 1);
69 xmap[i][3] = GP_MIN(xmap[i][3], (int)src->w - 1);
72 /* cubic resampling */
73 for (i = 0; i < dst->h; i++) {
74 float y = (1.00 * i / (dst->h - 1)) * (src->h - 1);
83 cvy[0] = cubic_int((yi[0] - y) * MUL + 0.5);
84 cvy[1] = cubic_int((yi[1] - y) * MUL + 0.5);
85 cvy[2] = cubic_int((yi[2] - y) * MUL + 0.5);
86 cvy[3] = cubic_int((yi[3] - y) * MUL + 0.5);
88 yi[0] = GP_MAX(yi[0], 0);
89 yi[2] = GP_MIN(yi[2], (int)src->h - 1);
90 yi[3] = GP_MIN(yi[3], (int)src->h - 1);
92 /* Generate interpolated row */
93 for (j = 0; j < src->w; j++) {
94 @ for c in pt.chanslist:
95 int32_t {{ c.name }}v[4];
99 pix[0] = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, j, yi[0]);
100 pix[1] = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, j, yi[1]);
101 pix[2] = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, j, yi[2]);
102 pix[3] = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, j, yi[3]);
104 @ for c in pt.chanslist:
105 {{ c.name }}v[0] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix[0]);
106 {{ c.name }}v[1] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix[1]);
107 {{ c.name }}v[2] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix[2]);
108 {{ c.name }}v[3] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix[3]);
112 @ for c in pt.chanslist:
113 {{ c.name }}v[0] = {{ c.name }}_2_LIN[{{ c.name }}v[0]];
114 {{ c.name }}v[1] = {{ c.name }}_2_LIN[{{ c.name }}v[1]];
115 {{ c.name }}v[2] = {{ c.name }}_2_LIN[{{ c.name }}v[2]];
116 {{ c.name }}v[3] = {{ c.name }}_2_LIN[{{ c.name }}v[3]];
120 @ for c in pt.chanslist:
121 MUL_I({{ c.name }}v, cvy);
124 @ for c in pt.chanslist:
125 col_{{ c.name }}[j] = SUM_I({{ c.name }}v);
129 /* now interpolate column for new image */
130 for (j = 0; j < dst->w; j++) {
131 @ for c in pt.chanslist:
132 int32_t {{ c.name }}v[4];
133 int32_t {{ c.name }};
136 @ for c in pt.chanslist:
137 {{ c.name }}v[0] = col_{{ c.name }}[xmap[j][0]];
138 {{ c.name }}v[1] = col_{{ c.name }}[xmap[j][1]];
139 {{ c.name }}v[2] = col_{{ c.name }}[xmap[j][2]];
140 {{ c.name }}v[3] = col_{{ c.name }}[xmap[j][3]];
143 @ for c in pt.chanslist:
144 MUL_I({{ c.name }}v, xmap_c[j]);
147 @ for c in pt.chanslist:
148 {{ c.name }} = (SUM_I({{ c.name }}v) + MUL*MUL/2) / MUL / MUL;
152 @ for c in pt.chanslist:
153 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** (c[2] + 2) - 1 }});
155 @ for c in pt.chanslist:
156 {{ c.name }} = {{ c.name }}_2_GAMMA[{{ c.name }}];
159 @ for c in pt.chanslist:
160 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** c[2] - 1 }});
164 GP_Pixel pix = GP_Pixel_CREATE_{{ pt.name }}({{ arr_to_params(pt.chan_names, "(uint8_t)") }});
165 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, j, i, pix);
168 if (GP_ProgressCallbackReport(callback, i, dst->h, dst->w))
172 GP_ProgressCallbackDone(callback);
178 static int resize_cubic(const GP_Pixmap *src, GP_Pixmap *dst,
179 GP_ProgressCallback *callback)
181 switch (src->pixel_type) {
182 @ for pt in pixeltypes:
183 @ if not pt.is_unknown() and not pt.is_palette():
184 case GP_PIXEL_{{ pt.name }}:
185 return resize_cubic_{{ pt.name }}(src, dst, callback);
194 int GP_FilterResizeCubicInt(const GP_Pixmap *src, GP_Pixmap *dst,
195 GP_ProgressCallback *callback)
197 if (src->pixel_type != dst->pixel_type) {
198 GP_WARN("The src and dst pixel types must match");
203 return resize_cubic(src, dst, callback);