1{mac_copy:spheres.bmp}
2//
3// AggPas 2.4 RM3 Demo application
4// Note: Press F1 key on run to see more info about this demo
5//
6// Paths: src;src\ctrl;src\svg;src\util;src\platform\win;expat-wrap
7//
8program
9 image_filters ;
10
11uses
12 SysUtils ,
13
14 agg_basics ,
15 agg_platform_support ,
16
17 agg_color ,
18 agg_pixfmt ,
19 agg_pixfmt_rgb ,
20
21 agg_ctrl ,
22 agg_slider_ctrl ,
23 agg_rbox_ctrl ,
24 agg_cbox_ctrl ,
25
26 agg_rendering_buffer ,
27 agg_renderer_base ,
28 agg_renderer_scanline ,
29 agg_rasterizer_scanline_aa ,
30 agg_scanline ,
31 agg_scanline_u ,
32 agg_scanline_p ,
33 agg_render_scanlines ,
34
35 agg_ellipse ,
36 agg_trans_affine ,
37 agg_conv_transform ,
38 agg_conv_stroke ,
39 agg_span_allocator ,
40 agg_span_interpolator_linear ,
41 agg_span_image_filter ,
42 agg_span_image_filter_rgb ,
43 agg_image_filters ,
44 agg_gsv_text ,
45 file_utils_ ;
46
47{$I agg_mode.inc }
48
49const
50 flip_y = true;
51
52 pixfmt     : define_pixfmt = pixfmt_bgr24;
53 pixfmt_pre : define_pixfmt = pixfmt_bgr24_pre;
54
55type
56 the_application = object(platform_support )
57   m_radius      ,
58   m_step        : slider_ctrl;
59   m_filters     : rbox_ctrl;
60   m_normalize   ,
61   m_run         ,
62   m_single_step ,
63   m_refresh     : cbox_ctrl;
64
65   m_cur_angle  : double;
66   m_cur_filter ,
67   m_num_steps  : int;
68
69   m_num_pix ,
70   m_time1   ,
71   m_time2   : double;
72
73   constructor Construct(format_ : pix_format_e; flip_y_ : boolean );
74   destructor  Destruct;
75
76   procedure on_draw; virtual;
77
78   procedure transform_image(angle : double );
79
80   procedure on_ctrl_change; virtual;
81   procedure on_idle; virtual;
82
83   procedure on_key(x ,y : int; key ,flags : unsigned ); virtual;
84
85  end;
86
87{ CONSTRUCT }
88constructor the_application.Construct;
89var
90 rgba : aggclr;
91
92begin
93 inherited Construct(format_ ,flip_y_ );
94
95 m_step.Construct       (115 ,5 ,400 ,11 ,not flip_y_ );
96 m_radius.Construct     (115 ,5 + 15 ,400 ,11 + 15 ,not flip_y_ );
97 m_filters.Construct    (0.0 ,0.0 ,110.0 ,210.0 ,not flip_y_ );
98 m_normalize.Construct  (8.0 ,215.0 ,'Normalize Filter' ,not flip_y_ );
99 m_run.Construct        (8.0 ,245.0 ,'RUN Test!' ,not flip_y_ );
100 m_single_step.Construct(8.0 ,230.0 ,'Single Step' ,not flip_y_ );
101 m_refresh.Construct    (8.0 ,265.0 ,'Refresh' ,not flip_y_ );
102
103 m_cur_angle :=0.0;
104 m_cur_filter:=1;
105 m_num_steps :=0;
106
107 m_num_pix:=0.0;
108 m_time1  :=0;
109 m_time2  :=0;
110
111 add_ctrl(@m_radius );
112 add_ctrl(@m_step );
113 add_ctrl(@m_filters );
114 add_ctrl(@m_run );
115 add_ctrl(@m_single_step );
116 add_ctrl(@m_normalize );
117 add_ctrl(@m_refresh );
118
119 m_run.text_size_        (7.5 );
120 m_single_step.text_size_(7.5 );
121 m_normalize.text_size_  (7.5 );
122 m_refresh.text_size_    (7.5 );
123 m_normalize.status_    (true );
124
125 m_radius.label_('Filter Radius=%.3f' );
126 m_step.label_  ('Step=%3.2f' );
127 m_radius.range_(2.0 ,8.0 );
128 m_radius.value_(4.0 );
129 m_step.range_  (1.0 ,10.0 );
130 m_step.value_  (5.0 );
131
132 m_filters.add_item ('simple (NN)' );
133 m_filters.add_item ('bilinear' );
134 m_filters.add_item ('bicubic' );
135 m_filters.add_item ('spline16' );
136 m_filters.add_item ('spline36' );
137 m_filters.add_item ('hanning' );
138 m_filters.add_item ('hamming' );
139 m_filters.add_item ('hermite' );
140 m_filters.add_item ('kaiser' );
141 m_filters.add_item ('quadric' );
142 m_filters.add_item ('catrom' );
143 m_filters.add_item ('gaussian' );
144 m_filters.add_item ('bessel' );
145 m_filters.add_item ('mitchell' );
146 m_filters.add_item ('sinc' );
147 m_filters.add_item ('lanczos' );
148 m_filters.add_item ('blackman' );
149 m_filters.cur_item_(1 );
150
151 m_filters.border_width_    (0 ,0 );
152 rgba.ConstrDbl             (0.0 ,0.0 ,0.0 ,0.1 );
153 m_filters.background_color_(@rgba );
154 m_filters.text_size_       (6.0 );
155 m_filters.text_thickness_  (0.85 );
156
157end;
158
159{ DESTRUCT }
160destructor the_application.Destruct;
161begin
162 inherited Destruct;
163
164 m_step.Destruct;
165 m_radius.Destruct;
166 m_filters.Destruct;
167 m_normalize.Destruct;
168 m_run.Destruct;
169 m_single_step.Destruct;
170 m_refresh.Destruct;
171
172end;
173
174{ ON_DRAW }
175procedure the_application.on_draw;
176var
177 pixf : pixel_formats;
178 rgba : aggclr;
179
180 rb : renderer_base;
181 rs : renderer_scanline_aa_solid;
182
183 ras : rasterizer_scanline_aa;
184 sl  : scanline_p8;
185
186 t  : gsv_text;
187 pt : conv_stroke;
188
189 buf : array[0..63 ] of char;
190
191begin
192// Initialize structures
193 pixfmt(pixf ,rbuf_window );
194
195 rb.Construct(@pixf );
196 rs.Construct(@rb );
197
198 rgba.ConstrDbl(1.0 ,1.0 ,1.0 );
199 rb.clear      (@rgba );
200 rb.copy_from  (rbuf_img(0 ) ,NIL ,110 ,35 );
201
202 ras.Construct;
203 sl.Construct;
204
205// Text
206 sprintf(@buf[0 ] ,'NSteps=%d' ,m_num_steps );
207
208 t.Construct;
209 t.start_point_(10.0 ,295.0 );
210 t.size_       (10.0 );
211 t.text_       (@buf[0 ] );
212
213 pt.Construct(@t );
214 pt.width_   (1.5 );
215
216 ras.add_path    (@pt );
217 rgba.ConstrDbl  (0 ,0 ,0 );
218 rs.color_       (@rgba );
219 render_scanlines(@ras ,@sl ,@rs );
220
221// Time
222 if (m_time1 <> m_time2 ) and
223    (m_num_pix > 0.0 ) then
224  begin
225   sprintf(@buf[0 ] ,'%3.2f Kpix/sec' ,m_num_pix / (m_time2 - m_time1 ) );
226
227   t.start_point_  (10.0 ,310.0 );
228   t.text_         (@buf[0 ] );
229   ras.add_path    (@pt );
230   render_scanlines(@ras ,@sl ,@rs );
231
232  end;
233
234// Render the controls
235 if m_filters._cur_item >= 14 then
236  render_ctrl(@ras ,@sl ,@rs ,@m_radius );
237
238 render_ctrl(@ras ,@sl ,@rs ,@m_step );
239 render_ctrl(@ras ,@sl ,@rs ,@m_filters );
240 render_ctrl(@ras ,@sl ,@rs ,@m_run );
241 render_ctrl(@ras ,@sl ,@rs ,@m_normalize );
242 render_ctrl(@ras ,@sl ,@rs ,@m_single_step );
243 render_ctrl(@ras ,@sl ,@rs ,@m_refresh );
244
245// Free AGG resources
246 ras.Destruct;
247 sl.Destruct;
248
249 t.Destruct;
250 pt.Destruct;
251
252end;
253
254{ TRANSFORM_IMAGE }
255procedure the_application.transform_image;
256var
257 width_ ,height_ : double;
258 pixf ,pixf_pre  : pixel_formats;
259
260 rb ,rb_pre : renderer_base;
261
262 rgba : aggclr;
263
264 ras : rasterizer_scanline_aa;
265 ell : ellipse;
266
267 sl : scanline_u8;
268 sa : span_allocator;
269 tr : conv_transform;
270 fi : image_filter_base_ptr;
271 sg : span_image_filter_ptr;
272 ri : renderer_scanline_aa;
273
274 filter : image_filter_lut;
275
276 interpolator : span_interpolator_linear;
277
278 src_mtx ,img_mtx : trans_affine;
279
280 tat : trans_affine_translation;
281 tar : trans_affine_rotation;
282
283 r : double;
284
285 norm : boolean;
286
287begin
288 fi:=NIL;
289 sg:=NIL;
290
291// Initialize
292 width_ :=rbuf_img(0 )._width;
293 height_:=rbuf_img(0 )._height;
294
295 pixfmt    (pixf ,rbuf_img(0 ) );
296 pixfmt_pre(pixf_pre , rbuf_img(0 ) );
297
298 rb.Construct    (@pixf );
299 rb_pre.Construct(@pixf_pre );
300
301 rgba.ConstrDbl(1.0 ,1.0 ,1.0 );
302 rb.clear      (@rgba );
303
304 ras.Construct;
305 sl.Construct;
306 sa.Construct;
307
308 src_mtx.Construct;
309
310 tat.Construct(-width_ / 2.0 ,-height_ / 2.0 ); src_mtx.multiply(@tat );
311 tar.Construct(angle * pi / 180.0 ); src_mtx.multiply(@tar );
312 tat.Construct(width_ / 2.0 ,height_ / 2.0 ); src_mtx.multiply(@tat );
313
314 img_mtx.Construct;
315
316 img_mtx:=src_mtx;
317
318 img_mtx.invert;
319
320 r:=width_;
321
322 if height_ < r then
323  r:=height_;
324
325 r:=r * 0.5;
326 r:=r - 4.0;
327
328 ell.Construct(width_ / 2.0 ,height_ / 2.0 ,r ,r ,200 );
329 tr.Construct (@ell ,@src_mtx );
330
331 m_num_pix:=m_num_pix + (r * r * pi );
332
333 interpolator.Construct(@img_mtx );
334
335 filter.Construct;
336
337 norm:=m_normalize._status;
338
339 rgba.ConstrDbl(0 ,0 ,0 ,0 );
340
341// Render
342 case m_filters._cur_item of
343  0 :
344   begin
345    sg:=new(
346     span_image_filter_rgb_nn_ptr ,
347     Construct(
348      @sa ,rbuf_img(1 ) ,@rgba ,@interpolator ,bgr_order ) );
349
350    ri.Construct    (@rb_pre ,sg );
351    ras.add_path    (@tr );
352    render_scanlines(@ras ,@sl ,@ri );
353
354   end;
355
356  1 :
357   begin
358    sg:=new(
359     span_image_filter_rgb_bilinear_ptr ,
360     Construct(
361      @sa ,rbuf_img(1) ,@rgba ,@interpolator ,bgr_order ) );
362
363    ri.Construct    (@rb_pre ,sg );
364    ras.add_path    (@tr );
365    render_scanlines(@ras ,@sl ,@ri );
366
367   end;
368
369  5 ,6 ,7 :
370   begin
371    case m_filters._cur_item of
372     5 : fi:=new(image_filter_hanning_ptr ,Construct );
373     6 : fi:=new(image_filter_hamming_ptr ,Construct );
374     7 : fi:=new(image_filter_hermite_ptr ,Construct );
375
376    end;
377
378    filter.calculate(fi ,norm );
379
380    sg:=new(
381     span_image_filter_rgb_2x2_ptr ,
382     Construct(
383      @sa ,rbuf_img(1) ,@rgba ,@interpolator ,@filter ,bgr_order ) );
384
385    ri.Construct    (@rb_pre ,sg );
386    ras.add_path    (@tr );
387    render_scanlines(@ras ,@sl ,@ri );
388
389   end;
390
391  2 ,3 ,4 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 :
392   begin
393    case m_filters._cur_item of
394     2  : fi:=new(image_filter_bicubic_ptr ,Construct );
395     3  : fi:=new(image_filter_spline16_ptr ,Construct );
396     4  : fi:=new(image_filter_spline36_ptr ,Construct );
397     8  : fi:=new(image_filter_kaiser_ptr ,Construct );
398     9  : fi:=new(image_filter_quadric_ptr ,Construct );
399     10 : fi:=new(image_filter_catrom_ptr ,Construct );
400     11 : fi:=new(image_filter_gaussian_ptr ,Construct );
401     12 : fi:=new(image_filter_bessel_ptr ,Construct );
402     13 : fi:=new(image_filter_mitchell_ptr ,Construct );
403     14 : fi:=new(image_filter_sinc_ptr ,Construct(m_radius._value ) );
404     15 : fi:=new(image_filter_lanczos_ptr ,Construct(m_radius._value ) );
405     16 : fi:=new(image_filter_blackman_ptr ,Construct(m_radius._value ) );
406
407    end;
408
409    filter.calculate(fi ,norm );
410
411    sg:=new(
412     span_image_filter_rgb_ptr ,
413     Construct(
414      @sa ,rbuf_img(1) ,@rgba ,@interpolator ,@filter ,bgr_order ) );
415
416    ri.Construct    (@rb_pre ,sg );
417    ras.add_path    (@tr );
418    render_scanlines(@ras ,@sl ,@ri );
419
420   end;
421
422 end;
423
424// Free
425 ras.Destruct;
426 sl.Destruct;
427 sa.Destruct;
428
429 filter.Destruct;
430
431 if sg <> NIL then
432  dispose(sg ,Destruct );
433
434 if fi <> NIL then
435  dispose(fi );
436
437end;
438
439{ ON_CTRL_CHANGE }
440procedure the_application.on_ctrl_change;
441begin
442 if m_single_step._status then
443  begin
444   m_cur_angle:=m_cur_angle + m_step._value;
445
446   copy_img_to_img(1 ,0 );
447   transform_image(m_step._value );
448
449   inc(m_num_steps );
450
451   force_redraw;
452
453   m_single_step.status_(false );
454
455  end;
456
457 if m_run._status then
458  begin
459   start_timer;
460
461   m_time1:=elapsed_time;
462   m_time2:=m_time1;
463
464   m_num_pix:=0.0;
465
466   wait_mode_(false );
467
468  end;
469
470 if m_refresh._status or
471    (m_filters._cur_item <> m_cur_filter ) then
472  begin
473   start_timer;
474
475   m_time1:=0;
476   m_time2:=0;
477
478   m_num_pix  :=0.0;
479   m_cur_angle:=0.0;
480
481   copy_img_to_img(1 ,2 );
482   transform_image(0.0 );
483
484   m_refresh.status_(false );
485
486   m_cur_filter:=m_filters._cur_item;
487   m_num_steps :=0;
488
489   force_redraw;
490
491  end;
492
493end;
494
495{ ON_IDLE }
496procedure the_application.on_idle;
497begin
498 if m_run._status then
499  begin
500   if m_cur_angle < 360.0 then
501    begin
502     m_cur_angle:=m_cur_angle + m_step._value;
503
504     copy_img_to_img(1 ,0 );
505     start_timer;
506     transform_image(m_step._value );
507
508     m_time2:=m_time2 + elapsed_time;
509
510     inc(m_num_steps );
511
512    end
513   else
514    begin
515     m_cur_angle:=0.0;
516
517     wait_mode_   (true );
518     m_run.status_(false );
519
520    end;
521
522   force_redraw;
523
524  end
525 else
526  wait_mode_(true );
527
528end;
529
530{ ON_KEY }
531procedure the_application.on_key;
532begin
533 if key = key_f1 then
534  message_(
535   'The image transformer algorithm can work with different interpolation filters, '#13 +
536   'such as Bilinear, Bicubic, Sinc, Blackman. The example demonstrates the difference '#13 +
537   'in quality between different filters. When switch the "Run Test" on, the image '#13 +
538   'starts rotating. But at each step there is the previously rotated image taken, '#13 +
539   'so the quality degrades. This degradation as well as the performance depend on '#13 +
540   'the type of the interpolation filter.' +
541   #13#13'Note: F2 key saves current "screenshot" file in this demo''s directory.  ' );
542
543end;
544
545VAR
546 app : the_application;
547 buf : array [0..255 ] of char;
548 ext : string[10 ];
549
550 img_name ,p ,n ,x : shortstring;
551
552 w ,h : unsigned;
553
554BEGIN
555 app.Construct(pix_format_bgr24 ,flip_y );
556 app.caption_ ('Image transformation filters comparison (F1-Help)' );
557
558 img_name:='spheres';
559
560{$IFDEF WIN32 }
561 if ParamCount > 0 then
562  begin
563   spread_name(ParamStr(1 ) ,p ,n ,x );
564
565   img_name:=fold_name(p ,n ,'' );
566
567  end;
568
569{$ENDIF }
570
571 if not app.load_img(0 ,img_name ) then
572  begin
573   img_name:=img_name + #0;
574   ext     :=app._img_ext + #0;
575
576   if img_name = 'spheres'#0 then
577    begin
578     sprintf(@buf[0 ]             ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) );
579     sprintf(@buf[StrLen(@buf ) ] ,'%s. '#13'Download http://www.antigrain.com/' ,ptrcomp(@ext[1 ] ) );
580     sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@img_name[1 ] ) );
581     sprintf(@buf[StrLen(@buf ) ] ,'%s'#13'or copy it from another directory if available.' ,ptrcomp(@ext[1 ] ) );
582
583    end
584   else
585    begin
586     sprintf(@buf[0 ]             ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) );
587     sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@ext[1 ] ) );
588
589    end;
590
591   app.message_(@buf[0 ] );
592
593  end
594 else
595  begin
596   app.copy_img_to_img(1 ,0 );
597   app.copy_img_to_img(2 ,0 );
598   app.transform_image(0.0 );
599
600   w:=app.rbuf_img(0 )._width + 110;
601   h:=app.rbuf_img(0 )._height + 40;
602
603   if w < 305 then
604    w:=305;
605
606   if h < 325 then
607    h:=325;
608
609   if app.init(w ,h ,0 ) then
610    app.run;
611
612  end;
613
614 app.Destruct;
615
616END.
617