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