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>
16 #include <filters/GP_Resize.h>
21 #define MUL_I(a, b) ({ \
29 ((a)[0] + (a)[1] + (a)[2] + (a)[3])
31 @ for pt in pixeltypes:
32 @ if not pt.is_unknown() and not pt.is_palette():
33 static int resize_cubic_{{ pt.name }}(const gp_pixmap *src,
34 gp_pixmap *dst, gp_progress_cb *callback)
36 @ for c in pt.chanslist:
37 int32_t col_{{ c.name }}[src->w];
42 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
43 src->w, src->h, dst->w, dst->h,
44 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
46 {@ fetch_gamma_tables(pt, "src") @}
48 /* pre-generate x mapping and constants */
49 int32_t xmap[dst->w][4];
50 int32_t xmap_c[dst->w][4];
52 for (i = 0; i < dst->w; i++) {
53 float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
55 xmap[i][0] = floor(x - 1);
60 xmap_c[i][0] = cubic_int((xmap[i][0] - x) * MUL + 0.5);
61 xmap_c[i][1] = cubic_int((xmap[i][1] - x) * MUL + 0.5);
62 xmap_c[i][2] = cubic_int((xmap[i][2] - x) * MUL + 0.5);
63 xmap_c[i][3] = cubic_int((xmap[i][3] - x) * MUL + 0.5);
65 xmap[i][0] = GP_MAX(xmap[i][0], 0);
66 xmap[i][2] = GP_MIN(xmap[i][2], (int)src->w - 1);
67 xmap[i][3] = GP_MIN(xmap[i][3], (int)src->w - 1);
70 /* cubic resampling */
71 for (i = 0; i < dst->h; i++) {
72 float y = (1.00 * i / (dst->h - 1)) * (src->h - 1);
81 cvy[0] = cubic_int((yi[0] - y) * MUL + 0.5);
82 cvy[1] = cubic_int((yi[1] - y) * MUL + 0.5);
83 cvy[2] = cubic_int((yi[2] - y) * MUL + 0.5);
84 cvy[3] = cubic_int((yi[3] - y) * MUL + 0.5);
86 yi[0] = GP_MAX(yi[0], 0);
87 yi[2] = GP_MIN(yi[2], (int)src->h - 1);
88 yi[3] = GP_MIN(yi[3], (int)src->h - 1);
90 /* Generate interpolated row */
91 for (j = 0; j < src->w; j++) {
92 @ for c in pt.chanslist:
93 int32_t {{ c.name }}v[4];
97 pix[0] = gp_getpixel_raw_{{ pt.pixelsize.suffix }}(src, j, yi[0]);
98 pix[1] = gp_getpixel_raw_{{ pt.pixelsize.suffix }}(src, j, yi[1]);
99 pix[2] = gp_getpixel_raw_{{ pt.pixelsize.suffix }}(src, j, yi[2]);
100 pix[3] = gp_getpixel_raw_{{ pt.pixelsize.suffix }}(src, j, yi[3]);
102 @ for c in pt.chanslist:
103 {{ c.name }}v[0] = GP_PIXEL_GET_{{ c.name }}_{{ pt.name }}(pix[0]);
104 {{ c.name }}v[1] = GP_PIXEL_GET_{{ c.name }}_{{ pt.name }}(pix[1]);
105 {{ c.name }}v[2] = GP_PIXEL_GET_{{ c.name }}_{{ pt.name }}(pix[2]);
106 {{ c.name }}v[3] = GP_PIXEL_GET_{{ c.name }}_{{ pt.name }}(pix[3]);
110 @ for c in pt.chanslist:
111 {{ c.name }}v[0] = {{ c.name }}_2_LIN[{{ c.name }}v[0]];
112 {{ c.name }}v[1] = {{ c.name }}_2_LIN[{{ c.name }}v[1]];
113 {{ c.name }}v[2] = {{ c.name }}_2_LIN[{{ c.name }}v[2]];
114 {{ c.name }}v[3] = {{ c.name }}_2_LIN[{{ c.name }}v[3]];
118 @ for c in pt.chanslist:
119 MUL_I({{ c.name }}v, cvy);
122 @ for c in pt.chanslist:
123 col_{{ c.name }}[j] = SUM_I({{ c.name }}v);
127 /* now interpolate column for new image */
128 for (j = 0; j < dst->w; j++) {
129 @ for c in pt.chanslist:
130 int32_t {{ c.name }}v[4];
131 int32_t {{ c.name }};
134 @ for c in pt.chanslist:
135 {{ c.name }}v[0] = col_{{ c.name }}[xmap[j][0]];
136 {{ c.name }}v[1] = col_{{ c.name }}[xmap[j][1]];
137 {{ c.name }}v[2] = col_{{ c.name }}[xmap[j][2]];
138 {{ c.name }}v[3] = col_{{ c.name }}[xmap[j][3]];
141 @ for c in pt.chanslist:
142 MUL_I({{ c.name }}v, xmap_c[j]);
145 @ for c in pt.chanslist:
146 {{ c.name }} = (SUM_I({{ c.name }}v) + MUL*MUL/2) / MUL / MUL;
150 @ for c in pt.chanslist:
151 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** (c[2] + 2) - 1 }});
153 @ for c in pt.chanslist:
154 {{ c.name }} = {{ c.name }}_2_GAMMA[{{ c.name }}];
157 @ for c in pt.chanslist:
158 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** c[2] - 1 }});
162 gp_pixel pix = GP_PIXEL_CREATE_{{ pt.name }}({{ arr_to_params(pt.chan_names, "(uint8_t)") }});
163 gp_putpixel_raw_{{ pt.pixelsize.suffix }}(dst, j, i, pix);
166 if (gp_progress_cb_report(callback, i, dst->h, dst->w))
170 gp_progress_cb_done(callback);
176 static int resize_cubic(const gp_pixmap *src, gp_pixmap *dst,
177 gp_progress_cb *callback)
179 switch (src->pixel_type) {
180 @ for pt in pixeltypes:
181 @ if not pt.is_unknown() and not pt.is_palette():
182 case GP_PIXEL_{{ pt.name }}:
183 return resize_cubic_{{ pt.name }}(src, dst, callback);
192 int gp_filter_resize_cubic_int(const gp_pixmap *src, gp_pixmap *dst,
193 gp_progress_cb *callback)
195 if (src->pixel_type != dst->pixel_type) {
196 GP_WARN("The src and dst pixel types must match");
201 return resize_cubic(src, dst, callback);