1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <time.h>
5 #include "agg_rendering_buffer.h"
6 #include "agg_rasterizer_scanline_aa.h"
7 #include "agg_ellipse.h"
8 #include "agg_trans_affine.h"
9 #include "agg_conv_transform.h"
10 #include "agg_conv_stroke.h"
11 #include "agg_pixfmt_rgb.h"
12 #include "agg_scanline_p.h"
13 #include "agg_renderer_scanline.h"
14 #include "agg_image_filters.h"
15 #include "ctrl/agg_slider_ctrl.h"
16 #include "ctrl/agg_rbox_ctrl.h"
17 #include "ctrl/agg_cbox_ctrl.h"
18 #include "platform/agg_platform_support.h"
19 
20 
21 enum flip_y_e { flip_y = true };
22 
23 
24 struct filter_base
25 {
26     virtual double radius() const = 0;
27     virtual void set_radius(double r) = 0;
28     virtual double calc_weight(double x) const = 0;
29 };
30 
31 
32 template<class Filter> struct image_filter_const_radius_adaptor : filter_base
33 {
radiusimage_filter_const_radius_adaptor34     virtual double radius() const { return m_filter.radius(); }
set_radiusimage_filter_const_radius_adaptor35     virtual void set_radius(double r) {}
calc_weightimage_filter_const_radius_adaptor36     virtual double calc_weight(double x) const { return m_filter.calc_weight(fabs(x)); }
37     Filter m_filter;
38 };
39 
40 
41 template<class Filter> struct image_filter_variable_radius_adaptor : filter_base
42 {
radiusimage_filter_variable_radius_adaptor43     virtual double radius() const { return m_filter.radius(); }
calc_weightimage_filter_variable_radius_adaptor44     virtual double calc_weight(double x) const { return m_filter.calc_weight(fabs(x)); }
set_radiusimage_filter_variable_radius_adaptor45     virtual void set_radius(double r) { m_filter = Filter(r); }
image_filter_variable_radius_adaptorimage_filter_variable_radius_adaptor46     image_filter_variable_radius_adaptor() : m_filter(2.0) {}
47     Filter m_filter;
48 };
49 
50 
51 
52 class the_application : public agg::platform_support
53 {
54     agg::slider_ctrl<agg::rgba>  m_radius;
55     agg::cbox_ctrl<agg::rgba>  m_bilinear;
56     agg::cbox_ctrl<agg::rgba>  m_bicubic;
57     agg::cbox_ctrl<agg::rgba>  m_spline16;
58     agg::cbox_ctrl<agg::rgba>  m_spline36;
59     agg::cbox_ctrl<agg::rgba>  m_hanning;
60     agg::cbox_ctrl<agg::rgba>  m_hamming;
61     agg::cbox_ctrl<agg::rgba>  m_hermite;
62     agg::cbox_ctrl<agg::rgba>  m_kaiser;
63     agg::cbox_ctrl<agg::rgba>  m_quadric;
64     agg::cbox_ctrl<agg::rgba>  m_catrom;
65     agg::cbox_ctrl<agg::rgba>  m_gaussian;
66     agg::cbox_ctrl<agg::rgba>  m_bessel;
67     agg::cbox_ctrl<agg::rgba>  m_mitchell;
68     agg::cbox_ctrl<agg::rgba>  m_sinc;
69     agg::cbox_ctrl<agg::rgba>  m_lanczos;
70     agg::cbox_ctrl<agg::rgba>  m_blackman;
71     agg::cbox_ctrl<agg::rgba>* m_filters[32];
72 
73     image_filter_const_radius_adaptor<agg::image_filter_bilinear>    m_filter_bilinear;
74     image_filter_const_radius_adaptor<agg::image_filter_bicubic>     m_filter_bicubic;
75     image_filter_const_radius_adaptor<agg::image_filter_spline16>    m_filter_spline16;
76     image_filter_const_radius_adaptor<agg::image_filter_spline36>    m_filter_spline36;
77     image_filter_const_radius_adaptor<agg::image_filter_hanning>     m_filter_hanning;
78     image_filter_const_radius_adaptor<agg::image_filter_hamming>     m_filter_hamming;
79     image_filter_const_radius_adaptor<agg::image_filter_hermite>     m_filter_hermite;
80     image_filter_const_radius_adaptor<agg::image_filter_kaiser>      m_filter_kaiser;
81     image_filter_const_radius_adaptor<agg::image_filter_quadric>     m_filter_quadric;
82     image_filter_const_radius_adaptor<agg::image_filter_catrom>      m_filter_catrom;
83     image_filter_const_radius_adaptor<agg::image_filter_gaussian>    m_filter_gaussian;
84     image_filter_const_radius_adaptor<agg::image_filter_bessel>      m_filter_bessel;
85     image_filter_const_radius_adaptor<agg::image_filter_mitchell>    m_filter_mitchell;
86     image_filter_variable_radius_adaptor<agg::image_filter_sinc>     m_filter_sinc;
87     image_filter_variable_radius_adaptor<agg::image_filter_lanczos>  m_filter_lanczos;
88     image_filter_variable_radius_adaptor<agg::image_filter_blackman> m_filter_blackman;
89 
90     filter_base* m_filter_func[32];
91     unsigned     m_num_filters;
92 
93 
94 public:
the_application(agg::pix_format_e format,bool flip_y)95     the_application(agg::pix_format_e format, bool flip_y) :
96         agg::platform_support(format, flip_y),
97         m_radius     (5.0, 5.0, 780-5, 10.0,     !flip_y),
98         m_bilinear (8.0, 30.0+15*0,  "bilinear", !flip_y),
99         m_bicubic  (8.0, 30.0+15*1,  "bicubic ", !flip_y),
100         m_spline16 (8.0, 30.0+15*2,  "spline16", !flip_y),
101         m_spline36 (8.0, 30.0+15*3,  "spline36", !flip_y),
102         m_hanning  (8.0, 30.0+15*4,  "hanning ", !flip_y),
103         m_hamming  (8.0, 30.0+15*5,  "hamming ", !flip_y),
104         m_hermite  (8.0, 30.0+15*6,  "hermite ", !flip_y),
105         m_kaiser   (8.0, 30.0+15*7,  "kaiser  ", !flip_y),
106         m_quadric  (8.0, 30.0+15*8,  "quadric ", !flip_y),
107         m_catrom   (8.0, 30.0+15*9,  "catrom  ", !flip_y),
108         m_gaussian (8.0, 30.0+15*10, "gaussian", !flip_y),
109         m_bessel   (8.0, 30.0+15*11, "bessel  ", !flip_y),
110         m_mitchell (8.0, 30.0+15*12, "mitchell", !flip_y),
111         m_sinc     (8.0, 30.0+15*13, "sinc    ", !flip_y),
112         m_lanczos  (8.0, 30.0+15*14, "lanczos ", !flip_y),
113         m_blackman (8.0, 30.0+15*15, "blackman", !flip_y),
114         m_num_filters(0)
115     {
116         m_filters[m_num_filters++] = &m_bilinear;
117         m_filters[m_num_filters++] = &m_bicubic;
118         m_filters[m_num_filters++] = &m_spline16;
119         m_filters[m_num_filters++] = &m_spline36;
120         m_filters[m_num_filters++] = &m_hanning;
121         m_filters[m_num_filters++] = &m_hamming;
122         m_filters[m_num_filters++] = &m_hermite;
123         m_filters[m_num_filters++] = &m_kaiser;
124         m_filters[m_num_filters++] = &m_quadric;
125         m_filters[m_num_filters++] = &m_catrom;
126         m_filters[m_num_filters++] = &m_gaussian;
127         m_filters[m_num_filters++] = &m_bessel;
128         m_filters[m_num_filters++] = &m_mitchell;
129         m_filters[m_num_filters++] = &m_sinc;
130         m_filters[m_num_filters++] = &m_lanczos;
131         m_filters[m_num_filters++] = &m_blackman;
132 
133         unsigned i = 0;
134 
135         m_filter_func[i++] = &m_filter_bilinear;
136         m_filter_func[i++] = &m_filter_bicubic;
137         m_filter_func[i++] = &m_filter_spline16;
138         m_filter_func[i++] = &m_filter_spline36;
139         m_filter_func[i++] = &m_filter_hanning;
140         m_filter_func[i++] = &m_filter_hamming;
141         m_filter_func[i++] = &m_filter_hermite;
142         m_filter_func[i++] = &m_filter_kaiser;
143         m_filter_func[i++] = &m_filter_quadric;
144         m_filter_func[i++] = &m_filter_catrom;
145         m_filter_func[i++] = &m_filter_gaussian;
146         m_filter_func[i++] = &m_filter_bessel;
147         m_filter_func[i++] = &m_filter_mitchell;
148         m_filter_func[i++] = &m_filter_sinc;
149         m_filter_func[i++] = &m_filter_lanczos;
150         m_filter_func[i++] = &m_filter_blackman;
151         for(i = 0; i < m_num_filters; i++)
152         {
153             add_ctrl(*m_filters[i]);
154         }
155 
156         m_radius.range(2.0, 8.0);
157         m_radius.value(4.0);
158         m_radius.label("Radius=%.3f");
159         add_ctrl(m_radius);
160     }
161 
~the_application()162     virtual ~the_application()
163     {
164     }
165 
on_draw()166     virtual void on_draw()
167     {
168         typedef agg::pixfmt_bgr24 pixfmt;
169         typedef agg::renderer_base<pixfmt> renderer_base;
170         typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
171 
172         pixfmt pixf(rbuf_window());
173         renderer_base rb(pixf);
174         renderer_solid rs(rb);
175 
176         rb.clear(agg::rgba(1.0, 1.0, 1.0));
177         agg::rasterizer_scanline_aa<> ras;
178         agg::scanline_p8 sl;
179 
180         double x_start = 125.0;
181         double x_end   = initial_width() - 15.0;
182         double y_start = 10.0;
183         double y_end   = initial_height() - 10.0;
184         double x_center = (x_start + x_end) / 2;
185 
186         unsigned i;
187 
188         agg::path_storage p;
189         agg::conv_stroke<agg::path_storage> pl(p);
190         agg::conv_transform<agg::conv_stroke<agg::path_storage> > tr(pl, trans_affine_resizing());
191 
192         for(i = 0; i <= 16; i++)
193         {
194             double x = x_start + (x_end - x_start) * i / 16.0;
195             p.remove_all();
196             p.move_to(x+0.5, y_start);
197             p.line_to(x+0.5, y_end);
198             ras.add_path(tr);
199             rs.color(agg::rgba8(0, 0, 0, i == 8 ? 255 : 100));
200             agg::render_scanlines(ras, sl, rs);
201         }
202 
203         double ys = y_start + (y_end - y_start) / 6.0;
204 
205         p.remove_all();
206         p.move_to(x_start, ys);
207         p.line_to(x_end,   ys);
208         ras.add_path(tr);
209         rs.color(agg::rgba8(0, 0, 0));
210         agg::render_scanlines(ras, sl, rs);
211 
212 
213         pl.width(1.0);
214 
215         for(i = 0; i < m_num_filters; i++)
216         {
217             if(m_filters[i]->status())
218             {
219                 m_filter_func[i]->set_radius(m_radius.value());
220                 unsigned j;
221 
222                 double radius = m_filter_func[i]->radius();
223                 unsigned n = unsigned(radius * 256 * 2);
224                 double dy = y_end - ys;
225 
226                 double xs = (x_end + x_start)/2.0 - (radius * (x_end - x_start) / 16.0);
227                 double dx = (x_end - x_start) * radius / 8.0;
228 
229                 p.remove_all();
230                 p.move_to(xs+0.5, ys + dy * m_filter_func[i]->calc_weight(-radius));
231                 for(j = 1; j < n; j++)
232                 {
233                     p.line_to(xs + dx * j / n + 0.5,
234                               ys + dy * m_filter_func[i]->calc_weight(j / 256.0 - radius));
235                 }
236                 ras.add_path(tr);
237                 rs.color(agg::rgba8(100, 0, 0));
238                 agg::render_scanlines(ras, sl, rs);
239 
240                 p.remove_all();
241                 unsigned xint;
242                 int ir = int(ceil(radius) + 0.1);
243 
244                 for(xint = 0; xint < 256; xint++)
245                 {
246                     int xfract;
247                     double sum = 0;
248                     for(xfract = -ir; xfract < ir; xfract++)
249                     {
250                         double xf = xint/256.0 + xfract;
251                         if(xf >= -radius || xf <= radius)
252                         {
253                             sum += m_filter_func[i]->calc_weight(xf);
254                         }
255                     }
256 
257                     double x = x_center + ((-128.0 + xint) / 128.0) * radius * (x_end - x_start) / 16.0;
258                     double y = ys + sum * 256 - 256;
259 
260                     if(xint == 0) p.move_to(x, y);
261                     else          p.line_to(x, y);
262                 }
263                 ras.add_path(tr);
264                 rs.color(agg::rgba8(0, 100, 0));
265                 agg::render_scanlines(ras, sl, rs);
266 
267                 agg::image_filter_lut normalized(*m_filter_func[i]);
268                 const agg::int16* weights = normalized.weight_array();
269 
270                 xs = (x_end + x_start)/2.0 - (normalized.diameter() * (x_end - x_start) / 32.0);
271                 unsigned nn = normalized.diameter() * 256;
272                 p.remove_all();
273                 p.move_to(xs+0.5, ys + dy * weights[0] / agg::image_filter_scale);
274                 for(j = 1; j < nn; j++)
275                 {
276                     p.line_to(xs + dx * j / n + 0.5,
277                               ys + dy * weights[j] / agg::image_filter_scale);
278                 }
279                 ras.add_path(tr);
280                 rs.color(agg::rgba8(0, 0, 100, 255));
281                 agg::render_scanlines(ras, sl, rs);
282             }
283         }
284 
285         for(i = 0; i < m_num_filters; i++)
286         {
287             agg::render_ctrl(ras, sl, rb, *m_filters[i]);
288         }
289         if(m_sinc.status() || m_lanczos.status() || m_blackman.status())
290         {
291             agg::render_ctrl(ras, sl, rb, m_radius);
292         }
293     }
294 };
295 
296 
297 
298 
299 
300 
301 
agg_main(int argc,char * argv[])302 int agg_main(int argc, char* argv[])
303 {
304     the_application app(agg::pix_format_bgr24, flip_y);
305     app.caption("Image filters' shape comparison");
306 
307     if(app.init(780, 300, agg::window_resize))
308     {
309         return app.run();
310     }
311     return 0;
312 }
313 
314 
315