doc: Update filters.txt doc.
[gfxprim.git] / doc / filters.txt
blob9d4228ed5bf12ae96fa71295b57810387c59fad5
1 Context filters
2 ---------------
4 Pixel filters for 'GP_Context'.
6 The context filter is basically a function that operates on context pixels.
7 The result may be stored into a new bitmap or placed to bitmap passed as
8 argument or, in some cases, the filter could be used 'in place' so the result
9 is stored into the same context as the one passed as filter source.
11 Common filter API
12 ~~~~~~~~~~~~~~~~~
14 For convenience, the filters API is unified:
16 * There are two functions for each filter
17   - first one takes destination as an argument
18   - second one allocates the destination and returns pointer to it
19 * First argument(s) are always source(s)
20 * Then, in case of second variant, destination
21 * Other parameters follow
22 * And the last argument is progress callback
24 When using allocating version of the filter, pointer to the newly allocated
25 context is returned, or in case of failure 'NULL' is returned.
27 If 'malloc()' has failed 'NULL' is returned.
29 If filter has been interrupted by a callback, all allocated memory is freed,
30 and 'NULL' is returned.
32 When using non-allocating variant of the filter, the destination context must
33 have correct pixel type and the size must be big enough to store the result.
34 The return value from such filter is either zero, in case of success, or
35 non-zero when filter was interrupted by a callback.
37 For filters that work 'in-place' (which is explicitly said for each filter)
38 the source and the destination could be the same context. Note that this is
39 not expected to work if you do several overlapping sub-contexts and pass these
40 as arguments.
42 [source,c]
43 -------------------------------------------------------------------------------
45  * Filter common API.
46  */
47 int GP_FilterFoo(const GP_Context *src, GP_Context *dst,
48                  foo params ...,
49                  GP_ProgressCallback *callback);
51 GP_Context *GP_FilterFooAlloc(const GP_Context *src,
52                               foo params ...,
53                               GP_ProgressCallback *callback);
54 -------------------------------------------------------------------------------
57 Filters also exists in _Raw variant whose interface is similar to the first
58 type of filter function. These filter APIs are used for internal
59 implementation and shouldn't be called by user as the destination is expected
60 to be crafted exactly for storing the filter result and there are 'NO' sanity
61 checks in place.
63 'You could use these at your own risk'
65 [source,c]
66 -------------------------------------------------------------------------------
68  * Raw filter common API.
69  */
70 int GP_FilterFoo_Raw(const GP_Context *src, GP_Context *dst,
71                      foo params ...,
72                      GP_ProgressCallback *callback);
73 -------------------------------------------------------------------------------
75 Filter Parameters
76 ~~~~~~~~~~~~~~~~~
78 In order to pass, per-channel, filter parameters to a filter, structure called
79 GP_FilterParams was created.
81 [source,c]
82 -------------------------------------------------------------------------------
83 #include <GP.h>
84 /* or */
85 #include <filters/GP_FilterParam.h>
87 typedef union GP_FilterParamVal {
88         float f;
89         uint32_t ui;
90         int32_t i;
91         void *ptr;
92 } GP_FilterParamVal;
94 typedef struct GP_FilterParam {
95         char channel_name[2];
96         union GP_FilterParamVal val;
97 } GP_FilterParam;
98 -------------------------------------------------------------------------------
100 Some filters do take an empty channel_name terminated (empty channel_name is
101 empty string i.e. "\0") array of GP_FilterParam, which is used to describe
102 per-channel parameters.
105 There are two methods how to construct GP_FilterParam structure. First one is
106 to use macro that expands to a code which declares and initializes the array on
107 the stack second uses memory allocated by a malloc(). In both cases the
108 structure is has initialized channel names and terminator.
110 [source,c]
111 -------------------------------------------------------------------------------
112 #include <GP.h>
113 /* or */
114 #include <filters/GP_FilterParam.h>
116 #define GP_FILTER_PARAMS(pixel_type, name) \
117         GP_FilterParam name[GP_PixelTypes[pixel_type].numchannels + 1]; \
118         GP_FilterParamInitChannels(name, pixel_type);
119 -------------------------------------------------------------------------------
121 Macro that declares and initializes GP_FilterParam structure for a given
122 pixel_type.
124 [source,c]
125 -------------------------------------------------------------------------------
126 #include <GP.h>
127 /* or */
128 #include <filters/GP_FilterParam.h>
130 GP_FilterParam *GP_FilterParamCreate(GP_PixelType pixel_type);
132 void GP_FilterParamDestroy(GP_FilterParam *self);
133 -------------------------------------------------------------------------------
135 Second possible way allocates memory using malloc().
137 Functions for manipulating and querying existing GP_FilterParam follows.
139 [source,c]
140 -------------------------------------------------------------------------------
141 #include <GP.h>
142 /* or */
143 #include <filters/GP_FilterParam.h>
145 void GP_FilterParamInitChannels(GP_FilterParam params[],
146                                 GP_PixelType pixel_type);
147 -------------------------------------------------------------------------------
149 Initializes filter param array channel names (accordingly to pixel type) and
150 terminator. The params array must be large enough to hold number of pixel type
151 channels plus one.
153 [source,c]
154 -------------------------------------------------------------------------------
155 #include <GP.h>
156 /* or */
157 #include <filters/GP_FilterParam.h>
159 GP_FilterParam *GP_FilterParamChannel(GP_FilterParam params[],
160                                       const char *channel_name);
161 -------------------------------------------------------------------------------
163 Does lookup for a given channel name and returns, if found, corresponding
164 GP_FilterParam, otherwise 'NULL' is returned.
166 This function is primary used in filters, where filter, at the start, resolves
167 all it's parameters.
169 [source,c]
170 -------------------------------------------------------------------------------
171 #include <GP.h>
172 /* or */
173 #include <filters/GP_FilterParam.h>
175 int GP_FilterParamCheckPixelType(GP_FilterParam params[],
176                                  GP_PixelType pixel_type);
177 -------------------------------------------------------------------------------
179 Matches param structure against pixel_type. Returns zero if params describes
180 exactly same channels like pixel_type, non-zero otherwise.
182 [source,c]
183 -------------------------------------------------------------------------------
184 #include <GP.h>
185 /* or */
186 #include <filters/GP_FilterParam.h>
188 void GP_FilterParamSetIntAll(GP_FilterParam params[], int32_t val);
190 int GP_FilterParamSetInt(GP_FilterParam params[], const char *channel_name,
191                          int32_t val);
193 void GP_FilterParamSetFloatAll(GP_FilterParam params[], float val);
195 int GP_FilterParamSetFloat(GP_FilterParam params[], const char *channel_name,
196                            float val);
198 void GP_FilterParamSetUIntAll(GP_FilterParam params[], uint32_t val);
200 int GP_FilterParamSetUInt(GP_FilterParam params[], const char *channel_name,
201                           uint32_t val);
203 void GP_FilterParamSetPtrAll(GP_FilterParam params[], void *ptr);
205 int GP_FilterParamSetPtr(GP_FilterParam params[], const char *channel_name,
206                          void *ptr);
208 void GP_FilterParamFreePtrAll(GP_FilterParam params[]);
209 -------------------------------------------------------------------------------
211 Parameter setters. Those that sets individual value returns zero on success
212 (i.e. channel was found) and non-zero otherwise.
214 The last one calls free() on all param pointers, which is used to free
215 allocate memory.
217 Point operation filters
218 ~~~~~~~~~~~~~~~~~~~~~~~
220 Point operations are filters that works with pixels as with independent values
221 (the value of destination pixel depends only on the pixel on the same
222 coordinates in source image). All of these filters works 'in-place' and the
223 result has always the same size as the source.
225 [source,c]
226 -------------------------------------------------------------------------------
227 #include <GP_Filters.h>
229 GP_Context *GP_FilterBrightness(const GP_Context *src, GP_Context *dst,
230                                 int32_t inc, GP_ProgressCallback *callback);
231 -------------------------------------------------------------------------------
233 Brightness filter, increments all pixel channels by a fixed value.
235 [source,c]
236 -------------------------------------------------------------------------------
237 #include <GP_Filters.h>
239 GP_Context *GP_FilterContrast(const GP_Context *src, GP_Context *dst, 
240                               float mul, GP_ProgressCallback *callback);
241 -------------------------------------------------------------------------------
243 Contrast filter, multiplies all pixel channels by a fixed value.
245 [source,c]
246 -------------------------------------------------------------------------------
247 #include <GP_Filters.h>
249 GP_Context *GP_FilterInvert(const GP_Context *src, GP_Context *dst,
250                             GP_ProgressCallback *callback);
251 -------------------------------------------------------------------------------
253 Inverts the image, for each channel the result value is computed as "chan_max
254 - val".
256 Arithmetic filters
257 ~~~~~~~~~~~~~~~~~~
259 Arithmetic filters do take two contexts as an input and combines them into one
260 output context.
262 The pixel type of both input contexts must match.
264 If size of the input contexts differs, minimum is used.
266 [source,c]
267 -------------------------------------------------------------------------------
268 #include <filters/GP_Arithmetic.h>
269 /* or */
270 #include <GP.h>
272 int GP_FilterAddition(const GP_Context *src_a,
273                       const GP_Context *src_b,
274                       GP_Context *dst,
275                       GP_ProgressCallback *callback);
277 GP_Context *GP_FilterAdditionAlloc(const GP_Context *src_a,
278                                    const GP_Context *src_b,
279                                    GP_ProgressCallback *callback);
280 -------------------------------------------------------------------------------
282 Produces saturated (clamped) addition of two contexts.
284 [source,c]
285 -------------------------------------------------------------------------------
286 #include <filters/GP_Arithmetic.h>
287 /* or */
288 #include <GP.h>
290 int GP_FilterMultiply(const GP_Context *src_a,
291                       const GP_Context *src_b,
292                       GP_Context *dst,
293                       GP_ProgressCallback *callback);
295 GP_Context *GP_FilterMultiplyAlloc(const GP_Context *src_a,
296                                    const GP_Context *src_b,
297                                    GP_ProgressCallback *callback);
298 -------------------------------------------------------------------------------
300 Produces saturated (clamped) multiplication of two contexts.
302 [source,c]
303 -------------------------------------------------------------------------------
304 #include <filters/GP_Arigthmetic.h>
305 /* or */
306 #include <GP.h>
308 int GP_FilterDifference(const GP_Context *src_a,
309                         const GP_Context *src_b,
310                         GP_Context *dst,
311                         GP_ProgressCallback *callback);
313 GP_Context *GP_FilterDifferenceAlloc(const GP_Context *src_a,
314                                      const GP_Context *src_b,
315                                      GP_ProgressCallback *callback);
317 -------------------------------------------------------------------------------
319 Produces symmetric difference (i.e. abs(a - b)).
321 [source,c]
322 -------------------------------------------------------------------------------
323 #include <filters/GP_Arigthmetic.h>
324 /* or */
325 #include <GP.h>
327 int GP_FilterMax(const GP_Context *src_a,
328                  const GP_Context *src_b,
329                  GP_Context *dst,
330                  GP_ProgressCallback *callback);
332 GP_Context *GP_FilterMaxAlloc(const GP_Context *src_a,
333                               const GP_Context *src_b,
334                               GP_ProgressCallback *callback);
336 int GP_FilterMin(const GP_Context *src_a,
337                  const GP_Context *src_b,
338                  GP_Context *dst,
339                  GP_ProgressCallback *callback);
341 GP_Context *GP_FilterMinAlloc(const GP_Context *src_a,
342                               const GP_Context *src_b,
343                               GP_ProgressCallback *callback);
344 -------------------------------------------------------------------------------
346 Maximum and minimum filter.
348 Rotation and Symmetry filters
349 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
351 [source,c]
352 -------------------------------------------------------------------------------
353 #include <filters/GP_Rotate.h>
354 /* or */
355 #include <GP.h>
357 int GP_FilterMirrorH(const GP_Context *src, GP_Context *dst,
358                      GP_ProgressCallback *callback);
360 GP_Context *GP_FilterMirrorH_Alloc(const GP_Context *src,
361                                    GP_ProgressCallback *callback);
362 -------------------------------------------------------------------------------
364 Mirrors context horizontally.
366 Works 'in-place'.
368 The destination has to have the same pixel type and the size must be at least
369 as large as source.
371 [source,c]
372 -------------------------------------------------------------------------------
373 #include <filters/GP_Rotate.h>
374 /* or */
375 #include <GP.h>
377 int GP_FilterMirrorV(const GP_Context *src, GP_Context *dst,
378                      GP_ProgressCallback *callback);
380 GP_Context *GP_FilterMirrorV_Alloc(const GP_Context *src,
381                                    GP_ProgressCallback *callback);
382 -------------------------------------------------------------------------------
384 Mirrors context vertically.
386 Works 'in-place'.
388 The destination has to have the same pixel type and the size must be at least
389 as large as source.
391 [source,c]
392 -------------------------------------------------------------------------------
393 #include <filters/GP_Rotate.h>
394 /* or */
395 #include <GP.h>
397 int GP_FilterRotate90(const GP_Context *src, GP_Context *dst,
398                       GP_ProgressCallback *callback);
400 GP_Context *GP_FilterRotate90_Alloc(const GP_Context *src,
401                                     GP_ProgressCallback *callback);
402 -------------------------------------------------------------------------------
404 Rotate context by 90 degrees.
406 Doesn't work 'in-place' (yet).
408 The destination has to have the same pixel type and size must be large enough to
409 fit rotated context (i.e. W and H are swapped).
411 [source,c]
412 -------------------------------------------------------------------------------
413 #include <filters/GP_Rotate.h>
414 /* or */
415 #include <GP.h>
417 int GP_FilterRotate180(const GP_Context *src, GP_Context *dst,
418                        GP_ProgressCallback *callback);
420 GP_Context *GP_FilterRotate180_Alloc(const GP_Context *src,
421                                      GP_ProgressCallback *callback);
422 -------------------------------------------------------------------------------
424 Rotate context by 180 degrees.
426 Doesn't work 'in-place' (yet).
428 The destination has to have the same pixel type and the size must be at least
429 as large as source.
431 [source,c]
432 -------------------------------------------------------------------------------
433 #include <filters/GP_Rotate.h>
434 /* or */
435 #include <GP.h>
437 int GP_FilterRotate270(const GP_Context *src, GP_Context *dst,
438                        GP_ProgressCallback *callback);
440 GP_Context *GP_FilterRotate270_Alloc(const GP_Context *src,
441                                      GP_ProgressCallback *callback);
442 -------------------------------------------------------------------------------
444 Rotate context by 270 degrees.
446 Doesn't work 'in-place' (yet).
448 The destination has to have the same pixel type and destination size must be
449 large enough to fit rotated context (i.e. W and H are swapped).
451 [source,c]
452 -------------------------------------------------------------------------------
453 #include <filters/GP_Rotate.h>
454 /* or */
455 #include <GP.h>
457 typedef enum GP_FilterSymmetries {
458         GP_ROTATE_90,
459         GP_ROTATE_CW = GP_ROTATE_90,
460         GP_ROTATE_180,
461         GP_ROTATE_270,
462         GP_ROTATE_CCW = GP_ROTATE_270,
463         GP_MIRROR_H,
464         GP_MIRROR_V,
465 } GP_FilterSymmetries;
467 GP_Context *GP_FilterSymmetry(const GP_Context *src,
468                               GP_FilterSymmetries symmetry,
469                               GP_ProgressCallback *callback);
471 int GP_FilterSymmetry(const GP_Context *src, GP_Context *dst,
472                       GP_FilterSymmetries symmetry,
473                       GP_ProgressCallback *callback);
474 -------------------------------------------------------------------------------
476 Catch all function for symmetry filters.
479 Linear filters
480 ~~~~~~~~~~~~~~
482 Linear filters family consists of filters based on discrete linear
483 convolution, that means that computed pixel value depends on linear
484 combination of the image pixels.
486 It's defined as:
487 [latex, discrete_linear_convolution.png, 140]
488 -------------------------------------------------------------------------------
490 O(x,y)=\sum_{i=-\infty}^{\infty}\sum_{j=-\infty}^{\infty}I(x+i,y+j) \cdot K(i,j)
492 -------------------------------------------------------------------------------
494 The K denotes convolution kernel and in practice, due to computational
495 complexity, the i and j are bounded in relatively small intervals. For example
496 i and j are in (-1,1) and the kernel size is 3x3.
498 Note that pixel values outside the image are undefined. The linear convolution
499 in GFXprim simply uses the closest border pixel values for all pixels outside
500 the image.
502 Particular convolution kernel is called separable if it could be decomposed
503 into two one dimensional kernels (these when combined yields back the original
504 kernel). Such convolution then could be applied as two one dimensional
505 convolutions which is faster operation (especially for big kernels).
507 Generic Linear Convolution
508 ^^^^^^^^^^^^^^^^^^^^^^^^^^
510 Following paragraph describes linear convolution implementation as well as a
511 little of the math background skip it if you just need to use one of the
512 ready-to-use filters.
514 [source,c]
515 -------------------------------------------------------------------------------
516 #include <filters/GP_Linear.h>
517 /* or */
518 #include <GP.h>
520 int GP_FilterLinearConvolution_Raw(const GP_Context *src,
521                                    GP_Coord x_src, GP_Coord y_src,
522                                    GP_Size w_src, GP_Size h_src,
523                                    GP_Context *dst,
524                                    GP_Coord x_dst, GP_Coord y_dst,
525                                    float kernel[], uint32_t kw, uint32_t kh,
526                                    float kern_div, GP_ProgressCallback *callback);
527 -------------------------------------------------------------------------------
529 Internal generic convolution filter, this is a base for all linear convolution
530 filters with non-separable kernel.
532 The src coordinate and sizes denotes rectangle in the source context that the
533 filter operates on.
535 The dst coordinates defines offset into the dst context.
537 The kernel is two-dimensional array of a size kw * kh indexed as
538 kernel[x + y*kw]. 
540 The kern_div is a coeficient that is used to divide the resuting values often
541 used to normalize the result.
543 This filter works 'in-place'.
545 The pixel value is computed as:
546 [latex, discrete_linear_convolution_alg1.png, 140]
547 -------------------------------------------------------------------------------
549 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}\sum_{j=0}^{kh - 1}
550        I(x + i - \lfloor kw/2 \rfloor, y + j - \lfloor kh/2 \rfloor)
551        \cdot kernel(i,j)
553 -------------------------------------------------------------------------------
555 Which is the same as:
557 [latex, discrete_linear_convolution_alg2.png, 140]
558 -------------------------------------------------------------------------------
560 O(x,y)={1 \over kern\_div} \cdot
561        \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
562        \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
563        I(x + i, y + j)
564        \cdot kernel(i + \lfloor kw/2 \rfloor, j + \lfloor kh/2 \rfloor)
566 -------------------------------------------------------------------------------
568 NOTE: The number of kernel rows and columns is expected to be odd number.
570 [source,c]
571 -------------------------------------------------------------------------------
572 #include <filters/GP_Linear.h>
573 /* or */
574 #include <GP.h>
576 int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
577                                     GP_Coord x_src, GP_Coord y_src,
578                                     GP_Size w_src, GP_Size h_src,
579                                     GP_Context *dst,
580                                     GP_Coord x_dst, GP_Coord y_dst,
581                                     float kernel[], uint32_t kw, float kern_div,
582                                     GP_ProgressCallback *callback);
584 int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
585                                     GP_Coord x_src, GP_Coord y_src,
586                                     GP_Size w_src, GP_Size h_src,
587                                     GP_Context *dst,
588                                     GP_Coord x_dst, GP_Coord y_dst,
589                                     float kernel[], uint32_t kh, float kern_div,
590                                     GP_ProgressCallback *callback);
592 int GP_FilterVHLinearConvolution_Raw(const GP_Context *src,
593                                      GP_Coord x_src, GP_Coord y_src,
594                                      GP_Size w_src, GP_Size h_src,
595                                      GP_Context *dst,
596                                      GP_Coord x_dst, GP_Coord y_dst,
597                                      float hkernel[], uint32_t kw, float hkern_div,
598                                      float vkernel[], uint32_t kh, float vkern_div,
599                                      GP_ProgressCallback *callback);
601 void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div);
602 -------------------------------------------------------------------------------
604 Internal special functions for one dimensional vertical and horizontal
605 convolution these two functions are base for all separable convolution filters.
607 The src coordinate and sizes denotes rectangle in the source context that the
608 filter operates on.
610 The dst coordinates are offset into the dst.
612 The kernel is one-dimensional array of floats of size kw or kh.
614 The kern_div is a coeficient that is used to divide the resuting values. 
616 The last function does both vertical and horizontal convolution and takes care
617 of correct progress callback.
619 These filters work 'in-place'.
621 The pixel value is computed as:
622 [latex, discrete_linear_1D_convolution_alg1.png, 140]
623 -------------------------------------------------------------------------------
625 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}
626        I(x + i - \lfloor kw/2 \rfloor, y)
627        \cdot kernel(i)
631 O(x,y)={1 \over kern\_div} \cdot \sum_{j=0}^{kw - 1}
632        I(x, y + j - \lfloor kh/2 \rfloor)
633        \cdot kernel(j)
635 -------------------------------------------------------------------------------
637 Which is the same as:
639 [latex, discrete_linear_1D_convolution_alg2.png, 140]
640 -------------------------------------------------------------------------------
642 O(x,y)={1 \over kern\_div} \cdot
643        \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
644        I(x + i, y)
645        \cdot kernel(i + \lfloor kw/2 \rfloor)
649 O(x,y)={1 \over kern\_div} \cdot
650        \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
651        I(x, y + j)
652        \cdot kernel(i, j + \lfloor kh/2 \rfloor)
654 -------------------------------------------------------------------------------
656 NOTE: The number of kernel rows and columns is expected to be odd number.
658 NOTE: The linear convolutions are internally implemented using integer
659       arithmetics, which works fine, but you need to take a care not to
660       overflow 32bit signed integer. If the pixel channel size is 8bit
661       long and 10bits are used for the fixed point part of the number 
662       the rest must fit into about 10 bits to be safe.
664 [source,c]
665 -------------------------------------------------------------------------------
666 #include <filters/GP_Convolution.h>
667 /* or */
668 #include <GP.h>
670 typedef struct GP_FilterKernel2D {
671         unsigned int w;
672         unsigned int h;
673         float div;
674         float *kernel;
675 } GP_FilterKernel2D;
677 int GP_FilterConvolutionEx(const GP_Context *src,
678                            GP_Coord x_src, GP_Coord y_src,
679                            GP_Size w_src, GP_Coord h_src,
680                            GP_Context *dst,
681                            GP_Coord x_dst, GP_Coord y_dst,
682                            const GP_FilterKernel2D *kernel,
683                            GP_ProgressCallback *callback);
685 GP_Context *GP_FilterConvolutionExAlloc(const GP_Context *src,
686                                         GP_Coord x_src, GP_Coord y_src,
687                                         GP_Size w_src, GP_Size h_src,
688                                         const GP_FilterKernel2D *kernel,
689                                         GP_ProgressCallback *callback);
691 int GP_FilterConvolution(const GP_Context *src, GP_Context *dst,
692                          const GP_FilterKernel2D *kernel,
693                          GP_ProgressCallback *callback);
695 GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src,
696                                 const GP_FilterKernel2D *kernel,
697                                 GP_ProgressCallback *callback);
699 void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel);
700 -------------------------------------------------------------------------------
702 Linear convolution filters, you should prefferably use this API over the _Raw
703 variants.
705 The Ex variants takes a rectangle on which the filter should operate as well
706 as offset into the destination. The destination must be large enough so that
707 starting with offset there is at least w_dst and h_dst pixels.
709 The kernel is a pointer to a structure initalized with the kernel size, divider
710 and array of kernel values.
712 The last function prints convolution kernel in human-readable format into the
713 stdout.
715 [source,c]
716 -------------------------------------------------------------------------------
717 #include <GP.h>
720  * Example box smoothing filter.
721  */
722 static void box_smoothing(GP_Context *img)
724         float box_filter[] = {
725                 1, 1, 1,
726                 1, 1, 1,
727                 1, 1, 1,
728         };
730         GP_FilterKernel2D box_kernel = {
731                 .w = 3,
732                 .h = 3,
733                 .div = 9,
734                 .kernel = box_filter,
735         };
737         GP_FilterConvolution(img, img, &box_kernel, NULL);
739 -------------------------------------------------------------------------------
741 Example function that implements simple 'in-place' smoothing filter.
743 Laplace Filter
744 ^^^^^^^^^^^^^^
746 [source,c]
747 -------------------------------------------------------------------------------
748 #include <GP_Filters.h>
749 /* or */
750 #include <GP.h>
752 int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
753                      GP_ProgressCallback *callback);
755 GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src,
756                                   GP_ProgressCallback *callback);
757 -------------------------------------------------------------------------------
759 Discrete Laplace filter that produces a second derivative of the original
760 image.
762 The convolution kernel is defined as:
764 [latex, laplacian_kernel.png, 130]
765 -------------------------------------------------------------------------------
767 \begin{bmatrix}
768 0  &  1  &  0 \\
769 0  & -2  &  0 \\
770 0  &  1  &  0
771 \end{bmatrix}
773 \begin{bmatrix}
774 0  &  0  &  0 \\
775 1  & -2  &  1 \\
776 0  &  0  &  0 
777 \end{bmatrix}
779 \begin{bmatrix}
780 0  &  1  &  0 \\
781 1  & -4  &  1 \\
782 0  &  1  &  0
783 \end{bmatrix}
785 -------------------------------------------------------------------------------
787 NOTE: This filter is not separable but could be written as a sum of two one
788       dimensional filters as the kernel definition suggests.
790 Laplacian Edge Sharpening
791 ^^^^^^^^^^^^^^^^^^^^^^^^^
793 [source,c]
794 -------------------------------------------------------------------------------
795 #include <GP_Filters.h>
796 /* or */
797 #include <GP.h>
799 int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst,
800                             float w, GP_ProgressCallback *callback);
802 GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
803                                          GP_ProgressCallback *callback);
804 -------------------------------------------------------------------------------
806 Laplace based edge sharpening filter, subtracts weighted second derivative
807 from the original image.
809 [latex, laplacian_edge_sharpening.png, 140]
810 -------------------------------------------------------------------------------
812 O(x,y) = I(x,y) - w * I''(x,y)
814 -------------------------------------------------------------------------------
816 .Original Image; Edge Sharpening w=0.1, w=0.3, w=0.5
817 image:images/dither/lenna_small.png[
818         "Original Image", 
819         link="images/dither/lenna.png"]
820 image:images/edge_sharpening/lenna_small_w_0_1.png[
821         "Edge Sharpening w=0.1", 
822         link="images/edge_sharpening/lenna_w_0_1.png"]
823 image:images/edge_sharpening/lenna_small_w_0_3.png[
824         "Edge Sharpening w=0.5", 
825         link="images/edge_sharpening/lenna_w_0_3.png"]
826 image:images/edge_sharpening/lenna_small_w_0_5.png[
827         "Edge Sharpening w=0.5", 
828         link="images/edge_sharpening/lenna_w_0_5.png"]
830 Gaussian Blur
831 ^^^^^^^^^^^^^
833 [source,c]
834 -------------------------------------------------------------------------------
835 #include <GP_Filters.h>
837 GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
838                                   float sigma_x, float sigma_y,
839                                   GP_ProgressCallback *callback);
840 -------------------------------------------------------------------------------
842 Gaussian blur filter.
844 Works 'in-place'.
846 'TODO:' this filter is implemented for RGB888 only.
849 Interpolation filters
850 ~~~~~~~~~~~~~~~~~~~~~
852 [source,c]
853 -------------------------------------------------------------------------------
854 #include <GP_Filters.h>
856 typedef enum GP_InterpolationType {
857         GP_INTERP_NN,    /* Nearest Neighbour */
858         GP_INTERP_CUBIC, /* Bicubic           */
859 } GP_InterpolationType;
861 GP_Context *GP_FilterResize(const GP_Context *src, GP_Context *dst,
862                             GP_InterpolationType type,
863                             GP_Size w, GP_Size h,
864                             GP_ProgressCallback *callback);
865 -------------------------------------------------------------------------------
867 Interpolate (resize) the context.
869 Doesn't work 'in-place' (this is quite impossible as the size of the bitmap is
870 changed by the filter).
872 If the filter destination is non 'NULL' and the 'w' and 'h' is smaller than the
873 destination size the source image is interpolated into sub-context of
874 destination defined by 'w' and 'h'.
876 'TODO:' this filter is implemented for RGB888 only.
878 Nearest Neighbour Interpolation
879 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
881 Fast, but produces "pixelated" images. May however work better for images with
882 sharp edges mostly consisting of big one color regions (it doesn't blur the
883 result on upscaling).
885 Bicubic Interpolation
886 ^^^^^^^^^^^^^^^^^^^^^
888 Works well as is on image upscaling. To get decent result on downscaling
889 low-pass filter (Gaussian blur) must be used on original image before actual
890 downscaling. To do this reasonably fast we could cheat a little: first resize
891 big images a little without the low-pass filter, then apply low-pass filter and
892 finally downscale it to desired size.
894 Dithering
895 ~~~~~~~~~
897 Currently there are two dithering algorithms implemented. Both takes an RGB888
898 24bit image as input and are able to produce any RGB or Grayscale image.
899 This filters doesn't work 'in-place' as the result has different pixel type.
901 Floyd-Steinberg
902 ^^^^^^^^^^^^^^^
904 Classical Floyd-Steinberg. Produces good results and is a little faster than
905 the Hilbert-Peano dithering.
907 The error is distributed to neighbor pixels as follows:
909 [width="10%"]
910 |===================
911 |      |   X  | 7/16
912 | 3/16 | 5/16 | 1/16
913 |===================
915 And is throwed away at the image borders.
917 [source,c]
918 -------------------------------------------------------------------------------
919 #include <GP_Filters.h>
921 int GP_FilterFloydSteinberg_RGB888(const GP_Context *src,
922                                    GP_Context *dst,
923                                    GP_ProgressCallback *callback);
924 -------------------------------------------------------------------------------
926 Renders Floyd Steinberg dithering directly into passed context. The
927 destination must be at least as large as source. 
929 If operation was aborted by a callback, non-zero is returned.
931 [source,c]
932 -------------------------------------------------------------------------------
933 #include <GP_Filters.h>
935 GP_Context *GP_FilterFloydSteinberg_RGB888_Alloc(const GP_Context *src,
936                                                  GP_PixelType pixel_type,
937                                                  GP_ProgressCallback *callback);
938 -------------------------------------------------------------------------------
940 Returns pointer to allocated context of given pixel_type.
942 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
943 returned.
945 Hilbert-Peano
946 ^^^^^^^^^^^^^
948 Hilbert-Peano space filling curve based dithering.
950 The error value is distributed around the Hilbert curve.
952 The result is a little more noisy, but doesn't create repeating patterns like
953 Floyd-Steinberg which looks generally better to human eye. On the other hand
954 edges tend to be less sharp.
956 [source,c]
957 -------------------------------------------------------------------------------
958 #include <GP_Filters.h>
960 int GP_FilterHilbertPeano_RGB888(const GP_Context *src,
961                                  GP_Context *dst,
962                                  GP_ProgressCallback *callback);
963 -------------------------------------------------------------------------------
965 Renders Hilbert Peano dithering directly into passed context. The
966 destination must be at least as large as source. 
968 If operation was aborted by a callback, non-zero is returned.
970 [source,c]
971 -------------------------------------------------------------------------------
972 #include <GP_Filters.h>
974 GP_Context *GP_FilterHilbertPeano_RGB888_Alloc(const GP_Context *src,
975                                                GP_PixelType pixel_type,
976                                                GP_ProgressCallback *callback);
977 -------------------------------------------------------------------------------
979 Returns pointer to allocated context of given pixel_type.
981 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
982 returned.
984 Example Images
985 ^^^^^^^^^^^^^^
986 All following images were generated using 'grinder'.
987 (Click for bigger size)
989 .Original Image; Floyd-Steinberg, Hilbert-Peano: 1-bit, 2-bit, 4-bit, 8-bit Grayscale; 1-bit, 2-bit, 3-bit (per channel) RGB
990 image:images/dither/lenna_small.png[
991         "Original Image", 
992         link="images/dither/lenna.png"]
993 image:images/dither/lenna_G1_FS_small.png[
994         "1-bit Grayscale Floyd-Steinberg",
995         link="images/dither/lenna_G1_FS.png"]
996 image:images/dither/lenna_G1_HP_small.png[
997         "1-bit Grayscale Hilbert-Peano",
998         link="images/dither/lenna_G1_HP.png"]
999 image:images/dither/lenna_G2_FS_small.png[
1000         "2-bit Grayscale Floyd-Steinberg",
1001         link="images/dither/lenna_G2_FS.png"]
1002 image:images/dither/lenna_G2_HP_small.png[
1003         "2-bit Grayscale Hilbert-Peano",
1004         link="images/dither/lenna_G2_HP.png"]
1005 image:images/dither/lenna_G4_FS_small.png[
1006         "4-bit Grayscale Floyd-Steinberg",
1007         link="images/dither/lenna_G4_FS.png"]
1008 image:images/dither/lenna_G4_HP_small.png[
1009         "4-bit Grayscale Hilbert-Peano",
1010         link="images/dither/lenna_G4_HP.png"]
1011 image:images/dither/lenna_G8_FS_small.png[
1012         "8-bit Grayscale Floyd-Steinberg",
1013         link="images/dither/lenna_G8_FS.png"]
1014 image:images/dither/lenna_G8_HP_small.png[
1015         "7-bit Grayscale Hilbert-Peano",
1016         link="images/dither/lenna_G8_HP.png"]
1017 image:images/dither/lenna_RGB111_FS_small.png[
1018         "1-bit RGB Floyd-Steinberg",
1019         link="images/dither/lenna_RGB111_FS.png"]
1020 image:images/dither/lenna_RGB111_HP_small.png[
1021         "1-bit RGB Hilbert-Peano",
1022         link="images/dither/lenna_RGB111_HP.png"]
1023 image:images/dither/lenna_RGB222_FS_small.png[
1024         "2-bit RGB Floyd-Steinberg",
1025         link="images/dither/lenna_RGB222_FS.png"]
1026 image:images/dither/lenna_RGB222_HP_small.png[
1027         "2-bit RGB Hilbert-Peano",
1028         link="images/dither/lenna_RGB222_HP.png"]
1029 image:images/dither/lenna_RGB333_FS_small.png[
1030         "3-bit RGB Floyd-Steinberg",
1031         link="images/dither/lenna_RGB333_FS.png"]
1032 image:images/dither/lenna_RGB333_HP_small.png[
1033         "3-bit RGB Hilbert-Peano",
1034         link="images/dither/lenna_RGB333_HP.png"]