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