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 * Each filter returns pointer to destination context or 'NULL' on failure
17 * The first two arguments are source and destination
18 * The last argument is progress callback
20 Each filter function could be used in two modes.
22 By passing non-'NULL' argument as filter destination user requests result to
23 be stored into the destination context. The context must have correct pixel
24 type and the context size must be big enough to store the result.
26 For filters that work 'in-place' (which is explicitly said for each filter)
27 the source and the destination could be the same context. Note that this is
28 not expected to work if you do several overlapping subcontexts and pass these
31 When 'NULL' is passed as destination new context for storing the result is
32 allocated and returned.
34 The return value is either pointer to destination context or 'NULL' either
35 when malloc(2) has failed or if the filter is not implemented for such
36 pixel_type, parameters, etc...
39 -------------------------------------------------------------------------------
43 GP_Context *GP_FilterFoo(const GP_Context *src, GP_Context *dst,
45 GP_ProgressCallback *callback);
46 -------------------------------------------------------------------------------
49 Filters also exists in _Raw variant (that just takes source context,
50 destination context, filters parameters and progress callback). These filter
51 APIs are used for internal implementation and shouldn't be called by user as
52 the destination is expected to be crafted exactly for storing the filter
53 result and there are 'NO' sanity checks in place.
55 'You could use these at your own risk'
58 -------------------------------------------------------------------------------
60 * Raw filter common API.
62 void GP_FilterFoo_Raw(const GP_Context *src, GP_Context *dst,
64 GP_ProgressCallback *callback);
65 -------------------------------------------------------------------------------
67 Point operation filters
68 ~~~~~~~~~~~~~~~~~~~~~~~
70 Point operations are filters that works with pixels as with independent values
71 (the value of destination pixel depends only on the pixel on the same
72 coordinates in source image). All of these filters works 'in-place' and the
73 result has always the same size as the source.
76 -------------------------------------------------------------------------------
77 #include <GP_Filters.h>
79 GP_Context *GP_FilterBrightness(const GP_Context *src, GP_Context *dst,
80 int32_t inc, GP_ProgressCallback *callback);
81 -------------------------------------------------------------------------------
83 Brightness filter, increments all pixel channels by a fixed value.
86 -------------------------------------------------------------------------------
87 #include <GP_Filters.h>
89 GP_Context *GP_FilterContrast(const GP_Context *src, GP_Context *dst,
90 float mul, GP_ProgressCallback *callback);
91 -------------------------------------------------------------------------------
93 Contrast filter, multiplies all pixel channels by a fixed value.
96 -------------------------------------------------------------------------------
97 #include <GP_Filters.h>
99 GP_Context *GP_FilterInvert(const GP_Context *src, GP_Context *dst,
100 GP_ProgressCallback *callback);
101 -------------------------------------------------------------------------------
103 Inverts the image, for each channel the result value is computed as "chan_max
106 Rotation and Symmetry filters
107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110 -------------------------------------------------------------------------------
111 #include <GP_Filters.h>
113 int GP_FilterMirrorH(const GP_Context *src, GP_Context *dst,
114 GP_ProgressCallback *callback);
116 GP_Context *GP_FilterMirrorH_Alloc(const GP_Context *src,
117 GP_ProgressCallback *callback);
118 -------------------------------------------------------------------------------
120 Mirrors context horizontally.
124 The destination has to have the same pixel type and the size must be at least
128 -------------------------------------------------------------------------------
129 #include <GP_Filters.h>
131 int GP_FilterMirrorV(const GP_Context *src, GP_Context *dst,
132 GP_ProgressCallback *callback);
134 GP_Context *GP_FilterMirrorV_Alloc(const GP_Context *src,
135 GP_ProgressCallback *callback);
136 -------------------------------------------------------------------------------
138 Mirrors context vertically.
142 The destination has to have the same pixel type and the size must be at least
146 -------------------------------------------------------------------------------
147 #include <GP_Filters.h>
149 int GP_FilterRotate90(const GP_Context *src, GP_Context *dst,
150 GP_ProgressCallback *callback);
152 GP_Context *GP_FilterRotate90_Alloc(const GP_Context *src,
153 GP_ProgressCallback *callback);
154 -------------------------------------------------------------------------------
156 Rotate context by 90 degrees.
158 Doesn't work 'in-place' (yet).
160 The destination has to have the same pixel type and size must be large enough to
161 fit rotated context (i.e. W and H are swapped).
164 -------------------------------------------------------------------------------
165 #include <GP_Filters.h>
167 int GP_FilterRotate180(const GP_Context *src, GP_Context *dst,
168 GP_ProgressCallback *callback);
170 GP_Context *GP_FilterRotate180_Alloc(const GP_Context *src,
171 GP_ProgressCallback *callback);
172 -------------------------------------------------------------------------------
174 Rotate context by 180 degrees.
176 Doesn't work 'in-place' (yet).
178 The destination has to have the same pixel type and the size must be at least
182 -------------------------------------------------------------------------------
183 #include <GP_Filters.h>
185 int GP_FilterRotate270(const GP_Context *src, GP_Context *dst,
186 GP_ProgressCallback *callback);
188 GP_Context *GP_FilterRotate270_Alloc(const GP_Context *src,
189 GP_ProgressCallback *callback);
190 -------------------------------------------------------------------------------
192 Rotate context by 270 degrees.
194 Doesn't work 'in-place' (yet).
196 The destination has to have the same pixel type and destination size must be
197 large enough to fit rotated context (eg. W and H are swapped).
200 -------------------------------------------------------------------------------
201 typedef enum GP_FilterSymmetries {
203 GP_ROTATE_CW = GP_ROTATE_90,
206 GP_ROTATE_CCW = GP_ROTATE_270,
209 } GP_FilterSymmetries;
211 GP_Context *GP_FilterSymmetry(const GP_Context *src,
212 GP_FilterSymmetries symmetry,
213 GP_ProgressCallback *callback);
215 int GP_FilterSymmetry(const GP_Context *src, GP_Context *dst,
216 GP_FilterSymmetries symmetry,
217 GP_ProgressCallback *callback);
218 -------------------------------------------------------------------------------
220 Catch all function for symmetry filters.
227 -------------------------------------------------------------------------------
228 #include <GP_Filters.h>
230 GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
231 float sigma_x, float sigma_y,
232 GP_ProgressCallback *callback);
233 -------------------------------------------------------------------------------
235 Gaussian blur filter.
239 'TODO:' this filter is implemented for RGB888 only.
242 Interpolation filters
243 ~~~~~~~~~~~~~~~~~~~~~
246 -------------------------------------------------------------------------------
247 #include <GP_Filters.h>
249 typedef enum GP_InterpolationType {
250 GP_INTERP_NN, /* Nearest Neighbour */
251 GP_INTERP_CUBIC, /* Bicubic */
252 } GP_InterpolationType;
254 GP_Context *GP_FilterResize(const GP_Context *src, GP_Context *dst,
255 GP_InterpolationType type,
256 GP_Size w, GP_Size h,
257 GP_ProgressCallback *callback);
258 -------------------------------------------------------------------------------
260 Interpolate (resize) the context.
262 Doesn't work 'in-place' (this is quite impossible as the size of the bitmap is
263 changed by the filter).
265 If the filter destination is non 'NULL' and the 'w' and 'h' is smaller than the
266 destination size the source image is interpolated into subcontext of
267 destination defined by 'w' and 'h'.
269 'TODO:' this filter is implemented for RGB888 only.
271 Nearest Neighbour Interpolation
272 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
274 Fast, but produces "pixelated" images. May however work better for images with
275 sharp edges mostly consisting of big one color regions (it doesn't blur the
276 result on upscaling).
278 Bicubic Interpolation
279 ^^^^^^^^^^^^^^^^^^^^^
281 Works well as is on image upscaling. To get decent result on downscaling
282 low-pass filter (Gaussian blur) must be used on original image before actual
283 downscaling. To do this reasonably fast we could cheat a little: first resize
284 big images a little without the low-pass filter, then apply low-pass filter and
285 finally downscale it to desired size.
290 Currently there are two dithering algorithms implemented. Both takes an RGB888
291 24bit image as input and are able to produce any RGB or Grayscale image.
292 This filters doesn't work 'in-place' as the result has different pixel type.
297 Classical Floyd-Steinberg. Produces good results and is a little faster than
298 the Hilbert-Peano dithering.
300 The error is distributed to neighbor pixels as follows:
308 And is throwed away at the image borders.
311 -------------------------------------------------------------------------------
312 #include <GP_Filters.h>
314 int GP_FilterFloydSteinberg_RGB888(const GP_Context *src,
316 GP_ProgressCallback *callback);
317 -------------------------------------------------------------------------------
319 Renders Floyd Steinberg dithering directly into passed context. The
320 destination must be at least as large as source.
322 If operation was aborted by a callback, non-zero is returned.
325 -------------------------------------------------------------------------------
326 #include <GP_Filters.h>
328 GP_Context *GP_FilterFloydSteinberg_RGB888_Alloc(const GP_Context *src,
329 GP_PixelType pixel_type,
330 GP_ProgressCallback *callback);
331 -------------------------------------------------------------------------------
333 Returns pointer to allocated context of given pixel_type.
335 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
341 Hilbert-Peano space filling curve based dithering.
343 The error value is distributed around the Hilbert curve.
345 The result is a little more noisy, but doesn't create repeating patterns like
346 Floyd-Steinberg which looks generally better to human eye. On the other hand
347 edges tend to be less sharp.
350 -------------------------------------------------------------------------------
351 #include <GP_Filters.h>
353 int GP_FilterHilbertPeano_RGB888(const GP_Context *src,
355 GP_ProgressCallback *callback);
356 -------------------------------------------------------------------------------
358 Renders Hilbert Peano dithering directly into passed context. The
359 destination must be at least as large as source.
361 If operation was aborted by a callback, non-zero is returned.
364 -------------------------------------------------------------------------------
365 #include <GP_Filters.h>
367 GP_Context *GP_FilterHilbertPeano_RGB888_Alloc(const GP_Context *src,
368 GP_PixelType pixel_type,
369 GP_ProgressCallback *callback);
370 -------------------------------------------------------------------------------
372 Returns pointer to allocated context of given pixel_type.
374 If malloc(2) has failed, or operation was aborted by a callback 'NULL' is
379 All following images were generated using 'grinder'.
380 (Click for bigger size)
382 .Original Image; Floyd-Steinberg, Hilbert-Peano: 1-bit, 2-bit, 4-bit, 8-bit Grayscale; 1-bit, 2-bit, 3-bit (per channel) RGB
383 image:images/dither/lenna_small.png[
385 link="images/dither/lenna.png"]
386 image:images/dither/lenna_G1_FS_small.png[
387 "1-bit Grayscale Floyd-Steinberg",
388 link="images/dither/lenna_G1_FS.png"]
389 image:images/dither/lenna_G1_HP_small.png[
390 "1-bit Grayscale Hilbert-Peano",
391 link="images/dither/lenna_G1_HP.png"]
392 image:images/dither/lenna_G2_FS_small.png[
393 "2-bit Grayscale Floyd-Steinberg",
394 link="images/dither/lenna_G2_FS.png"]
395 image:images/dither/lenna_G2_HP_small.png[
396 "2-bit Grayscale Hilbert-Peano",
397 link="images/dither/lenna_G2_HP.png"]
398 image:images/dither/lenna_G4_FS_small.png[
399 "4-bit Grayscale Floyd-Steinberg",
400 link="images/dither/lenna_G4_FS.png"]
401 image:images/dither/lenna_G4_HP_small.png[
402 "4-bit Grayscale Hilbert-Peano",
403 link="images/dither/lenna_G4_HP.png"]
404 image:images/dither/lenna_G8_FS_small.png[
405 "8-bit Grayscale Floyd-Steinberg",
406 link="images/dither/lenna_G8_FS.png"]
407 image:images/dither/lenna_G8_HP_small.png[
408 "7-bit Grayscale Hilbert-Peano",
409 link="images/dither/lenna_G8_HP.png"]
410 image:images/dither/lenna_RGB111_FS_small.png[
411 "1-bit RGB Floyd-Steinberg",
412 link="images/dither/lenna_RGB111_FS.png"]
413 image:images/dither/lenna_RGB111_HP_small.png[
414 "1-bit RGB Hilbert-Peano",
415 link="images/dither/lenna_RGB111_HP.png"]
416 image:images/dither/lenna_RGB222_FS_small.png[
417 "2-bit RGB Floyd-Steinberg",
418 link="images/dither/lenna_RGB222_FS.png"]
419 image:images/dither/lenna_RGB222_HP_small.png[
420 "2-bit RGB Hilbert-Peano",
421 link="images/dither/lenna_RGB222_HP.png"]
422 image:images/dither/lenna_RGB333_FS_small.png[
423 "3-bit RGB Floyd-Steinberg",
424 link="images/dither/lenna_RGB333_FS.png"]
425 image:images/dither/lenna_RGB333_HP_small.png[
426 "3-bit RGB Hilbert-Peano",
427 link="images/dither/lenna_RGB333_HP.png"]