1Image_new_item = class 2 Menupullright "_New" "make new things" { 3 Image_black_item = class 4 Menuaction "_Image" "make a new image" { 5 format_names = [ 6 "8-bit unsigned int - UCHAR", // 0 7 "8-bit signed int - CHAR", // 1 8 "16-bit unsigned int - USHORT", // 2 9 "16-bit signed int - SHORT", // 3 10 "32-bit unsigned int - UINT", // 4 11 "32-bit signed int - INT", // 5 12 "32-bit float - FLOAT", // 6 13 "64-bit complex - COMPLEX", // 7 14 "64-bit float - DOUBLE", // 8 15 "128-bit complex - DPCOMPLEX" // 9 16 ]; 17 18 action = class 19 Image _result { 20 _vislevel = 3; 21 22 nwidth = Expression "Image width (pixels)" 64; 23 nheight = Expression "Image height (pixels)" 64; 24 nbands = Expression "Image bands" 1; 25 format_option = Option "Image format" format_names 0; 26 type_option = Option_enum 27 Image_type.type_names "Image type" "B_W"; 28 pixel = Expression "Pixel value" 0; 29 30 _result 31 = image_new (to_real nwidth) (to_real nheight) (to_real nbands) 32 (to_real format_option) Image_coding.NOCODING 33 type_option.value_thing pixel.expr 0 0; 34 } 35 } 36 37 Image_new_from_image_item = class 38 Menuaction "_From Image" "make a new image based on image x" { 39 action x = class 40 Image _result { 41 _vislevel = 3; 42 43 pixel = Expression "Pixel value" 0; 44 45 _result 46 = image_new x.width x.height x.bands 47 x.format x.coding x.type pixel.expr x.xoffset x.yoffset; 48 } 49 } 50 51 Image_region_item = class 52 Menupullright "_Region on Image" "make a new region on an image" { 53 Region_item = class 54 Menuaction "_Region" "make a region on an image" { 55 action image = scope.Region_relative image 0.25 0.25 0.5 0.5; 56 } 57 58 Mark_item = class 59 Menuaction "_Point" "make a point on an image" { 60 action image = scope.Mark_relative image 0.5 0.5; 61 } 62 63 Arrow_item = class 64 Menuaction "_Arrow" "make an arrow on an image" { 65 action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; 66 } 67 68 HGuide_item = class 69 Menuaction "_Horizontal Guide" 70 "make a horizontal guide on an image" { 71 action image = scope.HGuide image 0.5; 72 } 73 74 VGuide_item = class 75 Menuaction "_Vertical Guide" "make a vertical guide on an image" { 76 action image = scope.VGuide image 0.5; 77 } 78 79 sep1 = Menuseparator; 80 81 Move_item = class 82 Menuaction "From Region" 83 "new region on image using existing region as a guide" { 84 action a b 85 = map_binary process a b 86 { 87 process a b 88 = x.Region target x.left x.top x.width x.height, 89 is_Region x 90 = x.Arrow target x.left x.top x.width x.height, 91 is_Arrow x 92 = error "bad arguments to region-from-region" 93 { 94 // prefer image then region 95 compare a b 96 = false, 97 !is_Image a && is_Image b 98 = false, 99 is_Region a && !is_Region b 100 = true; 101 102 [target, x] = sortc compare [a, b]; 103 } 104 } 105 } 106 } 107} 108 109Image_convert_to_image_item = class 110 Menuaction "Con_vert to Image" "convert anything to an image" { 111 action x = to_image x; 112} 113 114Image_number_format_item = class 115 Menupullright "_Format" "convert numeric format" { 116 117 U8_item = class 118 Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { 119 action x = map_unary cast_unsigned_char x; 120 } 121 122 U16_item = class 123 Menuaction "1_6 bit unsigned" 124 "convert to unsigned 16 bit [0, 65535]" { 125 action x = map_unary cast_unsigned_short x; 126 } 127 128 U32_item = class 129 Menuaction "_32 bit unsigned" 130 "convert to unsigned 32 bit [0, 4294967295]" { 131 action x = map_unary cast_unsigned_int x; 132 } 133 134 sep1 = Menuseparator; 135 136 S8_item = class 137 Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { 138 action x = map_unary cast_signed_char x; 139 } 140 141 S16_item = class 142 Menuaction "16 b_it signed" 143 "convert to signed 16 bit [-32768, 32767]" { 144 action x = map_unary cast_signed_short x; 145 } 146 147 S32_item = class 148 Menuaction "32 bi_t signed" 149 "convert to signed 32 bit [-2147483648, 2147483647]" { 150 action x = map_unary cast_signed_int x; 151 } 152 153 sep2 = Menuseparator; 154 155 Float_item = class 156 Menuaction "_Single precision float" 157 "convert to IEEE 32 bit float" { 158 action x = map_unary cast_float x; 159 } 160 161 Double_item = class 162 Menuaction "_Double precision float" 163 "convert to IEEE 64 bit float" { 164 action x = map_unary cast_double x; 165 } 166 167 sep3 = Menuseparator; 168 169 Scmplxitem = class 170 Menuaction "Single _precision complex" 171 "convert to 2 x IEEE 32 bit float" { 172 action x = map_unary cast_complex x; 173 } 174 175 Dcmplx_item = class 176 Menuaction "Double p_recision complex" 177 "convert to 2 x IEEE 64 bit float" { 178 action x = map_unary cast_double_complex x; 179 } 180} 181 182Image_header_item = class 183 Menupullright "_Header" "do stuff to the image header" { 184 185 Image_get_item = class 186 Menupullright "_Get" "get header fields" { 187 188 // the header fields we can get 189 fields = class { 190 type = 0; 191 width = 1; 192 height = 2; 193 format = 3; 194 bands = 4; 195 xres = 5; 196 yres = 6; 197 xoffset = 7; 198 yoffset = 8; 199 coding = 9; 200 201 field_names = Enum [ 202 $width => width, 203 $height => height, 204 $bands => bands, 205 $format => format, 206 $type => type, 207 $xres => xres, 208 $yres => yres, 209 $xoffset => xoffset, 210 $yoffset => yoffset, 211 $coding => coding 212 ]; 213 214 field_option name = Option_enum field_names (_ "Field") name; 215 216 field_funcs = Table [ 217 [type, get_type], 218 [width, get_width], 219 [height, get_height], 220 [format, get_format], 221 [bands, get_bands], 222 [xres, get_xres], 223 [yres, get_yres], 224 [xoffset, get_xoffset], 225 [yoffset, get_yoffset], 226 [coding, get_coding] 227 ]; 228 } 229 230 get_field field_name x = class 231 _result { 232 _vislevel = 3; 233 234 field = fields.field_option field_name; 235 236 _result 237 = map_unary (Real @ 238 fields.field_funcs.lookup 0 1 field.value_thing) x; 239 } 240 241 Width_item = class 242 Menuaction "_Width" "get width" { 243 action x = get_field "width" x; 244 } 245 246 Height_item = class 247 Menuaction "_Height" "get height" { 248 action x = get_field "height" x; 249 } 250 251 Bands_item = class 252 Menuaction "_Bands" "get bands" { 253 action x = get_field "bands" x; 254 } 255 256 Format_item = class 257 Menuaction "_Format" "get format" { 258 action x = get_field "format" x; 259 } 260 261 Type_item = class 262 Menuaction "_Type" "get type" { 263 action x = get_field "type" x; 264 } 265 266 Xres_item = class 267 Menuaction "_Xres" "get X resolution" { 268 action x = get_field "xres" x; 269 } 270 271 Yres_item = class 272 Menuaction "_Yres" "get Y resolution" { 273 action x = get_field "yres" x; 274 } 275 276 Xoffset_item = class 277 Menuaction "X_offset" "get X offset" { 278 action x = get_field "xoffset" x; 279 } 280 281 Yoffset_item = class 282 Menuaction "Yo_ffset" "get Y offset" { 283 action x = get_field "yoffset" x; 284 } 285 286 Coding_item = class 287 Menuaction "_Coding" "get coding" { 288 action x = get_field "coding" x; 289 } 290 291 sep1 = Menuseparator; 292 293 Custom_item = class 294 Menuaction "C_ustom" "get any header field" { 295 action x = class 296 _result { 297 _vislevel = 3; 298 299 field = String "Field" "Xsize"; 300 parse = Option "Parse" [ 301 "No parsing", 302 "Parse string as integer", 303 "Parse string as real", 304 "Parse string as hh:mm:ss" 305 ] 0; 306 307 _result 308 = map_unary (wrap @ process @ get_header field.value) x 309 { 310 parse_str parse str = parse (split is_space str)?0; 311 312 parse_field name cast parse x 313 = cast x, is_number x 314 = parse_str parse x, is_string x 315 = error ("not " ++ name); 316 317 get_int = parse_field "int" cast_int parse_int; 318 get_float = parse_field "float" cast_float parse_float; 319 get_time = parse_field "hh:mm:ss" cast_int parse_time; 320 321 wrap x 322 = Real x, is_real x 323 = Vector x, is_real_list x 324 = Image x, is_image x 325 = Bool x, is_bool x 326 = Matrix x, is_matrix x 327 = String "String" x, is_string x 328 = List x, is_list x 329 = x; 330 331 process = [ 332 id, 333 get_int, 334 get_float, 335 get_time 336 ]?parse; 337 } 338 } 339 } 340 } 341 342 sep1 = Menuseparator; 343 344 Image_set_meta_item = class 345 Menuaction "_Set" "set image metadata" { 346 action x = class 347 _result { 348 _vislevel = 3; 349 350 fname = String "Field" "field-name"; 351 val = Expression "Value" 42; 352 353 _result 354 = map_unary process x 355 { 356 process image 357 = set_header fname.value val.expr image; 358 } 359 } 360 } 361 362 Image_edit_header_item = class 363 Menuaction "_Edit" "change advisory header fields of image" { 364 type_names = Image_type.type_names; 365 all_names = sort (map (extract 0) type_names.value); 366 367 get_prop has get def x 368 = get x, has x 369 = def; 370 371 action x = class 372 _result { 373 _vislevel = 3; 374 375 nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); 376 nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); 377 nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); 378 nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); 379 380 type_option 381 = Option_enum Image_type.type_names "Image type" 382 (Image_type.type_names.get_name type) 383 { 384 type 385 = x.type, is_Image x 386 = Image_type.MULTIBAND; 387 } 388 389 _result 390 = map_unary process x 391 { 392 process image 393 = Image (im_copy_set image.value type_option.value_thing 394 (to_real nxres) (to_real nyres) 395 (to_real nxoff) (to_real nyoff)); 396 } 397 } 398 } 399} 400 401Image_cache_item = class 402 Menuaction "C_ache" "cache calculated image pixels" { 403 action x = class 404 _result { 405 _vislevel = 3; 406 407 tile_width = Number "Tile width" 32; 408 tile_height = Number "Tile height" 32; 409 max_tiles = Number "Maximum number of tiles to cache" (-1); 410 411 _result 412 = map_unary process x 413 { 414 process image 415 = cache (to_real tile_width) (to_real tile_height) 416 (to_real max_tiles) image; 417 } 418 } 419} 420 421#separator 422 423Image_levels_item = class 424 Menupullright "_Levels" "change image levels" { 425 Scale_item = class 426 Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { 427 action x = map_unary scale x; 428 } 429 430 Linear_item = class 431 Menuaction "_Linear" "linear transform of image levels" { 432 action x = class 433 _result { 434 _vislevel = 3; 435 436 scale = Scale "Scale" 0.001 3 1; 437 offset = Scale "Offset" (-128) 128 0; 438 439 _result 440 = map_unary adj x 441 { 442 adj x 443 // only force back to input type if this is a thing 444 // with a type ... so we work for Colour / Matrix etc. 445 = clip2fmt x.format x', has_member "format" x 446 = x' 447 { 448 x' = x * scale + offset; 449 } 450 } 451 } 452 } 453 454 Gamma_item = class 455 Menuaction "_Power" "power transform of image levels (gamma)" { 456 action x = class 457 _result { 458 _vislevel = 3; 459 460 gamma = Scale "Gamma" 0.001 4 1; 461 image_maximum_hint = "You may need to change image_maximum if " ++ 462 "this is not an 8 bit image"; 463 im_mx 464 = Expression "Image maximum" mx 465 { 466 mx 467 = Image_format.maxval x.format, has_format x 468 = 255; 469 } 470 471 _result 472 = map_unary gam x 473 { 474 gam x 475 = clip2fmt (get_format x) x', has_format x 476 = x' 477 { 478 x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; 479 } 480 } 481 } 482 } 483 484 Tone_item = class 485 Menuaction "_Tone Curve" "adjust tone curve" { 486 action x = class 487 _result { 488 _vislevel = 3; 489 490 b = Scale "Black point" 0 100 0; 491 w = Scale "White point" 0 100 100; 492 493 sp = Scale "Shadow point" 0.1 0.3 0.2; 494 mp = Scale "Mid-tone point" 0.4 0.6 0.5; 495 hp = Scale "Highlight point" 0.7 0.9 0.8; 496 497 sa = Scale "Shadow adjust" (-15) 15 0; 498 ma = Scale "Mid-tone adjust" (-30) 30 0; 499 ha = Scale "Highlight adjust" (-15) 15 0; 500 501 curve = tone_build x.format b w sp mp hp sa ma ha; 502 503 _result = map_unary (hist_map curve) x; 504 } 505 } 506} 507 508Image_transform_item = class 509 Menupullright "_Transform" "transform images" { 510 Rotate_item = class 511 Menupullright "Ro_tate" "rotate image" { 512 Fixed_item = class 513 Menupullright "_Fixed" "clockwise rotation by fixed angles" { 514 rotate_widget default x = class 515 _result { 516 _vislevel = 3; 517 518 angle = Option "Rotate by" [ 519 "Don't rotate", 520 "90 degrees clockwise", 521 "180 degrees", 522 "90 degrees anticlockwise" 523 ] default; 524 525 _result 526 = map_unary process x 527 { 528 process in = [ 529 in, 530 rot90 in, 531 rot180 in, 532 rot270 in 533 ] ? angle; 534 } 535 } 536 537 Rot90_item = class 538 Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { 539 action x = rotate_widget 1 x; 540 } 541 542 Rot180_item = class 543 Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { 544 action x = rotate_widget 2 x; 545 } 546 547 Rot270_item = class 548 Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { 549 action x = rotate_widget 3 x; 550 } 551 } 552 553 Free_item = class 554 Menuaction "_Free" "clockwise rotation by any angle" { 555 action x = class 556 _result { 557 _vislevel = 3; 558 559 angle = Scale "Angle" (-180) 180 0; 560 561 _result 562 = map_unary process x 563 { 564 process image 565 = rotate angle image; 566 } 567 } 568 } 569 570 Straighten_item = class 571 Menuaction "_Straighten" 572 ("smallest rotation that makes an arrow either horizontal " ++ 573 "or vertical") { 574 action x 575 = map_unary straighten x 576 { 577 straighten arrow 578 = rotate angle'' arrow.image 579 { 580 x = arrow.width; 581 y = arrow.height; 582 583 angle = im (polar (x, y)); 584 585 angle' 586 = angle - 360, angle > 315 587 = angle - 180, angle > 135 588 = angle; 589 590 angle'' 591 = -angle', angle' >= (-45) && angle' < 45 592 = 90 - angle'; 593 } 594 } 595 } 596 } 597 598 Flip_item = class 599 Menupullright "_Flip" "mirror left/right or up/down" { 600 Left_right_item = class 601 Menuaction "_Left Right" "mirror object left/right" { 602 action x = map_unary fliplr x; 603 } 604 605 Top_bottom_item = class 606 Menuaction "_Top Bottom" "mirror object top/bottom" { 607 action x = map_unary fliptb x; 608 } 609 } 610 611 Resize_item = class 612 Menupullright "_Resize" "change image size" { 613 _interp = Option_enum Interpolate.names "Interpolation" "Bilinear"; 614 615 Scale_item = class 616 Menuaction "_Scale" "scale image size by a factor" { 617 action x = class 618 _result { 619 _vislevel = 3; 620 621 xfactor = Expression "Horizontal scale factor" 1; 622 yfactor = Expression "Vertical scale factor" 1; 623 interp = _interp; 624 625 _result 626 = map_unary process x 627 { 628 process image 629 = resize xfactor yfactor interp.value_thing image; 630 } 631 } 632 } 633 634 Size_item = class 635 Menuaction "_Size To" "resize to a fixed size" { 636 action x = class 637 _result { 638 _vislevel = 3; 639 640 which = Option "Resize axis" [ 641 "Shortest", 642 "Longest", 643 "Horizontal", 644 "Vertical" 645 ] 0; 646 size = Expression "Resize to (pixels)" 128; 647 interp = _interp; 648 649 _result 650 = map_unary process x 651 { 652 process image 653 = resize fac fac interp.value_thing image 654 { 655 xfac = to_real size / image.width; 656 yfac = to_real size / image.height; 657 max_factor = max_pair xfac yfac; 658 min_factor = min_pair xfac yfac; 659 fac = [max_factor, min_factor, xfac, yfac]?which; 660 } 661 } 662 } 663 } 664 665 Size_within_item = class 666 Menuaction "Size _Within" "size to fit within a rectangle" { 667 action x = class 668 _result { 669 _vislevel = 3; 670 671 // the rects we size to fit within 672 _rects = [ 673 [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], 674 [1280, 1024], [1024, 768], [800, 600], [640, 480] 675 ]; 676 677 within = Option "Fit within (pixels)" ( 678 [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ 679 ["Custom"] 680 ) 4; 681 custom_width = Expression "Custom width" 1000; 682 custom_height = Expression "Custom height" 1000; 683 size = Option "Page size" [ 684 "Full page", "Half page", "Quarter page" 685 ] 0; 686 interp = _interp; 687 688 _result 689 = map_unary process x 690 { 691 xdiv = [1, 2, 2]?size; 692 ydiv = [1, 1, 2]?size; 693 allrect = _rects ++ [ 694 [custom_width.expr, custom_height.expr] 695 ]; 696 [width, height] = allrect?within; 697 698 process x 699 = resize fac fac interp.value_thing x, fac < 1 700 = x 701 { 702 xfac = (width / xdiv) / x.width; 703 yfac = (height / ydiv) / x.height; 704 fac = min_pair xfac yfac; 705 } 706 } 707 } 708 } 709 710 Resize_canvas_item = class 711 Menuaction "_Canvas" "change size of surrounding image" { 712 action x = class 713 _result { 714 _vislevel = 3; 715 716 // try to guess a sensible size for the new image 717 _guess_size 718 = x.rect, is_Image x 719 = Rect 0 0 100 100; 720 721 nwidth = Expression "New width (pixels)" _guess_size.width; 722 nheight = Expression "New height (pixels)" _guess_size.height; 723 bgcolour = Expression "Background colour" 0; 724 725 position = Option "Position" [ 726 "North-west", 727 "North", 728 "North-east", 729 "West", 730 "Centre", 731 "East", 732 "South-west", 733 "South", 734 "South-east", 735 "Specify in pixels" 736 ] 4; 737 left = Expression "Pixels from left" 0; 738 top = Expression "Pixels from top" 0; 739 740 _result 741 = map_unary process x 742 { 743 process image 744 = insert_noexpand xp yp image background 745 { 746 width = image.width; 747 height = image.height; 748 coding = image.coding; 749 bands 750 = 3, coding == Image_coding.LABPACK 751 = image.bands; 752 format 753 = Image_format.FLOAT, coding == Image_coding.LABPACK 754 = image.format; 755 type = image.type; 756 757 // placement vectors ... left, centre, right 758 xposv = [0, to_real nwidth / 2 - width / 2, 759 to_real nwidth - width]; 760 yposv = [0, to_real nheight / 2 - height / 2, 761 to_real nheight - height]; 762 xp 763 = left, position == 9 764 = xposv?((int) (position % 3)); 765 yp 766 = top, position == 9 767 = yposv?((int) (position / 3)); 768 769 background = image_new nwidth nheight 770 bands format coding type bgcolour.expr 0 0; 771 } 772 } 773 } 774 } 775 } 776 777 Image_perspective_item = Perspective_item; 778 779 Image_rubber_item = class 780 Menupullright "Ru_bber Sheet" 781 "automatically warp images to superposition" { 782 rubber_interp = Option "Interpolation" 783 (map (extract 0) Interpolate.names.value) Interpolate.BILINEAR; 784 rubber_order = Option "Order" ["0", "1", "2", "3"] 1; 785 rubber_wrap = Toggle "Wrap image edges" false; 786 787 // a transform ... a matrix, plus the size of the image the 788 // matrix was made for 789 Transform matrix image_width image_height = class 790 matrix { 791 // scale a transform ... if it worked for a m by n image, make 792 // it work for a (m * xfac) by (y * yfac) image 793 rescale xfac yfac 794 = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) 795 (image_width * xfac) (image_height * yfac) 796 { 797 facs = [ 798 [xfac, yfac], 799 [1, 1], 800 [1, 1], 801 [1 / xfac, 1 / yfac], 802 [1 / xfac, 1 / yfac], 803 [1 / xfac, 1 / yfac] 804 ]; 805 } 806 } 807 808 // yuk!!!! fix is_instanceof to not need absolute names 809 is_Transform = is_instanceof 810 "Image_transform_item.Image_rubber_item.Transform"; 811 812 Find_item = class 813 Menuaction "_Find" 814 ("find a transform which will map sample image onto " ++ 815 "reference") { 816 action reference sample = class 817 _trn { 818 _vislevel = 3; 819 820 // controls 821 order = rubber_order; 822 interp = rubber_interp; 823 wrap = rubber_wrap; 824 max_err = Expression "Maximum error" 0.3; 825 max_iter = Expression "Maximum iterations" 10; 826 827 // transform 828 [sample', trn, err] = transform_search 829 max_err max_iter order interp wrap 830 sample reference; 831 transformed_image = Image sample'; 832 _trn = Transform trn reference.width reference.height; 833 final_error = err; 834 } 835 } 836 837 Apply_item = class 838 Menuaction "_Apply" "apply a transform to an image" { 839 action a b = class 840 _result { 841 _vislevel = 3; 842 843 // controls 844 interp = rubber_interp; 845 wrap = rubber_wrap; 846 847 _result 848 = map_binary trans a b 849 { 850 trans a b 851 = transform interp wrap t' i 852 { 853 // get the transform arg first 854 [i, t] = sortc (const is_Transform) [a, b]; 855 t' = t.rescale (i.width / t.image_width) 856 (i.height / t.image_height); 857 } 858 } 859 } 860 } 861 } 862 863 sep1 = Menuseparator; 864 865 Match_item = class 866 Menuaction "_Linear Match" 867 "rotate and scale one image to match another" { 868 action x y = class 869 _result { 870 _vislevel = 3; 871 872 // try to find an image ... for a group, get the first item 873 find_image x 874 = x, is_Image x 875 = find_image x?0, is_list x 876 = find_image x.value, is_class x && has_value x 877 = error "unable to find image"; 878 879 _a = find_image x; 880 _b = find_image y; 881 882 ap1 = Mark_relative _a 0.5 0.25; 883 bp1 = Mark_relative _b 0.5 0.25; 884 ap2 = Mark_relative _a 0.5 0.75; 885 bp2 = Mark_relative _b 0.5 0.75; 886 887 refine = Toggle "Refine selected tie-points" false; 888 lock = Toggle "No resize" false; 889 890 _result 891 = map_binary process x y 892 { 893 process a b 894 = Image b''' 895 { 896 _prefs = Workspaces.Preferences; 897 window = _prefs.MOSAIC_WINDOW_SIZE; 898 object = _prefs.MOSAIC_OBJECT_SIZE; 899 900 a' = a.value; 901 b' = b.value; 902 903 b'' = clip2fmt a.format b'; 904 905 // return p2 ... if lock is set, return a p2 a standard 906 // distance along the vector joining p1 and p2 907 norm p1 p2 908 = Rect left' top' 0 0, lock 909 = p2 910 { 911 v = (p2.left - p1.left, p2.top - p1.top); 912 // 100000 to give precision since we pass points as 913 // ints to match 914 n = 100000 * sign v; 915 left' = p1.left + re n; 916 top' = p1.top + im n; 917 } 918 919 ap2'' = norm ap1 ap2; 920 bp2'' = norm bp1 bp2; 921 922 b''' 923 = im_match_linear_search a' b'' 924 ap1.left ap1.top bp1.left bp1.top 925 ap2''.left ap2''.top bp2''.left bp2''.top 926 object window, 927 // we can't search if lock is on 928 refine && !lock 929 = im_match_linear a' b'' 930 ap1.left ap1.top bp1.left bp1.top 931 ap2''.left ap2''.top bp2''.left bp2''.top; 932 } 933 } 934 } 935 } 936 937 Image_perspective_match_item = Perspective_match_item; 938} 939 940Image_band_item = class 941 Menupullright "_Band" "manipulate image bands" { 942 // like extract_bands, but return [] for zero band image 943 // makes compose a bit simpler 944 exb b n x 945 = [], to_real n == 0 946 = extract_bands b n x; 947 948 Extract_item = class Menuaction "_Extract" "extract bands from image" { 949 action x = class 950 _result { 951 _vislevel = 3; 952 953 first = Expression "Extract from band" 0; 954 number = Expression "Extract this many bands" 1; 955 956 _result = map_unary (exb first number) x; 957 } 958 } 959 960 Insert_item = class Menuaction "_Insert" "insert bands into image" { 961 action x y = class 962 _result { 963 _vislevel = 3; 964 965 first = Expression "Insert at position" 0; 966 967 _result 968 = map_binary process x y 969 { 970 process im1 im2 971 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 972 { 973 f = to_real first; 974 b = im1.bands; 975 } 976 } 977 } 978 } 979 980 Delete_item = class Menuaction "_Delete" "delete bands from image" { 981 action x = class 982 _result { 983 _vislevel = 3; 984 985 first = Expression "Delete from band" 0; 986 number = Expression "Delete this many bands" 1; 987 988 _result 989 = map_unary process x 990 { 991 process im 992 = exb 0 f im ++ exb (f + n) (b - (f + n)) im 993 { 994 f = to_real first; 995 n = to_real number; 996 b = im.bands; 997 } 998 } 999 } 1000 } 1001 1002 Bandwise_item = Image_join_item.Bandwise_item; 1003 1004 sep1 = Menuseparator; 1005 1006 To_dimension_item = class 1007 Menuaction "To D_imension" "convert bands to width or height" { 1008 action x = class 1009 _result { 1010 _vislevel = 3; 1011 1012 orientation = Option "Orientation" [ 1013 "Horizontal", 1014 "Vertical" 1015 ] 0; 1016 1017 _result 1018 = map_unary process x 1019 { 1020 process im 1021 = foldl1 [join_lr, join_tb]?orientation (bandsplit im); 1022 } 1023 } 1024 } 1025 1026 To_bands_item = class 1027 Menuaction "To B_ands" "turn width or height to bands" { 1028 action x = class 1029 _result { 1030 _vislevel = 3; 1031 1032 orientation = Option "Orientation" [ 1033 "Horizontal", 1034 "Vertical" 1035 ] 0; 1036 1037 _result 1038 = map_unary process x 1039 { 1040 process im 1041 = bandjoin (map extract_column [0 .. im.width - 1]), 1042 orientation == 0 1043 = bandjoin (map extract_row [0 .. im.height - 1]) 1044 { 1045 extract_column n 1046 = extract_area n 0 1 im.height im; 1047 extract_row n 1048 = extract_area 0 n im.width 1 im; 1049 } 1050 } 1051 } 1052 } 1053} 1054 1055Image_crop_item = class 1056 Menuaction "_Crop" "extract a rectangular area from an image" { 1057 action x = class 1058 _result { 1059 _vislevel = 3; 1060 1061 // try to find the image geometry ... don't bother trying to look 1062 // inside groups though 1063 _geo 1064 = x.rect, is_Image x 1065 = Rect 0 0 100 100; 1066 1067 l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); 1068 t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); 1069 w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); 1070 h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); 1071 1072 _result 1073 = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] 1074 { 1075 extract im l t w h 1076 = extract_area left' top' width' height' im 1077 { 1078 width' = min_pair (to_real w) im.width; 1079 height' = min_pair (to_real h) im.height; 1080 left' = range 0 (to_real l) (im.width - width'); 1081 top' = range 0 (to_real t) (im.height - height'); 1082 } 1083 } 1084 } 1085} 1086 1087Image_insert_item = class 1088 Menuaction "_Insert" "insert a small image into a large image" { 1089 action a b 1090 = insert_position, is_Group a || is_Group b 1091 = insert_area 1092 { 1093 insert_area = class 1094 _result { 1095 _check_args = [ 1096 [a, "a", check_Image], 1097 [b, "b", check_Image] 1098 ] ++ super._check_args; 1099 _vislevel = 3; 1100 1101 // sort to get smallest first 1102 _pred x y = x.width * x.height < y.width * y.height; 1103 [_a', _b'] = sortc _pred [a, b]; 1104 1105 place 1106 = Area _b' left top width height 1107 { 1108 // be careful in case b is smaller than a 1109 left = max_pair 0 ((_b'.width - _a'.width) / 2); 1110 top = max_pair 0 ((_b'.height - _a'.height) / 2); 1111 width = min_pair _a'.width _b'.width; 1112 height = min_pair _a'.height _b'.height; 1113 } 1114 1115 _result 1116 = insert_noexpand place.left place.top 1117 (clip2fmt _b'.format a'') _b' 1118 { 1119 a'' = extract_area 0 0 place.width place.height _a'; 1120 } 1121 } 1122 1123 insert_position = class 1124 _result { 1125 _vislevel = 3; 1126 1127 position = Option "Position" [ 1128 "North-west", 1129 "North", 1130 "North-east", 1131 "West", 1132 "Centre", 1133 "East", 1134 "South-west", 1135 "South", 1136 "South-east", 1137 "Specify in pixels" 1138 ] 4; 1139 left = Expression "Pixels from left" 0; 1140 top = Expression "Pixels from top" 0; 1141 1142 _result 1143 = map_binary insert a b 1144 { 1145 insert a b 1146 = insert_noexpand left top (clip2fmt b.format a) b, 1147 position == 9 1148 = insert_noexpand xp yp (clip2fmt b.format a) b 1149 { 1150 xr = b.width - a.width; 1151 yr = b.height - a.height; 1152 xp = [0, xr / 2, xr]?((int) (position % 3)); 1153 yp = [0, yr / 2, yr]?((int) (position / 3)); 1154 } 1155 } 1156 } 1157 } 1158} 1159 1160Image_select_item = Select_item; 1161 1162Image_join_item = class 1163 Menupullright "_Join" "join two or more images together" { 1164 Bandwise_item = class 1165 Menuaction "_Bandwise" "join two images bandwise" { 1166 action a b = join a b; 1167 } 1168 1169 sep1 = Menuseparator; 1170 1171 join_lr shim bg align a b 1172 = im2 1173 { 1174 w = a.width + b.width + shim; 1175 h = max_pair a.height b.height; 1176 1177 back = image_new w h a.bands a.format a.coding a.type bg 0 0; 1178 1179 ya = [0, max_pair 0 ((b.height - a.height)/2), 1180 max_pair 0 (b.height - a.height)]; 1181 yb = [0, max_pair 0 ((a.height - b.height)/2), 1182 max_pair 0 (a.height - b.height)]; 1183 1184 im1 = insert_noexpand 0 ya?align a back; 1185 im2 = insert_noexpand (a.width + shim) yb?align b im1; 1186 } 1187 1188 join_tb shim bg align a b 1189 = im2 1190 { 1191 w = max_pair a.width b.width; 1192 h = a.height + b.height + shim; 1193 1194 back = image_new w h a.bands a.format a.coding a.type bg 0 0; 1195 1196 xa = [0, max_pair 0 ((b.width - a.width)/2), 1197 max_pair 0 (b.width - a.width)]; 1198 xb = [0, max_pair 0 ((a.width - b.width)/2), 1199 max_pair 0 (a.width - b.width)]; 1200 1201 im1 = insert_noexpand xa?align 0 a back; 1202 im2 = insert_noexpand xb?align (a.height + shim) b im1; 1203 } 1204 1205 halign_names = ["Top", "Centre", "Bottom"]; 1206 valign_names = ["Left", "Centre", "Right"]; 1207 1208 Left_right_item = class 1209 Menuaction "_Left to Right" "join two images left-right" { 1210 action a b = class 1211 _result { 1212 _vislevel = 3; 1213 1214 shim = Scale "Spacing" 0 100 0; 1215 bg_colour = Expression "Background colour" 0; 1216 align = Option "Alignment" halign_names 1; 1217 1218 _result = map_binary 1219 (join_lr shim.value bg_colour.expr align.value) a b; 1220 } 1221 } 1222 1223 Top_bottom_item = class 1224 Menuaction "_Top to Bottom" "join two images top-bottom" { 1225 action a b = class 1226 _result { 1227 _vislevel = 3; 1228 1229 shim = Scale "Spacing" 0 100 0; 1230 bg_colour = Expression "Background colour" 0; 1231 align = Option "Alignment" valign_names 1; 1232 1233 _result = map_binary 1234 (join_tb shim.value bg_colour.expr align.value) a b; 1235 } 1236 } 1237 1238 sep2 = Menuseparator; 1239 1240 Array_item = class 1241 Menuaction "_Array" 1242 "join a list of lists of images into a single image" { 1243 action x = class 1244 _result { 1245 _vislevel = 3; 1246 1247 hshim = Scale "Horizontal spacing" (-100) (100) 0; 1248 vshim = Scale "Vertical spacing" (-100) (100) 0; 1249 bg_colour = Expression "Background colour" 0; 1250 halign = Option "Horizontal alignment" valign_names 1; 1251 valign = Option "Vertical alignment" halign_names 1; 1252 1253 _result 1254 = (image_set_origin 0 0 @ 1255 foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ 1256 map (foldl1 (join_lr hshim.value 1257 bg_colour.expr valign.value))) (to_list (to_list x)); 1258 } 1259 } 1260} 1261 1262Image_tile_item = class 1263 Menupullright "Til_e" "tile an image across and down" { 1264 tile_widget default_type x = class 1265 _result { 1266 _vislevel = 3; 1267 1268 across = Expression "Tiles across" 2; 1269 down = Expression "Tiles down" 2; 1270 repeat = Option "Tile type" 1271 ["Replicate", "Four-way mirror"] default_type; 1272 1273 _result 1274 = map_unary process x 1275 { 1276 process image 1277 = tile across down image, repeat == 0 1278 = tile across down image'' 1279 { 1280 image' = insert image.width 0 (fliplr image) image; 1281 image'' = insert 0 image.height (fliptb image') image'; 1282 } 1283 } 1284 } 1285 1286 Replicate_item = class 1287 Menuaction "_Replicate" "replicate image across and down" { 1288 action x = tile_widget 0 x; 1289 } 1290 1291 Fourway_item = class 1292 Menuaction "_Four-way Mirror" "four-way mirror across and down" { 1293 action x = tile_widget 1 x; 1294 } 1295 1296 Chop_item = class 1297 Menuaction "_Chop Into Tiles" "slice an image into tiles" { 1298 action x = class 1299 _result { 1300 _vislevel = 3; 1301 1302 tile_width = Expression "Tile width" 100; 1303 tile_height = Expression "Tile height" 100; 1304 hoverlap = Expression "Horizontal overlap" 0; 1305 voverlap = Expression "Vertical overlap" 0; 1306 1307 _result 1308 = map_unary (Group @ map Group @ process) x 1309 { 1310 process x 1311 = imagearray_chop tile_width tile_height 1312 hoverlap voverlap x; 1313 } 1314 } 1315 } 1316} 1317 1318#separator 1319 1320Pattern_images_item = class 1321 Menupullright "_Patterns" "make a variety of useful patterns" { 1322 Grey_item = class 1323 Menuaction "Grey _Ramp" "make a smooth grey ramp" { 1324 action = class 1325 _result { 1326 _vislevel = 3; 1327 1328 nwidth = Expression "Image width (pixels)" 64; 1329 nheight = Expression "Image height (pixels)" 64; 1330 orientation = Option "Orientation" [ 1331 "Horizontal", 1332 "Vertical" 1333 ] 0; 1334 foption = Option "Format" ["8 bit", "float"] 0; 1335 1336 _result 1337 = Image im 1338 { 1339 gen 1340 = im_grey, foption == 0 1341 = im_fgrey; 1342 w = to_real nwidth; 1343 h = to_real nheight; 1344 im 1345 = gen w h, orientation == 0 1346 = rot90 (gen h w); 1347 } 1348 } 1349 } 1350 1351 Xy_item = class 1352 Menuaction "_XY Image" 1353 "make a two band image whose pixel values are their coordinates" { 1354 action = class 1355 _result { 1356 _vislevel = 3; 1357 1358 nwidth = Expression "Image width (pixels)" 64; 1359 nheight = Expression "Image height (pixels)" 64; 1360 1361 _result = Image (make_xy nwidth nheight); 1362 } 1363 } 1364 1365 Gaussian_item = class 1366 Menuaction "Gaussian _Noise" "make an image of gaussian noise" { 1367 action = class 1368 _result { 1369 _vislevel = 3; 1370 1371 nwidth = Expression "Image width (pixels)" 64; 1372 nheight = Expression "Image height (pixels)" 64; 1373 mean = Scale "Mean" 0 255 128; 1374 deviation = Scale "Deviation" 0 128 50; 1375 1376 _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) 1377 mean.value deviation.value); 1378 } 1379 } 1380 1381 Fractal_item = class 1382 Menuaction "_Fractal" "make a fractal image" { 1383 action = class 1384 _result { 1385 _vislevel = 3; 1386 1387 nsize = Expression "Image size (pixels)" 64; 1388 dimension = Scale "Dimension" 2.001 2.999 2.001; 1389 1390 _result = Image (im_fractsurf (to_real nsize) dimension.value); 1391 } 1392 } 1393 1394 Checkerboard_item = class 1395 Menuaction "_Checkerboard" "make a checkerboard image" { 1396 action = class 1397 _result { 1398 _vislevel = 3; 1399 1400 nwidth = Expression "Image width (pixels)" 64; 1401 nheight = Expression "Image height (pixels)" 64; 1402 hpsize = Expression "Horizontal patch size" 8; 1403 vpsize = Expression "Vertical patch size" 8; 1404 hpoffset = Expression "Horizontal patch offset" 0; 1405 vpoffset = Expression "Vertical patch offset" 0; 1406 1407 _result 1408 = Image (xstripes ^ ystripes) 1409 { 1410 pixels = make_xy nwidth nheight; 1411 xpixels = pixels?0 + to_real hpoffset; 1412 ypixels = pixels?1 + to_real vpoffset; 1413 1414 make_stripe pix swidth = pix % (swidth * 2) >= swidth; 1415 1416 xstripes = make_stripe xpixels (to_real hpsize); 1417 ystripes = make_stripe ypixels (to_real vpsize); 1418 } 1419 } 1420 } 1421 1422 Grid_item = class 1423 Menuaction "Gri_d" "make a grid" { 1424 action = class 1425 _result { 1426 _vislevel = 3; 1427 1428 nwidth = Expression "Image width (pixels)" 64; 1429 nheight = Expression "Image height (pixels)" 64; 1430 hspace = Expression "Horizontal line spacing" 8; 1431 vspace = Expression "Vertical line spacing" 8; 1432 thick = Expression "Line thickness" 1; 1433 hoff = Expression "Horizontal grid offset" 4; 1434 voff = Expression "Vertical grid offset" 4; 1435 1436 _result 1437 = Image (xstripes | ystripes) 1438 { 1439 pixels = make_xy nwidth nheight; 1440 xpixels = pixels?0 + to_real hoff; 1441 ypixels = pixels?1 + to_real voff; 1442 1443 make_stripe pix swidth = pix % swidth < to_real thick; 1444 1445 xstripes = make_stripe xpixels (to_real hspace); 1446 ystripes = make_stripe ypixels (to_real vspace); 1447 } 1448 } 1449 } 1450 1451 Text_item = class 1452 Menuaction "_Text" "make a bitmap of some text" { 1453 action = class 1454 _result { 1455 _vislevel = 3; 1456 1457 text = String "Text to paint" "<i>Hello</i> world!"; 1458 font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; 1459 wrap = Expression "Wrap text at" 500; 1460 align = Option "Alignment" [ 1461 "Left", 1462 "Centre", 1463 "Right" 1464 ] 0; 1465 dpi = Expression "DPI" 300; 1466 1467 _result = Image (im_text text.value font.value 1468 (to_real wrap) align.value (to_real dpi)); 1469 } 1470 } 1471 1472 New_CIELAB_slice_item = class 1473 Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { 1474 action = class 1475 _result { 1476 _vislevel = 3; 1477 1478 nsize = Expression "Image size (pixels)" 64; 1479 L = Scale "L value" 0 100 50; 1480 1481 _result = Image (lab_slice (to_real nsize) L.value); 1482 } 1483 } 1484 1485 sense_option = Option "Sense" [ 1486 "Pass", 1487 "Reject" 1488 ] 0; 1489 1490 build fn size 1491 = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) 1492 (im_create_fmask size size); 1493 1494 New_ideal_item = class 1495 Menupullright "_Ideal Fourier Mask" 1496 "make various ideal Fourier filter masks" { 1497 High_low_item = class 1498 Menuaction "_High or Low Pass" 1499 ("make a mask image for a highpass/lowpass " ++ 1500 "ideal Fourier filter") { 1501 action = class 1502 _result { 1503 _vislevel = 3; 1504 1505 nsize = Expression "Image size (pixels)" 64; 1506 sense = sense_option; 1507 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1508 1509 _result 1510 = build param (to_real nsize) 1511 { 1512 param f = f sense.value fc.value 0 0 0 0; 1513 } 1514 } 1515 } 1516 1517 Ring_item = class 1518 Menuaction "_Ring Pass or Ring Reject" 1519 ("make a mask image for an ring pass/reject " ++ 1520 "ideal Fourier filter") { 1521 action = class 1522 _result { 1523 _vislevel = 3; 1524 1525 nsize = Expression "Image size (pixels)" 64; 1526 sense = sense_option; 1527 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1528 rw = Scale "Ring width" 0.01 0.99 0.5; 1529 1530 _result 1531 = build param (to_real nsize) 1532 { 1533 param f = f (sense.value + 6) fc.value rw.value 0 0 0; 1534 } 1535 } 1536 } 1537 1538 Band_item = class 1539 Menuaction "_Band Pass or Band Reject" 1540 ("make a mask image for a band pass/reject " ++ 1541 "ideal Fourier filter") { 1542 action = class 1543 _result { 1544 _vislevel = 3; 1545 1546 nsize = Expression "Image size (pixels)" 64; 1547 sense = sense_option; 1548 fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; 1549 fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; 1550 r = Scale "Radius" 0.01 0.99 0.5; 1551 1552 _result 1553 = build param (to_real nsize) 1554 { 1555 param f = f (sense.value + 12) fcx.value fcy.value 1556 r.value 0 0; 1557 } 1558 } 1559 } 1560 } 1561 1562 New_gaussian_item = class 1563 Menupullright "_Gaussian Fourier Mask" 1564 "make various Gaussian Fourier filter masks" { 1565 High_low_item = class 1566 Menuaction "_High or Low Pass" 1567 ("make a mask image for a highpass/lowpass " ++ 1568 "Gaussian Fourier filter") { 1569 action = class 1570 _result { 1571 _vislevel = 3; 1572 1573 nsize = Expression "Image size (pixels)" 64; 1574 sense = sense_option; 1575 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1576 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1577 1578 _result 1579 = build param (to_real nsize) 1580 { 1581 param f = f (sense.value + 4) fc.value ac.value 0 0 0; 1582 } 1583 } 1584 } 1585 1586 Ring_item = class 1587 Menuaction "_Ring Pass or Ring Reject" 1588 ("make a mask image for an ring pass/reject " ++ 1589 "Gaussian Fourier filter") { 1590 action = class 1591 _result { 1592 _vislevel = 3; 1593 1594 nsize = Expression "Image size (pixels)" 64; 1595 sense = sense_option; 1596 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1597 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1598 rw = Scale "Ring width" 0.01 0.99 0.5; 1599 1600 _result 1601 = build param (to_real nsize) 1602 { 1603 param f = f (sense.value + 10) fc.value rw.value 1604 ac.value 0 0; 1605 } 1606 } 1607 } 1608 1609 Band_item = class 1610 Menuaction "_Band Pass or Band Reject" 1611 ("make a mask image for a band pass/reject " ++ 1612 "Gaussian Fourier filter") { 1613 action = class 1614 _result { 1615 _vislevel = 3; 1616 1617 nsize = Expression "Image size (pixels)" 64; 1618 sense = sense_option; 1619 fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; 1620 fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; 1621 r = Scale "Radius" 0.01 0.99 0.5; 1622 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1623 1624 _result 1625 = build param (to_real nsize) 1626 { 1627 param f = f (sense.value + 16) fcx.value fcy.value 1628 r.value ac.value 0; 1629 } 1630 } 1631 } 1632 } 1633 1634 New_butterworth_item = class 1635 Menupullright "_Butterworth Fourier Mask" 1636 "make various Butterworth Fourier filter masks" { 1637 High_low_item = class 1638 Menuaction "_High or Low Pass" 1639 ("make a mask image for a highpass/lowpass " ++ 1640 "Butterworth Fourier filter") { 1641 action = class 1642 _result { 1643 _vislevel = 3; 1644 1645 nsize = Expression "Image size (pixels)" 64; 1646 sense = sense_option; 1647 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1648 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1649 order = Scale "Order" 1 10 2; 1650 1651 _result 1652 = build param (to_real nsize) 1653 { 1654 param f = f (sense.value + 2) order.value fc.value 1655 ac.value 0 0; 1656 } 1657 } 1658 } 1659 1660 Ring_item = class 1661 Menuaction "_Ring Pass or Ring Reject" 1662 ("make a mask image for an ring pass/reject " ++ 1663 "Butterworth Fourier filter") { 1664 action = class 1665 _result { 1666 _vislevel = 3; 1667 1668 nsize = Expression "Image size (pixels)" 64; 1669 sense = sense_option; 1670 fc = Scale "Frequency cutoff" 0.01 0.99 0.5; 1671 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1672 rw = Scale "Ring width" 0.01 0.99 0.5; 1673 order = Scale "Order" 1 10 2; 1674 1675 _result 1676 = build param (to_real nsize) 1677 { 1678 param f = f (sense.value + 8) order.value fc.value 1679 rw.value ac.value 0; 1680 } 1681 } 1682 } 1683 1684 Band_item = class 1685 Menuaction "_Band Pass or Band Reject" 1686 ("make a mask image for a band pass/reject " ++ 1687 "Butterworth Fourier filter") { 1688 action = class 1689 _result { 1690 _vislevel = 3; 1691 1692 nsize = Expression "Image size (pixels)" 64; 1693 sense = sense_option; 1694 fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; 1695 fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; 1696 r = Scale "Radius" 0.01 0.99 0.5; 1697 ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; 1698 order = Scale "Order" 1 10 2; 1699 1700 _result 1701 = build param (to_real nsize) 1702 { 1703 param f = f (sense.value + 14) order.value fcx.value 1704 fcy.value r.value ac.value; 1705 } 1706 } 1707 } 1708 } 1709} 1710 1711Test_images_item = class 1712 Menupullright "Test I_mages" "make a variety of test images" { 1713 Eye_item = class 1714 Menuaction "_Spatial Response" 1715 "image for testing the eye's spatial response" { 1716 action = class 1717 _result { 1718 _vislevel = 3; 1719 1720 nwidth = Expression "Image width (pixels)" 64; 1721 nheight = Expression "Image height (pixels)" 64; 1722 factor = Scale "Factor" 0.001 1 0.2; 1723 1724 _result = Image (im_eye (to_real nwidth) (to_real nheight) 1725 factor.value); 1726 } 1727 } 1728 1729 Zone_plate = class 1730 Menuaction "_Zone Plate" "make a zone plate" { 1731 action = class 1732 _result { 1733 _vislevel = 3; 1734 1735 nsize = Expression "Image size (pixels)" 64; 1736 1737 _result = Image (im_zone (to_real nsize)); 1738 } 1739 } 1740 1741 Frequency_test_chart_item = class 1742 Menuaction "_Frequency Testchart" 1743 "make a black/white frequency test pattern" { 1744 action = class 1745 _result { 1746 _vislevel = 3; 1747 1748 nwidth = Expression "Image width (pixels)" 64; 1749 sheight = Expression "Strip height (pixels)" 10; 1750 waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; 1751 1752 _result 1753 = imagearray_assemble 0 0 (transpose [strips]) 1754 { 1755 freq_slice wave = Image (sin (grey / wave) > 0); 1756 strips = map freq_slice waves.expr; 1757 grey = im_fgrey (to_real nwidth) (to_real sheight) * 1758 360 * (to_real nwidth); 1759 } 1760 } 1761 } 1762 1763 CRT_test_chart_item = class 1764 Menuaction "CRT _Phosphor Chart" 1765 "make an image for measuring phosphor colours" { 1766 action = class 1767 _result { 1768 _vislevel = 3; 1769 1770 brightness = Scale "Brightness" 0 255 200; 1771 psize = Expression "Patch size (pixels)" 32; 1772 1773 _result 1774 = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) 1775 { 1776 1777 black = image_new (to_real psize) (to_real psize) 1 1778 Image_format.FLOAT Image_coding.NOCODING 1779 Image_type.B_W 0 0 0; 1780 notblack = black + brightness; 1781 1782 green = black ++ notblack ++ black; 1783 red = notblack ++ black ++ black; 1784 blue = black ++ black ++ notblack; 1785 white = notblack ++ notblack ++ notblack; 1786 } 1787 } 1788 } 1789 1790 Greyscale_chart_item = class 1791 Menuaction "_Greyscale" "make a greyscale" { 1792 action = class 1793 _result { 1794 _vislevel = 3; 1795 1796 pwidth = Expression "Patch width" 8; 1797 pheight = Expression "Patch height" 8; 1798 npatches = Expression "Number of patches" 16; 1799 1800 _result 1801 = Image (image_set_type Image_type.B_W 1802 (clip2fmt Image_format.UCHAR wedge)) 1803 { 1804 wedge 1805 = 255 / (to_real npatches - 1) * 1806 (int) (strip?0 / to_real pwidth) 1807 { 1808 strip = make_xy (to_real pwidth * to_real npatches) pheight; 1809 } 1810 } 1811 } 1812 } 1813 1814 CMYK_test_chart_item = class 1815 Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { 1816 action = class 1817 _result { 1818 _vislevel = 3; 1819 1820 pwidth = Expression "Patch width" 8; 1821 pheight = Expression "Patch height" 8; 1822 npatches = Expression "Number of patches" 16; 1823 1824 _result 1825 = Image (image_set_type Image_type.CMYK 1826 (clip2fmt Image_format.UCHAR strips)) 1827 { 1828 wedge 1829 = 255 / (to_real npatches - 1) * 1830 (int) (strip?0 / to_real pwidth) 1831 { 1832 strip = make_xy (to_real pwidth * to_real npatches) pheight; 1833 } 1834 1835 black = wedge * 0; 1836 1837 C = wedge ++ black ++ black ++ black; 1838 M = black ++ wedge ++ black ++ black; 1839 Y = black ++ black ++ wedge ++ black; 1840 K = black ++ black ++ black ++ wedge; 1841 1842 strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; 1843 } 1844 } 1845 } 1846 1847 Colour_atlas_item = class 1848 Menuaction "_Colour Atlas" 1849 "make a grid of patches grouped around a colour" { 1850 action = class 1851 _result { 1852 _vislevel = 3; 1853 1854 start = Colour_picker "Lab" [50,0,0]; 1855 nstep = Expression "Number of steps" 2; 1856 ssize = Expression "Step size" 2; 1857 1858 _result 1859 = Image (colour_transform_to (get_type start) im) 1860 { 1861 base = colour_transform_to Image_type.LAB start; 1862 step = to_real ssize; 1863 offset = to_real nstep * step; 1864 range c = [c - offset, c - offset + step ... c + offset]; 1865 1866 mk_patch b a = image_new 8 8 3 1867 Image_format.FLOAT Image_coding.NOCODING 1868 Image_type.LAB (Vector [base?0, a, b]) 0 0; 1869 1870 mk_strip b = map (mk_patch b) (range base?1); 1871 mk_grid = map mk_strip (range base?2); 1872 im = imagearray_assemble 1 1 mk_grid; 1873 } 1874 } 1875 } 1876} 1877 1878