xref: /haiku/headers/libs/agg/agg_image_filters.h (revision e39da397f5ff79f2db9f9a3ddf1852b6710578af)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // Image transformation filters,
17 // Filtering classes (image_filter_lut, image_filter),
18 // Basic filter shape classes
19 //----------------------------------------------------------------------------
20 #ifndef AGG_IMAGE_FILTERS_INCLUDED
21 #define AGG_IMAGE_FILTERS_INCLUDED
22 
23 #include "agg_array.h"
24 #include "agg_math.h"
25 
26 namespace agg
27 {
28 
29     // See Implementation agg_image_filters.cpp
30 
31     enum image_filter_scale_e
32     {
33         image_filter_shift = 14,                      //----image_filter_shift
34         image_filter_scale = 1 << image_filter_shift, //----image_filter_scale
35         image_filter_mask  = image_filter_scale - 1   //----image_filter_mask
36     };
37 
38     enum image_subpixel_scale_e
39     {
40         image_subpixel_shift = 8,                         //----image_subpixel_shift
41         image_subpixel_scale = 1 << image_subpixel_shift, //----image_subpixel_scale
42         image_subpixel_mask  = image_subpixel_scale - 1   //----image_subpixel_mask
43     };
44 
45 
46     //-----------------------------------------------------image_filter_lut
47     class image_filter_lut
48     {
49     public:
50         template<class FilterF> void calculate(const FilterF& filter,
51                                                bool normalization=true)
52         {
53             double r = filter.radius();
54             realloc_lut(r);
55             unsigned i;
56             unsigned pivot = diameter() << (image_subpixel_shift - 1);
57             for(i = 0; i < pivot; i++)
58             {
59                 double x = double(i) / double(image_subpixel_scale);
60                 double y = filter.calc_weight(x);
61                 m_weight_array[pivot + i] =
62                 m_weight_array[pivot - i] = (int16)iround(y * image_filter_scale);
63             }
64             unsigned end = (diameter() << image_subpixel_shift) - 1;
65             m_weight_array[0] = m_weight_array[end];
66             if(normalization)
67             {
68                 normalize();
69             }
70         }
71 
image_filter_lut()72         image_filter_lut() : m_radius(0), m_diameter(0), m_start(0) {}
73 
74         template<class FilterF> image_filter_lut(const FilterF& filter,
75                                                  bool normalization=true)
76         {
77             calculate(filter, normalization);
78         }
79 
radius()80         double       radius()       const { return m_radius;   }
diameter()81         unsigned     diameter()     const { return m_diameter; }
start()82         int          start()        const { return m_start;    }
weight_array()83         const int16* weight_array() const { return &m_weight_array[0]; }
84         void         normalize();
85 
86     private:
87         void realloc_lut(double radius);
88         image_filter_lut(const image_filter_lut&);
89         const image_filter_lut& operator = (const image_filter_lut&);
90 
91         double           m_radius;
92         unsigned         m_diameter;
93         int              m_start;
94         pod_array<int16> m_weight_array;
95     };
96 
97 
98 
99     //--------------------------------------------------------image_filter
100     template<class FilterF> class image_filter : public image_filter_lut
101     {
102     public:
image_filter()103         image_filter()
104         {
105             calculate(m_filter_function);
106         }
107     private:
108         FilterF m_filter_function;
109     };
110 
111 
112     //-----------------------------------------------image_filter_bilinear
113     struct image_filter_bilinear
114     {
radiusimage_filter_bilinear115         static double radius() { return 1.0; }
calc_weightimage_filter_bilinear116         static double calc_weight(double x)
117         {
118             return 1.0 - x;
119         }
120     };
121 
122 
123     //-----------------------------------------------image_filter_hanning
124     struct image_filter_hanning
125     {
radiusimage_filter_hanning126         static double radius() { return 1.0; }
calc_weightimage_filter_hanning127         static double calc_weight(double x)
128         {
129             return 0.5 + 0.5 * cos(pi * x);
130         }
131     };
132 
133 
134     //-----------------------------------------------image_filter_hamming
135     struct image_filter_hamming
136     {
radiusimage_filter_hamming137         static double radius() { return 1.0; }
calc_weightimage_filter_hamming138         static double calc_weight(double x)
139         {
140             return 0.54 + 0.46 * cos(pi * x);
141         }
142     };
143 
144     //-----------------------------------------------image_filter_hermite
145     struct image_filter_hermite
146     {
radiusimage_filter_hermite147         static double radius() { return 1.0; }
calc_weightimage_filter_hermite148         static double calc_weight(double x)
149         {
150             return (2.0 * x - 3.0) * x * x + 1.0;
151         }
152     };
153 
154     //------------------------------------------------image_filter_quadric
155     struct image_filter_quadric
156     {
radiusimage_filter_quadric157         static double radius() { return 1.5; }
calc_weightimage_filter_quadric158         static double calc_weight(double x)
159         {
160             double t;
161             if(x <  0.5) return 0.75 - x * x;
162             if(x <  1.5) {t = x - 1.5; return 0.5 * t * t;}
163             return 0.0;
164         }
165     };
166 
167     //------------------------------------------------image_filter_bicubic
168     class image_filter_bicubic
169     {
pow3(double x)170         static double pow3(double x)
171         {
172             return (x <= 0.0) ? 0.0 : x * x * x;
173         }
174 
175     public:
radius()176         static double radius() { return 2.0; }
calc_weight(double x)177         static double calc_weight(double x)
178         {
179             return
180                 (1.0/6.0) *
181                 (pow3(x + 2) - 4 * pow3(x + 1) + 6 * pow3(x) - 4 * pow3(x - 1));
182         }
183     };
184 
185     //-------------------------------------------------image_filter_kaiser
186     class image_filter_kaiser
187     {
188         double a;
189         double i0a;
190         double epsilon;
191 
192     public:
193         image_filter_kaiser(double b = 6.33) :
a(b)194             a(b), epsilon(1e-12)
195         {
196             i0a = 1.0 / bessel_i0(b);
197         }
198 
radius()199         static double radius() { return 1.0; }
calc_weight(double x)200         double calc_weight(double x) const
201         {
202             return bessel_i0(a * sqrt(1. - x * x)) * i0a;
203         }
204 
205     private:
bessel_i0(double x)206         double bessel_i0(double x) const
207         {
208             int i;
209             double sum, y, t;
210 
211             sum = 1.;
212             y = x * x / 4.;
213             t = y;
214 
215             for(i = 2; t > epsilon; i++)
216             {
217                 sum += t;
218                 t *= (double)y / (i * i);
219             }
220             return sum;
221         }
222     };
223 
224     //----------------------------------------------image_filter_catrom
225     struct image_filter_catrom
226     {
radiusimage_filter_catrom227         static double radius() { return 2.0; }
calc_weightimage_filter_catrom228         static double calc_weight(double x)
229         {
230             if(x <  1.0) return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0));
231             if(x <  2.0) return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x)));
232             return 0.;
233         }
234     };
235 
236     //---------------------------------------------image_filter_mitchell
237     class image_filter_mitchell
238     {
239         double p0, p2, p3;
240         double q0, q1, q2, q3;
241 
242     public:
243         image_filter_mitchell(double b = 1.0/3.0, double c = 1.0/3.0) :
244             p0((6.0 - 2.0 * b) / 6.0),
245             p2((-18.0 + 12.0 * b + 6.0 * c) / 6.0),
246             p3((12.0 - 9.0 * b - 6.0 * c) / 6.0),
247             q0((8.0 * b + 24.0 * c) / 6.0),
248             q1((-12.0 * b - 48.0 * c) / 6.0),
249             q2((6.0 * b + 30.0 * c) / 6.0),
250             q3((-b - 6.0 * c) / 6.0)
251         {}
252 
radius()253         static double radius() { return 2.0; }
calc_weight(double x)254         double calc_weight(double x) const
255         {
256             if(x < 1.0) return p0 + x * x * (p2 + x * p3);
257             if(x < 2.0) return q0 + x * (q1 + x * (q2 + x * q3));
258             return 0.0;
259         }
260     };
261 
262 
263     //----------------------------------------------image_filter_spline16
264     struct image_filter_spline16
265     {
radiusimage_filter_spline16266         static double radius() { return 2.0; }
calc_weightimage_filter_spline16267         static double calc_weight(double x)
268         {
269             if(x < 1.0)
270             {
271                 return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0;
272             }
273             return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1);
274         }
275     };
276 
277 
278     //---------------------------------------------image_filter_spline36
279     struct image_filter_spline36
280     {
radiusimage_filter_spline36281         static double radius() { return 3.0; }
calc_weightimage_filter_spline36282         static double calc_weight(double x)
283         {
284            if(x < 1.0)
285            {
286               return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0;
287            }
288            if(x < 2.0)
289            {
290               return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0/ 209.0) * (x-1);
291            }
292            return ((1.0/11.0 * (x-2) - 45.0/209.0) * (x-2) +  26.0/209.0) * (x-2);
293         }
294     };
295 
296 
297     //----------------------------------------------image_filter_gaussian
298     struct image_filter_gaussian
299     {
radiusimage_filter_gaussian300         static double radius() { return 2.0; }
calc_weightimage_filter_gaussian301         static double calc_weight(double x)
302         {
303             return exp(-2.0 * x * x) * sqrt(2.0 / pi);
304         }
305     };
306 
307 
308     //------------------------------------------------image_filter_bessel
309     struct image_filter_bessel
310     {
radiusimage_filter_bessel311         static double radius() { return 3.2383; }
calc_weightimage_filter_bessel312         static double calc_weight(double x)
313         {
314             return (x == 0.0) ? pi / 4.0 : besj(pi * x, 1) / (2.0 * x);
315         }
316     };
317 
318 
319     //-------------------------------------------------image_filter_sinc
320     class image_filter_sinc
321     {
322     public:
image_filter_sinc(double r)323         image_filter_sinc(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
radius()324         double radius() const { return m_radius; }
calc_weight(double x)325         double calc_weight(double x) const
326         {
327             if(x == 0.0) return 1.0;
328             x *= pi;
329             return sin(x) / x;
330         }
331     private:
332         double m_radius;
333     };
334 
335 
336     //-----------------------------------------------image_filter_lanczos
337     class image_filter_lanczos
338     {
339     public:
image_filter_lanczos(double r)340         image_filter_lanczos(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
radius()341         double radius() const { return m_radius; }
calc_weight(double x)342         double calc_weight(double x) const
343         {
344            if(x == 0.0) return 1.0;
345            if(x > m_radius) return 0.0;
346            x *= pi;
347            double xr = x / m_radius;
348            return (sin(x) / x) * (sin(xr) / xr);
349         }
350     private:
351         double m_radius;
352     };
353 
354 
355     //----------------------------------------------image_filter_blackman
356     class image_filter_blackman
357     {
358     public:
image_filter_blackman(double r)359         image_filter_blackman(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
radius()360         double radius() const { return m_radius; }
calc_weight(double x)361         double calc_weight(double x) const
362         {
363            if(x == 0.0) return 1.0;
364            if(x > m_radius) return 0.0;
365            x *= pi;
366            double xr = x / m_radius;
367            return (sin(x) / x) * (0.42 + 0.5*cos(xr) + 0.08*cos(2*xr));
368         }
369     private:
370         double m_radius;
371     };
372 
373     //------------------------------------------------image_filter_sinc36
374     class image_filter_sinc36 : public image_filter_sinc
image_filter_sinc36()375     { public: image_filter_sinc36() : image_filter_sinc(3.0){} };
376 
377     //------------------------------------------------image_filter_sinc64
378     class image_filter_sinc64 : public image_filter_sinc
image_filter_sinc64()379     { public: image_filter_sinc64() : image_filter_sinc(4.0){} };
380 
381     //-----------------------------------------------image_filter_sinc100
382     class image_filter_sinc100 : public image_filter_sinc
image_filter_sinc100()383     { public: image_filter_sinc100() : image_filter_sinc(5.0){} };
384 
385     //-----------------------------------------------image_filter_sinc144
386     class image_filter_sinc144 : public image_filter_sinc
image_filter_sinc144()387     { public: image_filter_sinc144() : image_filter_sinc(6.0){} };
388 
389     //-----------------------------------------------image_filter_sinc196
390     class image_filter_sinc196 : public image_filter_sinc
image_filter_sinc196()391     { public: image_filter_sinc196() : image_filter_sinc(7.0){} };
392 
393     //-----------------------------------------------image_filter_sinc256
394     class image_filter_sinc256 : public image_filter_sinc
image_filter_sinc256()395     { public: image_filter_sinc256() : image_filter_sinc(8.0){} };
396 
397     //---------------------------------------------image_filter_lanczos36
398     class image_filter_lanczos36 : public image_filter_lanczos
image_filter_lanczos36()399     { public: image_filter_lanczos36() : image_filter_lanczos(3.0){} };
400 
401     //---------------------------------------------image_filter_lanczos64
402     class image_filter_lanczos64 : public image_filter_lanczos
image_filter_lanczos64()403     { public: image_filter_lanczos64() : image_filter_lanczos(4.0){} };
404 
405     //--------------------------------------------image_filter_lanczos100
406     class image_filter_lanczos100 : public image_filter_lanczos
image_filter_lanczos100()407     { public: image_filter_lanczos100() : image_filter_lanczos(5.0){} };
408 
409     //--------------------------------------------image_filter_lanczos144
410     class image_filter_lanczos144 : public image_filter_lanczos
image_filter_lanczos144()411     { public: image_filter_lanczos144() : image_filter_lanczos(6.0){} };
412 
413     //--------------------------------------------image_filter_lanczos196
414     class image_filter_lanczos196 : public image_filter_lanczos
image_filter_lanczos196()415     { public: image_filter_lanczos196() : image_filter_lanczos(7.0){} };
416 
417     //--------------------------------------------image_filter_lanczos256
418     class image_filter_lanczos256 : public image_filter_lanczos
image_filter_lanczos256()419     { public: image_filter_lanczos256() : image_filter_lanczos(8.0){} };
420 
421     //--------------------------------------------image_filter_blackman36
422     class image_filter_blackman36 : public image_filter_blackman
image_filter_blackman36()423     { public: image_filter_blackman36() : image_filter_blackman(3.0){} };
424 
425     //--------------------------------------------image_filter_blackman64
426     class image_filter_blackman64 : public image_filter_blackman
image_filter_blackman64()427     { public: image_filter_blackman64() : image_filter_blackman(4.0){} };
428 
429     //-------------------------------------------image_filter_blackman100
430     class image_filter_blackman100 : public image_filter_blackman
image_filter_blackman100()431     { public: image_filter_blackman100() : image_filter_blackman(5.0){} };
432 
433     //-------------------------------------------image_filter_blackman144
434     class image_filter_blackman144 : public image_filter_blackman
image_filter_blackman144()435     { public: image_filter_blackman144() : image_filter_blackman(6.0){} };
436 
437     //-------------------------------------------image_filter_blackman196
438     class image_filter_blackman196 : public image_filter_blackman
image_filter_blackman196()439     { public: image_filter_blackman196() : image_filter_blackman(7.0){} };
440 
441     //-------------------------------------------image_filter_blackman256
442     class image_filter_blackman256 : public image_filter_blackman
image_filter_blackman256()443     { public: image_filter_blackman256() : image_filter_blackman(8.0){} };
444 
445 
446 }
447 
448 #endif
449