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.
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. If filter has
26 been interrupted by a callback, all allocated memory is freed and 'NULL' is
29 When using non-allocating variant of the filter, the destination context must
30 have correct pixel type and the context size must be big enough to store the
31 result. The return value from such filter is either zero, in case of success,
32 or non-zero when filter was interrupted by a callback.
34 For filters that work 'in-place' (which is explicitly said for each filter)
35 the source and the destination could be the same context. Note that this is
36 not expected to work if you do several overlapping sub-contexts and pass these
40 -------------------------------------------------------------------------------
44 int GP_FilterFoo(const GP_Context *src, GP_Context *dst,
46 GP_ProgressCallback *callback);
48 GP_Context *GP_FilterFooAlloc(const GP_Context *src,
50 GP_ProgressCallback *callback);
51 -------------------------------------------------------------------------------
54 Filters also exists in _Raw variant whose interface is similar to the first
55 type of filter function. These filter APIs are used for internal
56 implementation and shouldn't be called by user as the destination is expected
57 to be crafted exactly for storing the filter result and there are 'NO' sanity
60 'You could use these at your own risk'
63 -------------------------------------------------------------------------------
65 * Raw filter common API.
67 int GP_FilterFoo_Raw(const GP_Context *src, GP_Context *dst,
69 GP_ProgressCallback *callback);
70 -------------------------------------------------------------------------------
75 In order to pass, per-channel, filter parameters to a filter, structure called
76 GP_FilterParams was created.
79 -------------------------------------------------------------------------------
82 #include <filters/GP_FilterParam.h>
84 typedef union GP_FilterParamVal {
91 typedef struct GP_FilterParam {
93 union GP_FilterParamVal val;
95 -------------------------------------------------------------------------------
97 Some filters do take an empty channel_name terminated (empty channel_name is
98 empty string i.e. "\0") array of GP_FilterParam, which is used to describe
99 per-channel parameters.
102 There are two methods how to construct GP_FilterParam structure. First one is
103 to use macro that expands to a code which declares and initializes the array on
104 the stack second uses memory allocated by a malloc(). In both cases the
105 structure is has initialized channel names and terminator.
108 -------------------------------------------------------------------------------
111 #include <filters/GP_FilterParam.h>
113 #define GP_FILTER_PARAMS(pixel_type, name) \
114 GP_FilterParam name[GP_PixelTypes[pixel_type].numchannels + 1]; \
115 GP_FilterParamInitChannels(name, pixel_type);
116 -------------------------------------------------------------------------------
118 Macro that declares and initializes GP_FilterParam structure for a given
122 -------------------------------------------------------------------------------
125 #include <filters/GP_FilterParam.h>
127 GP_FilterParam *GP_FilterParamCreate(GP_PixelType pixel_type);
129 void GP_FilterParamDestroy(GP_FilterParam *self);
130 -------------------------------------------------------------------------------
132 Second possible way allocates memory using malloc().
134 Functions for manipulating and querying existing GP_FilterParam follows.
137 -------------------------------------------------------------------------------
140 #include <filters/GP_FilterParam.h>
142 void GP_FilterParamInitChannels(GP_FilterParam params[],
143 GP_PixelType pixel_type);
144 -------------------------------------------------------------------------------
146 Initializes filter param array channel names (accordingly to pixel type) and
147 terminator. The params array must be large enough to hold number of pixel type
151 -------------------------------------------------------------------------------
154 #include <filters/GP_FilterParam.h>
156 GP_FilterParam *GP_FilterParamChannel(GP_FilterParam params[],
157 const char *channel_name);
158 -------------------------------------------------------------------------------
160 Does lookup for a given channel name and returns, if found, corresponding
161 GP_FilterParam, otherwise 'NULL' is returned.
163 This function is primary used in filters, where filter, at the start, resolves
167 -------------------------------------------------------------------------------
170 #include <filters/GP_FilterParam.h>
172 int GP_FilterParamCheckPixelType(GP_FilterParam params[],
173 GP_PixelType pixel_type);
174 -------------------------------------------------------------------------------
176 Matches param structure against pixel_type. Returns zero if params describes
177 exactly same channels like pixel_type, non-zero otherwise.
180 -------------------------------------------------------------------------------
183 #include <filters/GP_FilterParam.h>
185 void GP_FilterParamSetIntAll(GP_FilterParam params[], int32_t val);
187 int GP_FilterParamSetInt(GP_FilterParam params[], const char *channel_name,
190 void GP_FilterParamSetFloatAll(GP_FilterParam params[], float val);
192 int GP_FilterParamSetFloat(GP_FilterParam params[], const char *channel_name,
195 void GP_FilterParamSetUIntAll(GP_FilterParam params[], uint32_t val);
197 int GP_FilterParamSetUInt(GP_FilterParam params[], const char *channel_name,
200 void GP_FilterParamSetPtrAll(GP_FilterParam params[], void *ptr);
202 int GP_FilterParamSetPtr(GP_FilterParam params[], const char *channel_name,
205 void GP_FilterParamFreePtrAll(GP_FilterParam params[]);
206 -------------------------------------------------------------------------------
208 Parameter setters. Those that sets individual value returns zero on success
209 (i.e. channel was found) and non-zero otherwise.
211 The last one calls free() on all param pointers, which is used to free
214 Point operation filters
215 ~~~~~~~~~~~~~~~~~~~~~~~
217 Point operations are filters that works with pixels as with independent values
218 (the value of destination pixel depends only on the pixel on the same
219 coordinates in source image). All of these filters works 'in-place' and the
220 result has always the same size as the source.
223 -------------------------------------------------------------------------------
224 #include <GP_Filters.h>
226 GP_Context *GP_FilterBrightness(const GP_Context *src, GP_Context *dst,
227 int32_t inc, GP_ProgressCallback *callback);
228 -------------------------------------------------------------------------------
230 Brightness filter, increments all pixel channels by a fixed value.
233 -------------------------------------------------------------------------------
234 #include <GP_Filters.h>
236 GP_Context *GP_FilterContrast(const GP_Context *src, GP_Context *dst,
237 float mul, GP_ProgressCallback *callback);
238 -------------------------------------------------------------------------------
240 Contrast filter, multiplies all pixel channels by a fixed value.
243 -------------------------------------------------------------------------------
244 #include <GP_Filters.h>
246 GP_Context *GP_FilterInvert(const GP_Context *src, GP_Context *dst,
247 GP_ProgressCallback *callback);
248 -------------------------------------------------------------------------------
250 Inverts the image, for each channel the result value is computed as "chan_max
256 Arithmetic filters do take two contexts as an input and combines them into one
259 The pixel type of both input contexts must match.
261 If size of the input contexts differs, minimum is used.
264 -------------------------------------------------------------------------------
265 #include <filters/GP_Arithmetic.h>
269 int GP_FilterAddition(const GP_Context *src_a,
270 const GP_Context *src_b,
272 GP_ProgressCallback *callback);
274 GP_Context *GP_FilterAdditionAlloc(const GP_Context *src_a,
275 const GP_Context *src_b,
276 GP_ProgressCallback *callback);
277 -------------------------------------------------------------------------------
279 Produces saturated (clamped) addition of two contexts.
282 -------------------------------------------------------------------------------
283 #include <filters/GP_Arithmetic.h>
287 int GP_FilterMultiply(const GP_Context *src_a,
288 const GP_Context *src_b,
290 GP_ProgressCallback *callback);
292 GP_Context *GP_FilterMultiplyAlloc(const GP_Context *src_a,
293 const GP_Context *src_b,
294 GP_ProgressCallback *callback);
295 -------------------------------------------------------------------------------
297 Produces saturated (clamped) multiplication of two contexts.
300 -------------------------------------------------------------------------------
301 #include <filters/GP_Arigthmetic.h>
305 int GP_FilterDifference(const GP_Context *src_a,
306 const GP_Context *src_b,
308 GP_ProgressCallback *callback);
310 GP_Context *GP_FilterDifferenceAlloc(const GP_Context *src_a,
311 const GP_Context *src_b,
312 GP_ProgressCallback *callback);
314 -------------------------------------------------------------------------------
316 Produces symmetric difference (i.e. abs(a - b)).
319 -------------------------------------------------------------------------------
320 #include <filters/GP_Arigthmetic.h>
324 int GP_FilterMax(const GP_Context *src_a,
325 const GP_Context *src_b,
327 GP_ProgressCallback *callback);
329 GP_Context *GP_FilterMaxAlloc(const GP_Context *src_a,
330 const GP_Context *src_b,
331 GP_ProgressCallback *callback);
333 int GP_FilterMin(const GP_Context *src_a,
334 const GP_Context *src_b,
336 GP_ProgressCallback *callback);
338 GP_Context *GP_FilterMinAlloc(const GP_Context *src_a,
339 const GP_Context *src_b,
340 GP_ProgressCallback *callback);
341 -------------------------------------------------------------------------------
343 Maximum and minimum filter.
345 Rotation and Symmetry filters
346 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
349 -------------------------------------------------------------------------------
350 #include <filters/GP_Rotate.h>
354 int GP_FilterMirrorH(const GP_Context *src, GP_Context *dst,
355 GP_ProgressCallback *callback);
357 GP_Context *GP_FilterMirrorH_Alloc(const GP_Context *src,
358 GP_ProgressCallback *callback);
359 -------------------------------------------------------------------------------
361 Mirrors context horizontally.
365 The destination has to have the same pixel type and the size must be at least
369 -------------------------------------------------------------------------------
370 #include <filters/GP_Rotate.h>
374 int GP_FilterMirrorV(const GP_Context *src, GP_Context *dst,
375 GP_ProgressCallback *callback);
377 GP_Context *GP_FilterMirrorV_Alloc(const GP_Context *src,
378 GP_ProgressCallback *callback);
379 -------------------------------------------------------------------------------
381 Mirrors context vertically.
385 The destination has to have the same pixel type and the size must be at least
389 -------------------------------------------------------------------------------
390 #include <filters/GP_Rotate.h>
394 int GP_FilterRotate90(const GP_Context *src, GP_Context *dst,
395 GP_ProgressCallback *callback);
397 GP_Context *GP_FilterRotate90_Alloc(const GP_Context *src,
398 GP_ProgressCallback *callback);
399 -------------------------------------------------------------------------------
401 Rotate context by 90 degrees.
403 Doesn't work 'in-place' (yet).
405 The destination has to have the same pixel type and size must be large enough to
406 fit rotated context (i.e. W and H are swapped).
409 -------------------------------------------------------------------------------
410 #include <filters/GP_Rotate.h>
414 int GP_FilterRotate180(const GP_Context *src, GP_Context *dst,
415 GP_ProgressCallback *callback);
417 GP_Context *GP_FilterRotate180_Alloc(const GP_Context *src,
418 GP_ProgressCallback *callback);
419 -------------------------------------------------------------------------------
421 Rotate context by 180 degrees.
423 Doesn't work 'in-place' (yet).
425 The destination has to have the same pixel type and the size must be at least
429 -------------------------------------------------------------------------------
430 #include <filters/GP_Rotate.h>
434 int GP_FilterRotate270(const GP_Context *src, GP_Context *dst,
435 GP_ProgressCallback *callback);
437 GP_Context *GP_FilterRotate270_Alloc(const GP_Context *src,
438 GP_ProgressCallback *callback);
439 -------------------------------------------------------------------------------
441 Rotate context by 270 degrees.
443 Doesn't work 'in-place' (yet).
445 The destination has to have the same pixel type and destination size must be
446 large enough to fit rotated context (i.e. W and H are swapped).
449 -------------------------------------------------------------------------------
450 #include <filters/GP_Rotate.h>
454 typedef enum GP_FilterSymmetries {
456 GP_ROTATE_CW = GP_ROTATE_90,
459 GP_ROTATE_CCW = GP_ROTATE_270,
462 } GP_FilterSymmetries;
464 GP_Context *GP_FilterSymmetry(const GP_Context *src,
465 GP_FilterSymmetries symmetry,
466 GP_ProgressCallback *callback);
468 int GP_FilterSymmetry(const GP_Context *src, GP_Context *dst,
469 GP_FilterSymmetries symmetry,
470 GP_ProgressCallback *callback);
471 -------------------------------------------------------------------------------
473 Catch all function for symmetry filters.
480 -------------------------------------------------------------------------------
481 #include <GP_Filters.h>
483 GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
484 float sigma_x, float sigma_y,
485 GP_ProgressCallback *callback);
486 -------------------------------------------------------------------------------
488 Gaussian blur filter.
492 'TODO:' this filter is implemented for RGB888 only.
495 Interpolation filters
496 ~~~~~~~~~~~~~~~~~~~~~
499 -------------------------------------------------------------------------------
500 #include <GP_Filters.h>
502 typedef enum GP_InterpolationType {
503 GP_INTERP_NN, /* Nearest Neighbour */
504 GP_INTERP_CUBIC, /* Bicubic */
505 } GP_InterpolationType;
507 GP_Context *GP_FilterResize(const GP_Context *src, GP_Context *dst,
508 GP_InterpolationType type,
509 GP_Size w, GP_Size h,
510 GP_ProgressCallback *callback);
511 -------------------------------------------------------------------------------
513 Interpolate (resize) the context.
515 Doesn't work 'in-place' (this is quite impossible as the size of the bitmap is
516 changed by the filter).
518 If the filter destination is non 'NULL' and the 'w' and 'h' is smaller than the
519 destination size the source image is interpolated into sub-context of
520 destination defined by 'w' and 'h'.
522 'TODO:' this filter is implemented for RGB888 only.
524 Nearest Neighbour Interpolation
525 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
527 Fast, but produces "pixelated" images. May however work better for images with
528 sharp edges mostly consisting of big one color regions (it doesn't blur the
529 result on upscaling).
531 Bicubic Interpolation
532 ^^^^^^^^^^^^^^^^^^^^^
534 Works well as is on image upscaling. To get decent result on downscaling
535 low-pass filter (Gaussian blur) must be used on original image before actual
536 downscaling. To do this reasonably fast we could cheat a little: first resize
537 big images a little without the low-pass filter, then apply low-pass filter and
538 finally downscale it to desired size.
543 Currently there are two dithering algorithms implemented. Both takes an RGB888
544 24bit image as input and are able to produce any RGB or Grayscale image.
545 This filters doesn't work 'in-place' as the result has different pixel type.
550 Classical Floyd-Steinberg. Produces good results and is a little faster than
551 the Hilbert-Peano dithering.
553 The error is distributed to neighbor pixels as follows:
561 And is throwed away at the image borders.
564 -------------------------------------------------------------------------------
565 #include <GP_Filters.h>
567 int GP_FilterFloydSteinberg_RGB888(const GP_Context *src,
569 GP_ProgressCallback *callback);
570 -------------------------------------------------------------------------------
572 Renders Floyd Steinberg dithering directly into passed context. The
573 destination must be at least as large as source.
575 If operation was aborted by a callback, non-zero is returned.
578 -------------------------------------------------------------------------------
579 #include <GP_Filters.h>
581 GP_Context *GP_FilterFloydSteinberg_RGB888_Alloc(const GP_Context *src,
582 GP_PixelType pixel_type,
583 GP_ProgressCallback *callback);
584 -------------------------------------------------------------------------------
586 Returns pointer to allocated context of given pixel_type.
588 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
594 Hilbert-Peano space filling curve based dithering.
596 The error value is distributed around the Hilbert curve.
598 The result is a little more noisy, but doesn't create repeating patterns like
599 Floyd-Steinberg which looks generally better to human eye. On the other hand
600 edges tend to be less sharp.
603 -------------------------------------------------------------------------------
604 #include <GP_Filters.h>
606 int GP_FilterHilbertPeano_RGB888(const GP_Context *src,
608 GP_ProgressCallback *callback);
609 -------------------------------------------------------------------------------
611 Renders Hilbert Peano dithering directly into passed context. The
612 destination must be at least as large as source.
614 If operation was aborted by a callback, non-zero is returned.
617 -------------------------------------------------------------------------------
618 #include <GP_Filters.h>
620 GP_Context *GP_FilterHilbertPeano_RGB888_Alloc(const GP_Context *src,
621 GP_PixelType pixel_type,
622 GP_ProgressCallback *callback);
623 -------------------------------------------------------------------------------
625 Returns pointer to allocated context of given pixel_type.
627 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
632 All following images were generated using 'grinder'.
633 (Click for bigger size)
635 .Original Image; Floyd-Steinberg, Hilbert-Peano: 1-bit, 2-bit, 4-bit, 8-bit Grayscale; 1-bit, 2-bit, 3-bit (per channel) RGB
636 image:images/dither/lenna_small.png[
638 link="images/dither/lenna.png"]
639 image:images/dither/lenna_G1_FS_small.png[
640 "1-bit Grayscale Floyd-Steinberg",
641 link="images/dither/lenna_G1_FS.png"]
642 image:images/dither/lenna_G1_HP_small.png[
643 "1-bit Grayscale Hilbert-Peano",
644 link="images/dither/lenna_G1_HP.png"]
645 image:images/dither/lenna_G2_FS_small.png[
646 "2-bit Grayscale Floyd-Steinberg",
647 link="images/dither/lenna_G2_FS.png"]
648 image:images/dither/lenna_G2_HP_small.png[
649 "2-bit Grayscale Hilbert-Peano",
650 link="images/dither/lenna_G2_HP.png"]
651 image:images/dither/lenna_G4_FS_small.png[
652 "4-bit Grayscale Floyd-Steinberg",
653 link="images/dither/lenna_G4_FS.png"]
654 image:images/dither/lenna_G4_HP_small.png[
655 "4-bit Grayscale Hilbert-Peano",
656 link="images/dither/lenna_G4_HP.png"]
657 image:images/dither/lenna_G8_FS_small.png[
658 "8-bit Grayscale Floyd-Steinberg",
659 link="images/dither/lenna_G8_FS.png"]
660 image:images/dither/lenna_G8_HP_small.png[
661 "7-bit Grayscale Hilbert-Peano",
662 link="images/dither/lenna_G8_HP.png"]
663 image:images/dither/lenna_RGB111_FS_small.png[
664 "1-bit RGB Floyd-Steinberg",
665 link="images/dither/lenna_RGB111_FS.png"]
666 image:images/dither/lenna_RGB111_HP_small.png[
667 "1-bit RGB Hilbert-Peano",
668 link="images/dither/lenna_RGB111_HP.png"]
669 image:images/dither/lenna_RGB222_FS_small.png[
670 "2-bit RGB Floyd-Steinberg",
671 link="images/dither/lenna_RGB222_FS.png"]
672 image:images/dither/lenna_RGB222_HP_small.png[
673 "2-bit RGB Hilbert-Peano",
674 link="images/dither/lenna_RGB222_HP.png"]
675 image:images/dither/lenna_RGB333_FS_small.png[
676 "3-bit RGB Floyd-Steinberg",
677 link="images/dither/lenna_RGB333_FS.png"]
678 image:images/dither/lenna_RGB333_HP_small.png[
679 "3-bit RGB Hilbert-Peano",
680 link="images/dither/lenna_RGB333_HP.png"]