1 2Colour_new_item = class 3 Menupullright (_ "_New") (_ "make a patch of colour") { 4 Widget_colour_item = class 5 Menuaction (_ "_Colour") (_ "make a patch of colour") { 6 action = Colour_picker "Lab" [50,0,0]; 7 } 8 9 LAB_colour = class 10 Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { 11 action = widget "Lab" [50, 0, 0]; 12 13 // ab_slice size 14 size = 512; 15 16 // range of values ... +/- 128 for ab 17 range = 256; 18 19 // map xy in slice image to ab and back 20 xy2ab x = x / (size / range) - 128; 21 ab2xy a = (a + 128) * (size / range); 22 23 widget space default_value = class 24 Colour space _result { 25 _vislevel = 3; 26 27 _L = default_value?0; 28 _a = default_value?1; 29 _b = default_value?2; 30 31 lightness = Slider 0 100 _L; 32 ab_slice = Image (lab_slice size lightness.value); 33 point = Mark ab_slice (ab2xy _a) (ab2xy _b); 34 35 _result = [lightness.value, xy2ab point.left, xy2ab point.top]; 36 37 Colour_edit colour_space value = widget colour_space value; 38 } 39 } 40} 41 42#separator 43 44Colour_convert_item = class 45 Menupullright (_ "_Convert To") (_ "convert to various colour spaces") { 46 spaces = Image_type.image_colour_spaces; 47 48 conv dest x = class 49 _result { 50 _vislevel = 3; 51 52 to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); 53 54 _result = map_unary (colour_transform_to to.value_thing) x; 55 } 56 57 Mono_item = class 58 Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { 59 action x = conv Image_type.B_W x; 60 } 61 62 sRGB_item = class 63 Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { 64 action x = conv Image_type.sRGB x; 65 } 66 67 Lab_item = class 68 Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { 69 action x = conv Image_type.LAB x; 70 } 71 72 LabQ_item = class 73 Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { 74 action x = conv Image_type.LABQ x; 75 } 76 77 LabS_item = class 78 Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { 79 action x = conv Image_type.LABS x; 80 } 81 82 LCh_item = class 83 Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { 84 action x = conv Image_type.LCH x; 85 } 86 87 XYZ_item = class 88 Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { 89 action x = conv Image_type.XYZ x; 90 } 91 92 Yxy_item = class 93 Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { 94 action x = conv Image_type.YXY x; 95 } 96 97 UCS_item = class 98 Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { 99 action x = conv Image_type.UCS x; 100 } 101} 102 103/* mark objects as being in various colourspaces 104 */ 105Colour_tag_item = class 106 Menupullright (_ "_Tag As") 107 (_ "tag object as being in various colour spaces") { 108 spaces = Image_type.image_colour_spaces; 109 110 tag dest x = class 111 _result { 112 _vislevel = 3; 113 114 to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); 115 116 _result = map_unary (image_set_type to.value_thing) x; 117 } 118 119 Mono_item = class 120 Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { 121 action x = tag Image_type.B_W x; 122 } 123 124 sRGB_item = class 125 Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { 126 action x = tag Image_type.sRGB x; 127 } 128 129 Lab_item = class 130 Menuaction (_ "_Lab") 131 (_ "tag as being in Lab colourspace (float Lab)") { 132 action x = tag Image_type.LAB x; 133 } 134 135 LabQ_item = class 136 Menuaction (_ "Lab_Q") 137 (_ "tag as being in LabQ colourspace (32-bit Lab)") { 138 action x = tag Image_type.LABQ x; 139 } 140 141 LabS_item = class 142 Menuaction (_ "Lab_S") 143 (_ "tag as being in LabS colourspace (48-bit Lab)") { 144 action x = tag Image_type.LABS x; 145 } 146 147 LCh_item = class 148 Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { 149 action x = tag Image_type.LCH x; 150 } 151 152 XYZ_item = class 153 Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { 154 action x = tag Image_type.XYZ x; 155 } 156 157 Yxy_item = class 158 Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { 159 action x = tag Image_type.YXY x; 160 } 161 162 UCS_item = class 163 Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { 164 action x = tag Image_type.UCS x; 165 } 166} 167 168Colour_temperature_item = class 169 Menupullright (_ "Colour Te_mperature") 170 (_ "colour temperature conversions") { 171 Whitepoint_item = class 172 Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { 173 action x = class 174 _result { 175 _vislevel = 3; 176 177 old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; 178 new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; 179 180 _result 181 = map_unary process x 182 { 183 process im 184 = im''' 185 { 186 im' = colour_transform_to Image_type.XYZ im; 187 im'' = im' * 188 (new_white.value_thing / old_white.value_thing); 189 im''' = colour_transform_to (get_type im) im''; 190 } 191 } 192 } 193 } 194 195 D65_to_D50_item = class 196 Menupullright (_ "D_65 to D50") (_ "complex conversion") { 197 XYZ_minimal_item = class 198 Menuaction (_ "_Minimal") 199 (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { 200 action x 201 = map_unary process x 202 { 203 process im 204 = im''' 205 { 206 im' = colour_transform_to Image_type.XYZ im; 207 im'' = recomb D652D50_direct im'; 208 im''' = colour_transform_to (get_type im) im''; 209 } 210 } 211 } 212 213 Bradford_item = class 214 Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { 215 action x 216 = map_unary process x 217 { 218 process im 219 = im''' 220 { 221 im' = colour_transform_to Image_type.XYZ im; 222 im'' = im_D652D50 im'; 223 im''' = colour_transform_to (get_type im) im''; 224 } 225 } 226 } 227 } 228 229 D50_to_D65_item = class 230 Menupullright (_ "D_50 to D65") (_ "complex conversion") { 231 XYZ_minimal_item = class 232 Menuaction (_ "_Minimal") 233 (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { 234 action x 235 = map_unary process x 236 { 237 process im 238 = im''' 239 { 240 im' = colour_transform_to Image_type.XYZ im; 241 im'' = recomb D502D65_direct im'; 242 im''' = colour_transform_to (get_type im) im''; 243 } 244 } 245 } 246 247 Bradford_item = class 248 Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { 249 action x 250 = map_unary process x 251 { 252 process im 253 = im''' 254 { 255 im' = colour_transform_to Image_type.XYZ im; 256 im'' = im_D502D65 im'; 257 im''' = colour_transform_to (get_type im) im''; 258 } 259 } 260 } 261 } 262 263 Lab_to_D50XYZ_item = class 264 Menuaction (_ "_Lab to D50 XYZ") 265 (_ "Lab to XYZ with a D50 whitepoint") { 266 action x = map_unary (colour_unary im_D50Lab2XYZ) x; 267 } 268 269 D50XYZ_to_Lab_item = class 270 Menuaction (_ "D50 _XYZ to Lab") 271 (_ "XYZ to Lab with a D50 whitepoint") { 272 action x = map_unary (colour_unary im_D50XYZ2Lab) x; 273 } 274} 275 276Colour_icc_item = class 277 Menupullright (_ "_ICC") (_ "transform with ICC profiles") { 278 print_profile = 279 "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; 280 monitor_profile = 281 "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; 282 guess_profile image 283 = monitor_profile, has_bands image && get_bands image == 3 284 = print_profile; 285 render_intents = Option_enum Render_intent.names (_ "Render intent") 286 (_ "Absolute"); 287 288 Export_item = class 289 Menuaction (_ "_Export") (_ "export from PCS to device space") { 290 action x = class 291 _result { 292 _vislevel = 3; 293 294 profile = Pathname (_ "Output profile") print_profile; 295 intent = render_intents; 296 depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; 297 298 _result 299 = map_unary process x 300 { 301 process image 302 = icc_export [8, 16]?depth profile.value 303 intent.value_thing lab 304 { 305 lab = colour_transform_to Image_type.LABQ image; 306 } 307 } 308 } 309 } 310 311 Import_item = class 312 Menuaction (_ "_Import") (_ "import from device space to PCS") { 313 action x = class 314 _result { 315 _vislevel = 3; 316 317 profile = Pathname (_ "Input profile") (guess_profile x); 318 intent = render_intents; 319 320 _result 321 = map_unary process x 322 { 323 process image 324 = icc_import profile.value intent.value_thing image; 325 } 326 } 327 } 328 329 Transform_item = class 330 Menuaction (_ "_Transform") (_ "transform between two device spaces") { 331 action x = class 332 _result { 333 _vislevel = 3; 334 335 in_profile = Pathname (_ "Input profile") (guess_profile x); 336 out_profile = Pathname (_ "Output profile") print_profile; 337 intent = render_intents; 338 339 _result 340 = map_unary process x 341 { 342 process image 343 = icc_transform in_profile.value out_profile.value 344 intent.value_thing image; 345 } 346 } 347 } 348 349 AC2RC_item = class 350 Menuaction (_ "_Absolute to Relative") 351 (_ "absolute to relative colorimetry using device profile") { 352 action x = class 353 _result { 354 _vislevel = 3; 355 356 profile = Pathname (_ "Pick a profile") (guess_profile x); 357 358 _result 359 = map_unary process x 360 { 361 process image 362 = icc_ac2rc profile.value lab 363 { 364 lab = colour_transform_to Image_type.LAB image; 365 } 366 } 367 } 368 } 369} 370 371#separator 372 373Colour_dE_item = class 374 Menupullright (_ "_Difference") (_ "calculate colour difference") { 375 /* Apply a converter to an object ... convert image or colour (since 376 * we can guess the colour space we're converting from), don't convert 377 * matrix or vector (since we can't tell ... assume it's in the right 378 * space already). 379 */ 380 apply_cvt cvt x 381 = cvt x, 382 is_Image x || is_Colour x || is_image x 383 = x; 384 385 diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); 386 387 /* Converter to LAB. 388 */ 389 lab_cvt = colour_transform_to Image_type.LAB; 390 391 /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after 392 * to make sure we get a rectangular coord system. 393 */ 394 ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ 395 colour_transform_to Image_type.UCS; 396 397 CIEdE76_item = class 398 Menuaction (_ "CIE dE _76") 399 (_ "calculate CIE dE 1976 for two objects") { 400 action a b = map_binary (diff lab_cvt) a b; 401 } 402 403 CIEdE00_item = class 404 Menuaction (_ "CIE dE _00") 405 (_ "calculate CIE dE 2000 for two objects") { 406 action a b = map_binary 407 (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; 408 } 409 410 UCS_item = class 411 Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { 412 action a b = map_binary (diff ucs_cvt) a b; 413 } 414} 415 416Colour_adjust_item = class 417 Menupullright (_ "_Adjust") (_ "alter colours in various ways") { 418 Recombination_item = class 419 Menuaction (_ "_Recombination") 420 (_ "recombine colour with an editable matrix") { 421 action x = class 422 _result { 423 _vislevel = 3; 424 425 matrix 426 = Matrix_rec (identity_matrix (bands x)) 427 { 428 // try to guess a sensible value for the size of the 429 // matrix 430 bands x 431 = x.bands, is_Image x || is_Colour x 432 = x.width, is_Matrix x 433 = bands x.value?0, is_Group x 434 = x.bands, has_member "bands" x 435 = 3; 436 } 437 438 _result = map_unary (recomb matrix) x; 439 } 440 } 441 442 Cast_item = class 443 Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { 444 action x = class 445 _result { 446 _vislevel = 3; 447 448 green_red = Slider (-20) 20 0; 449 blue_yellow = Slider (-20) 20 0; 450 451 _result 452 = map_unary adjust_cast x 453 { 454 adjust_cast in 455 = colour_transform_to (get_type in) in'' 456 { 457 in' = colour_transform_to Image_type.LAB in; 458 in'' = in' + 459 Vector [0, green_red.value, blue_yellow.value]; 460 } 461 } 462 } 463 } 464 465 HSB_item = class 466 Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { 467 action x = class 468 _result { 469 _vislevel = 3; 470 471 hue = Slider 0 360 0; 472 saturation = Slider 0.01 5 1; 473 brightness = Slider 0.01 5 1; 474 475 _result 476 = map_unary adjust_hsb x 477 { 478 adjust_hsb in 479 = colour_transform_to (get_type in) in'' 480 { 481 in' = colour_transform_to Image_type.LCH in; 482 in'' = in' * Vector [bv, sv, 1] + Vector [0, 0, hv]; 483 bv = brightness.value; 484 sv = saturation.value; 485 hv = hue.value; 486 } 487 } 488 } 489 } 490} 491 492Colour_similar_item = class 493 Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { 494 action x = class 495 _result { 496 _vislevel = 3; 497 498 target_colour = Colour_picker "Lab" [50, 0, 0]; 499 dE_threshold = Slider 0 100 10; 500 501 _result 502 = map_unary match x 503 { 504 match in 505 = abs_vec (in' - target) < dE_threshold 506 { 507 target = colour_transform_to Image_type.LAB target_colour; 508 in' = colour_transform_to Image_type.LAB in; 509 } 510 } 511 } 512} 513 514#separator 515 516Colour_image_to_colour_item = class 517 Menuaction (_ "Im_age to Colour") (_ "convert image to colour") { 518 action x 519 = map_unary test x 520 { 521 test x 522 = to_colour x, is_Image x 523 = to_colour (Image pixel), is_Mark x 524 = error (_ "Colour_from_image: arg not Image or Mark: " ++ 525 print x) 526 { 527 pixel = extract_area x.left x.top 1 1 x; 528 } 529 } 530} 531 532Colour_colour_to_image_item = class 533 Menuaction (_ "C_olour to _Image") (_ "convert colour to image") { 534 action x = class 535 _result { 536 _vislevel = 3; 537 538 width = Expression (_ "Width of image to make") 64; 539 height = Expression (_ "Height of image to make") 64; 540 541 _result 542 = map_unary (Image @ build) x 543 { 544 build in 545 = image_new (to_real width) (to_real height) 3 546 Image_format.FLOAT 547 Image_coding.NOCODING (get_type in) in 0 0; 548 } 549 } 550} 551 552#separator 553 554Colour_chart_to_matrix_item = class 555 Menuaction (_ "_Measure Colour Chart") 556 (_ "measure average pixel values for a colour chart image") { 557 action x = class 558 _result { 559 _vislevel = 3; 560 561 pacross = Expression (_ "Patches across chart") 6; 562 pdown = Expression (_ "Patches down chart") 4; 563 564 _result 565 = map_unary chart x 566 { 567 chart in 568 = measure 0 0 in.width in.height 569 (to_real pacross) (to_real pdown) in; 570 } 571 } 572} 573 574Colour_matrix_to_chart_item = class 575 Menuaction (_ "Make S_ynthetic Colour Chart") 576 (_ "make a colour chart image from a matrix of measurements") { 577 action x = class 578 _result { 579 _vislevel = 3; 580 581 pacross = Expression (_ "Patches across chart") 6; 582 pdown = Expression (_ "Patches down chart") 4; 583 pwidth = Expression (_ "Patch width in pixels") 50; 584 pheight = Expression (_ "Patch height in pixels") 50; 585 bwidth = Expression (_ "Border between patches") 0; 586 587 _result 588 = map_unary build_chart x 589 { 590 build_chart in 591 = Image (imagearray_assemble 592 (to_real bwidth) (to_real bwidth) patch_table) 593 { 594 // patch numbers for row starts 595 rowstart = map (multiply (to_real pacross)) 596 [0 .. to_real pdown - 1]; 597 598 // assemble patches ... each one a pixel value 599 patches = map (take (to_real pacross)) 600 (map (converse drop in.value) rowstart); 601 602 // make an n-band constant image from eg. [1,2,3] 603 // we don't know the format .. use sRGB (well, why not?) 604 patch v = image_new (to_real pwidth) (to_real pheight) (len v) 605 Image_format.FLOAT Image_coding.NOCODING 606 Image_type.sRGB (Vector v) 0 0; 607 608 // make an image for each patch 609 patch_table = map (map patch) patches; 610 } 611 } 612 } 613} 614 615Colour_plot_ab_scatter_item = class 616 Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { 617 action x = class 618 _result { 619 _vislevel = 3; 620 621 bins = Expression (_ "Number of bins on each axis") 8; 622 623 _result 624 = map_unary plot_scatter x 625 { 626 plot_scatter in 627 = Image (bg * (((90 / mx) * hist) ++ blk)) 628 { 629 lab = colour_transform_to Image_type.LAB in.value; 630 ab = (unsigned char) ((lab?1 ++ lab?2) + 128); 631 hist = hist_find_nD bins.expr ab; 632 mx = max hist; 633 bg = lab_slice bins.expr 1; 634 blk = 1 + im_black (to_real bins) (to_real bins) 2; 635 } 636 } 637 } 638} 639