5 * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz>
10 #include "core/GP_Pixmap.h"
11 #include "core/GP_GetPutPixel.h"
12 #include "core/GP_TempAlloc.h"
13 #include "core/GP_Clamp.h"
14 #include "core/GP_Debug.h"
16 #include "GP_Linear.h"
20 @ for pt in pixeltypes:
21 @ if not pt.is_unknown() and not pt.is_palette():
23 static int h_lin_conv_{{ pt.name }}(const GP_Pixmap *src,
24 GP_Coord x_src, GP_Coord y_src,
25 GP_Size w_src, GP_Size h_src,
27 GP_Coord x_dst, GP_Coord y_dst,
28 float kernel[], uint32_t kw, float kern_div,
29 GP_ProgressCallback *callback)
33 int ikernel[kw], ikern_div;
34 uint32_t size = w_src + kw - 1;
36 for (i = 0; i < kw; i++)
37 ikernel[i] = kernel[i] * MUL + 0.5;
39 ikern_div = kern_div * MUL + 0.5;
41 /* Create temporary buffers */
42 GP_TempAllocCreate(temp, {{ len(pt.chanslist) }} * size * sizeof(int));
44 @ for c in pt.chanslist:
45 int *{{ c.name }} = GP_TempAllocGet(temp, size * sizeof(int));
48 /* Do horizontal linear convolution */
49 for (y = 0; y < (GP_Coord)h_src; y++) {
50 int yi = GP_MIN(y_src + y, (int)src->h - 1);
52 /* Fetch the whole row */
53 GP_Pixel pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, 0, yi);
55 int xi = x_src - kw/2;
58 /* Copy border pixel until the source image starts */
59 while (xi <= 0 && i < size) {
60 @ for c in pt.chanslist:
61 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
67 /* Use as much source image pixels as possible */
68 while (xi < (int)src->w && i < size) {
69 pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xi, yi);
71 @ for c in pt.chanslist:
72 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
79 /* Copy the rest the border pixel when we are out again */
81 @ for c in pt.chanslist:
82 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
88 for (x = 0; x < (GP_Coord)w_src; x++) {
89 @ for c in pt.chanslist:
90 int32_t {{ c.name }}_sum = MUL/2;
91 int *p{{ c.name }} = {{ c.name }} + x;
94 /* count the pixel value from neighbours weighted by kernel */
95 for (i = 0; i < kw; i++) {
96 @ for c in pt.chanslist:
97 {{ c.name }}_sum += (*p{{ c.name }}++) * ikernel[i];
101 /* divide the result */
102 @ for c in pt.chanslist:
103 {{ c.name }}_sum /= ikern_div;
106 /* and clamp just to be extra sure */
107 @ for c in pt.chanslist:
108 {{ c.name }}_sum = GP_CLAMP({{ c.name }}_sum, 0, {{ c.max }});
110 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x_dst + x, y_dst + y,
111 GP_Pixel_CREATE_{{ pt.name }}(
112 {{ arr_to_params(pt.chan_names, "", "_sum") }}
116 if (GP_ProgressCallbackReport(callback, y, h_src, w_src)) {
117 GP_TempAllocFree(temp);
122 GP_TempAllocFree(temp);
124 GP_ProgressCallbackDone(callback);
130 int GP_FilterHLinearConvolution_Raw(const GP_Pixmap *src,
131 GP_Coord x_src, GP_Coord y_src,
132 GP_Size w_src, GP_Size h_src,
134 GP_Coord x_dst, GP_Coord y_dst,
135 float kernel[], uint32_t kw, float kern_div,
136 GP_ProgressCallback *callback)
138 GP_DEBUG(1, "Horizontal linear convolution kernel width %u "
139 "offset %ix%i rectangle %ux%u",
140 kw, x_src, y_src, w_src, h_src);
142 switch (src->pixel_type) {
143 @ for pt in pixeltypes:
144 @ if not pt.is_unknown() and not pt.is_palette():
145 case GP_PIXEL_{{ pt.name }}:
146 return h_lin_conv_{{ pt.name }}(src, x_src, y_src, w_src, h_src,
148 kernel, kw, kern_div, callback);
157 @ for pt in pixeltypes:
158 @ if not pt.is_unknown() and not pt.is_palette():
160 static int v_lin_conv_{{ pt.name }}(const GP_Pixmap *src,
161 GP_Coord x_src, GP_Coord y_src,
162 GP_Size w_src, GP_Size h_src,
164 GP_Coord x_dst, GP_Coord y_dst,
165 float kernel[], uint32_t kh, float kern_div,
166 GP_ProgressCallback *callback)
170 int ikernel[kh], ikern_div;
171 uint32_t size = h_src + kh - 1;
173 for (i = 0; i < kh; i++)
174 ikernel[i] = kernel[i] * MUL + 0.5;
176 ikern_div = kern_div * MUL + 0.5;
178 /* Create temporary buffers */
179 GP_TempAllocCreate(temp, {{ len(pt.chanslist) }} * size * sizeof(int));
181 @ for c in pt.chanslist:
182 int *{{ c.name }} = GP_TempAllocGet(temp, size * sizeof(int));
185 /* Do vertical linear convolution */
186 for (x = 0; x < (GP_Coord)w_src; x++) {
187 int xi = GP_MIN(x_src + x, (int)src->w - 1);
189 /* Fetch the whole row */
190 GP_Pixel pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xi, 0);
192 int yi = y_src - kh/2;
195 /* Copy border pixel until the source image starts */
196 while (yi <= 0 && i < size) {
197 @ for c in pt.chanslist:
198 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
205 /* Use as much source image pixels as possible */
206 while (yi < (int)src->h && i < size) {
207 pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xi, yi);
209 @ for c in pt.chanslist:
210 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
217 /* Copy the rest the border pixel when we are out again */
219 @ for c in pt.chanslist:
220 {{ c.name }}[i] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
226 for (y = 0; y < (GP_Coord)h_src; y++) {
227 @ for c in pt.chanslist:
228 int32_t {{ c.name }}_sum = MUL/2;
229 int *p{{ c.name }} = {{ c.name }} + y;
232 /* count the pixel value from neighbours weighted by kernel */
233 for (i = 0; i < kh; i++) {
234 @ for c in pt.chanslist:
235 {{ c.name }}_sum += (*p{{ c.name }}++) * ikernel[i];
239 /* divide the result */
240 @ for c in pt.chanslist:
241 {{ c.name }}_sum /= ikern_div;
244 /* and clamp just to be extra sure */
245 @ for c in pt.chanslist:
246 {{ c.name }}_sum = GP_CLAMP({{ c.name }}_sum, 0, {{ c.max }});
249 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x_dst + x, y_dst + y,
250 GP_Pixel_CREATE_{{ pt.name }}(
251 {{ arr_to_params(pt.chan_names, "", "_sum") }}
255 if (GP_ProgressCallbackReport(callback, x, w_src, h_src)) {
256 GP_TempAllocFree(temp);
261 GP_TempAllocFree(temp);
263 GP_ProgressCallbackDone(callback);
269 int GP_FilterVLinearConvolution_Raw(const GP_Pixmap *src,
270 GP_Coord x_src, GP_Coord y_src,
271 GP_Size w_src, GP_Size h_src,
273 GP_Coord x_dst, GP_Coord y_dst,
274 float kernel[], uint32_t kh, float kern_div,
275 GP_ProgressCallback *callback)
277 GP_DEBUG(1, "Vertical linear convolution kernel width %u "
278 "offset %ix%i rectangle %ux%u",
279 kh, x_src, y_src, w_src, h_src);
281 switch (src->pixel_type) {
282 @ for pt in pixeltypes:
283 @ if not pt.is_unknown() and not pt.is_palette():
284 case GP_PIXEL_{{ pt.name }}:
285 return v_lin_conv_{{ pt.name }}(src, x_src, y_src, w_src, h_src,
287 kernel, kh, kern_div, callback);
296 @ for pt in pixeltypes:
297 @ if not pt.is_unknown() and not pt.is_palette():
299 static int lin_conv_{{ pt.name }}(const GP_Pixmap *src,
300 GP_Coord x_src, GP_Coord y_src,
301 GP_Size w_src, GP_Size h_src,
303 GP_Coord x_dst, GP_Coord y_dst,
304 float kernel[], uint32_t kw, uint32_t kh,
305 float kern_div, GP_ProgressCallback *callback)
310 /* Do linear convolution */
311 for (y = 0; y < (GP_Coord)h_src; y++) {
312 @ for c in pt.chanslist:
313 uint32_t {{ c.name }}[kw][kh];
317 /* Prefill the buffer on the start */
318 for (j = 0; j < kh; j++) {
319 for (i = 0; i < kw - 1; i++) {
320 int xi = x_src + i - kw/2;
321 int yi = y_src + y + j - kh/2;
323 xi = GP_CLAMP(xi, 0, (int)src->w - 1);
324 yi = GP_CLAMP(yi, 0, (int)src->h - 1);
326 pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xi, yi);
328 @ for c in pt.chanslist:
329 {{ c.name }}[i][j] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
336 for (x = 0; x < (GP_Coord)w_src; x++) {
337 @ for c in pt.chanslist:
338 float {{ c.name }}_sum = 0;
341 for (j = 0; j < kh; j++) {
342 int xi = x_src + x + kw/2;
343 int yi = y_src + y + j - kh/2;
345 xi = GP_CLAMP(xi, 0, (int)src->w - 1);
346 yi = GP_CLAMP(yi, 0, (int)src->h - 1);
348 pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xi, yi);
350 @ for c in pt.chanslist:
351 {{ c.name }}[idx][j] = GP_Pixel_GET_{{ c.name }}_{{ pt.name }}(pix);
355 /* Count the pixel value from neighbours weighted by kernel */
356 for (i = 0; i < kw; i++) {
359 if ((int)i < idx + 1)
360 k = kw - idx - 1 + i;
364 for (j = 0; j < kh; j++) {
365 @ for c in pt.chanslist:
366 {{ c.name }}_sum += {{ c.name }}[i][j] * kernel[k + j * kw];
371 /* divide the result */
372 @ for c in pt.chanslist:
373 {{ c.name }}_sum /= kern_div;
376 /* and clamp just to be extra sure */
377 @ for c in pt.chanslist:
378 int {{ c.name }}_res = GP_CLAMP((int){{ c.name }}_sum, 0, {{ c.max }});
381 pix = GP_Pixel_CREATE_{{ pt.name }}({{ arr_to_params(pt.chan_names, "", "_res") }});
383 GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x_dst + x, y_dst + y, pix);
391 if (GP_ProgressCallbackReport(callback, y, h_src, w_src))
395 GP_ProgressCallbackDone(callback);
401 int GP_FilterLinearConvolution_Raw(const GP_Pixmap *src,
402 GP_Coord x_src, GP_Coord y_src,
403 GP_Size w_src, GP_Size h_src,
405 GP_Coord x_dst, GP_Coord y_dst,
406 float kernel[], uint32_t kw, uint32_t kh,
407 float kern_div, GP_ProgressCallback *callback)
409 GP_DEBUG(1, "Linear convolution kernel %ix%i rectangle %ux%u",
410 kw, kh, w_src, h_src);
412 switch (src->pixel_type) {
413 @ for pt in pixeltypes:
414 @ if not pt.is_unknown() and not pt.is_palette():
415 case GP_PIXEL_{{ pt.name }}:
416 return lin_conv_{{ pt.name }}(src, x_src, y_src, w_src, h_src,
418 kernel, kw, kh, kern_div, callback);