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