spiv: image_cache: Add elevator count, drop cache on d.
[gfxprim.git] / doc / filters.txt
blob1abf977100457663fe27d4609e5eff7941fe6857
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. If filter has
26 been interrupted by a callback, all allocated memory is freed and 'NULL' is
27 returned.
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
37 as arguments.
39 [source,c]
40 -------------------------------------------------------------------------------
42  * Filter common API.
43  */
44 int GP_FilterFoo(const GP_Context *src, GP_Context *dst,
45                  foo params ...,
46                  GP_ProgressCallback *callback);
48 GP_Context *GP_FilterFooAlloc(const GP_Context *src,
49                               foo params ...,
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
58 checks in place.
60 'You could use these at your own risk'
62 [source,c]
63 -------------------------------------------------------------------------------
65  * Raw filter common API.
66  */
67 int GP_FilterFoo_Raw(const GP_Context *src, GP_Context *dst,
68                      foo params ...,
69                      GP_ProgressCallback *callback);
70 -------------------------------------------------------------------------------
72 Filter Parameters
73 ~~~~~~~~~~~~~~~~~
75 In order to pass, per-channel, filter parameters to a filter, structure called
76 GP_FilterParams was created.
78 [source,c]
79 -------------------------------------------------------------------------------
80 #include <GP.h>
81 /* or */
82 #include <filters/GP_FilterParam.h>
84 typedef union GP_FilterParamVal {
85         float f;
86         uint32_t ui;
87         int32_t i;
88         void *ptr;
89 } GP_FilterParamVal;
91 typedef struct GP_FilterParam {
92         char channel_name[2];
93         union GP_FilterParamVal val;
94 } GP_FilterParam;
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.
107 [source,c]
108 -------------------------------------------------------------------------------
109 #include <GP.h>
110 /* or */
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
119 pixel_type.
121 [source,c]
122 -------------------------------------------------------------------------------
123 #include <GP.h>
124 /* or */
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.
136 [source,c]
137 -------------------------------------------------------------------------------
138 #include <GP.h>
139 /* or */
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
148 channels plus one.
150 [source,c]
151 -------------------------------------------------------------------------------
152 #include <GP.h>
153 /* or */
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
164 all it's parameters.
166 [source,c]
167 -------------------------------------------------------------------------------
168 #include <GP.h>
169 /* or */
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.
179 [source,c]
180 -------------------------------------------------------------------------------
181 #include <GP.h>
182 /* or */
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,
188                          int32_t val);
190 void GP_FilterParamSetFloatAll(GP_FilterParam params[], float val);
192 int GP_FilterParamSetFloat(GP_FilterParam params[], const char *channel_name,
193                            float val);
195 void GP_FilterParamSetUIntAll(GP_FilterParam params[], uint32_t val);
197 int GP_FilterParamSetUInt(GP_FilterParam params[], const char *channel_name,
198                           uint32_t val);
200 void GP_FilterParamSetPtrAll(GP_FilterParam params[], void *ptr);
202 int GP_FilterParamSetPtr(GP_FilterParam params[], const char *channel_name,
203                          void *ptr);
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
212 allocate memory.
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.
222 [source,c]
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.
232 [source,c]
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.
242 [source,c]
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
251 - val".
253 Arithmetic filters
254 ~~~~~~~~~~~~~~~~~~
256 Arithmetic filters do take two contexts as an input and combines them into one
257 output context.
259 The pixel type of both input contexts must match.
261 If size of the input contexts differs, minimum is used.
263 [source,c]
264 -------------------------------------------------------------------------------
265 #include <filters/GP_Arithmetic.h>
266 /* or */
267 #include <GP.h>
269 int GP_FilterAddition(const GP_Context *src_a,
270                       const GP_Context *src_b,
271                       GP_Context *dst,
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.
281 [source,c]
282 -------------------------------------------------------------------------------
283 #include <filters/GP_Arithmetic.h>
284 /* or */
285 #include <GP.h>
287 int GP_FilterMultiply(const GP_Context *src_a,
288                       const GP_Context *src_b,
289                       GP_Context *dst,
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.
299 [source,c]
300 -------------------------------------------------------------------------------
301 #include <filters/GP_Arigthmetic.h>
302 /* or */
303 #include <GP.h>
305 int GP_FilterDifference(const GP_Context *src_a,
306                         const GP_Context *src_b,
307                         GP_Context *dst,
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)).
318 [source,c]
319 -------------------------------------------------------------------------------
320 #include <filters/GP_Arigthmetic.h>
321 /* or */
322 #include <GP.h>
324 int GP_FilterMax(const GP_Context *src_a,
325                  const GP_Context *src_b,
326                  GP_Context *dst,
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,
335                  GP_Context *dst,
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
348 [source,c]
349 -------------------------------------------------------------------------------
350 #include <filters/GP_Rotate.h>
351 /* or */
352 #include <GP.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.
363 Works 'in-place'.
365 The destination has to have the same pixel type and the size must be at least
366 as large as source.
368 [source,c]
369 -------------------------------------------------------------------------------
370 #include <filters/GP_Rotate.h>
371 /* or */
372 #include <GP.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.
383 Works 'in-place'.
385 The destination has to have the same pixel type and the size must be at least
386 as large as source.
388 [source,c]
389 -------------------------------------------------------------------------------
390 #include <filters/GP_Rotate.h>
391 /* or */
392 #include <GP.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).
408 [source,c]
409 -------------------------------------------------------------------------------
410 #include <filters/GP_Rotate.h>
411 /* or */
412 #include <GP.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
426 as large as source.
428 [source,c]
429 -------------------------------------------------------------------------------
430 #include <filters/GP_Rotate.h>
431 /* or */
432 #include <GP.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).
448 [source,c]
449 -------------------------------------------------------------------------------
450 #include <filters/GP_Rotate.h>
451 /* or */
452 #include <GP.h>
454 typedef enum GP_FilterSymmetries {
455         GP_ROTATE_90,
456         GP_ROTATE_CW = GP_ROTATE_90,
457         GP_ROTATE_180,
458         GP_ROTATE_270,
459         GP_ROTATE_CCW = GP_ROTATE_270,
460         GP_MIRROR_H,
461         GP_MIRROR_V,
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.
476 Linear filters
477 ~~~~~~~~~~~~~~
479 [source,c]
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.
490 Works 'in-place'.
492 'TODO:' this filter is implemented for RGB888 only.
495 Interpolation filters
496 ~~~~~~~~~~~~~~~~~~~~~
498 [source,c]
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.
540 Dithering
541 ~~~~~~~~~
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.
547 Floyd-Steinberg
548 ^^^^^^^^^^^^^^^
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:
555 [width="10%"]
556 |===================
557 |      |   X  | 7/16
558 | 3/16 | 5/16 | 1/16
559 |===================
561 And is throwed away at the image borders.
563 [source,c]
564 -------------------------------------------------------------------------------
565 #include <GP_Filters.h>
567 int GP_FilterFloydSteinberg_RGB888(const GP_Context *src,
568                                    GP_Context *dst,
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.
577 [source,c]
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
589 returned.
591 Hilbert-Peano
592 ^^^^^^^^^^^^^
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.
602 [source,c]
603 -------------------------------------------------------------------------------
604 #include <GP_Filters.h>
606 int GP_FilterHilbertPeano_RGB888(const GP_Context *src,
607                                  GP_Context *dst,
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.
616 [source,c]
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
628 returned.
630 Example Images
631 ^^^^^^^^^^^^^^
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[
637         "Original Image", 
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"]