filters/gp_filter_resize_alloc: Check w and h
[gfxprim.git] / libs / filters / GP_ResizeCubic.gen.c.t
blob6f7ce07fb6717de274d2b9e030d255ffa8419017
1 @ include source.t
2 /*
3  * Cubic resampling
4  *
5  * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz>
6  */
8 #include <errno.h>
9 #include <math.h>
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>
17 #include "GP_Cubic.h"
19 #define MUL 1024
21 #define MUL_I(a, b) ({ \
22         a[0] *= b[0]; \
23         a[1] *= b[1]; \
24         a[2] *= b[2]; \
25         a[3] *= b[3]; \
28 #define SUM_I(a) \
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];
38 @         end
40         uint32_t i, j;
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);
56                 xmap[i][1] = x;
57                 xmap[i][2] = x + 1;
58                 xmap[i][3] = x + 2;
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);
68         }
70         /* cubic resampling */
71         for (i = 0; i < dst->h; i++) {
72                 float y = (1.00 * i / (dst->h - 1)) * (src->h - 1);
73                 int32_t cvy[4];
74                 int yi[4];
76                 yi[0] = floor(y - 1);
77                 yi[1] = y;
78                 yi[2] = y + 1;
79                 yi[3] = y + 2;
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];
94 @         end
95                         gp_pixel pix[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]);
107 @         end
109                         if (src->gamma) {
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]];
115 @         end
116                         }
118 @         for c in pt.chanslist:
119                         MUL_I({{ c.name }}v, cvy);
120 @         end
122 @         for c in pt.chanslist:
123                         col_{{ c.name }}[j] = SUM_I({{ c.name }}v);
124 @         end
125                 }
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 }};
132 @         end
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]];
139 @         end
141 @         for c in pt.chanslist:
142                         MUL_I({{ c.name }}v, xmap_c[j]);
143 @         end
145 @         for c in pt.chanslist:
146                         {{ c.name }} = (SUM_I({{ c.name }}v) + MUL*MUL/2) / MUL / MUL;
147 @         end
149                         if (src->gamma) {
150 @         for c in pt.chanslist:
151                                 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** (c[2] + 2) - 1 }});
152 @         end
153 @         for c in pt.chanslist:
154                                 {{ c.name }} = {{ c.name }}_2_GAMMA[{{ c.name }}];
155 @         end
156                         } else {
157 @         for c in pt.chanslist:
158                                 {{ c.name }} = GP_CLAMP_GENERIC({{ c.name }}, 0, {{ 2 ** c[2] - 1 }});
159 @         end
160                         }
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);
164                 }
166                 if (gp_progress_cb_report(callback, i, dst->h, dst->w))
167                         return 1;
168         }
170         gp_progress_cb_done(callback);
171         return 0;
174 @ end
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);
184         break;
185 @ end
186         default:
187                 errno = EINVAL;
188                 return -1;
189         }
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");
197                 errno = EINVAL;
198                 return 1;
199         }
201         return resize_cubic(src, dst, callback);