1 2/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real 3 */ 4to_matrix x 5 = to_matrix x.expr, is_Expression x 6 = x, is_Matrix x 7 = oo_unary_function to_matrix_op x, is_class x 8 = tom x 9{ 10 to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; 11 12 tom x 13 = Matrix (itom x), is_image x 14 = Matrix [[x]], is_real x 15 = Matrix [x], is_real_list x 16 = Matrix x, is_matrix x 17 = error (_ "bad arguments to " ++ "to_matrix"); 18 19 itom i 20 = (im_vips2mask ((double) i)).value, is_image i 21 = error (_ "not image"); 22} 23 24/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real 25 * Special case for Colour ... pull out the colour_space and set Type in the 26 * image. 27 */ 28to_image x 29 = to_image x.expr, is_Expression x 30 = x, is_Image x 31 = Image (image_set_type 32 (Image_type.colour_spaces.lookup 0 1 x.colour_space) 33 (mtoi [x.value])), 34 is_Colour x 35 = oo_unary_function to_image_op x, is_class x 36 = toi x 37{ 38 to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; 39 40 toi x 41 = Image x, is_image x 42 = Image (mtoi [[x]]), is_real x 43 = Image (mtoi [x]), is_real_list x 44 = Image (mtoi x), is_matrix x 45 = error (_ "bad arguments to " ++ "to_image"); 46 47 // [[real]] -> image 48 mtoi m 49 = im_mask2vips (Matrix m), width != 3 50 = joinup (im_mask2vips (Matrix m)) 51 { 52 width = len m?0; 53 height = len m; 54 joinup i 55 = b1 ++ b2 ++ b3 56 { 57 b1 = extract_area 0 0 1 height i; 58 b2 = extract_area 1 0 1 height i; 59 b3 = extract_area 2 0 1 height i; 60 } 61 } 62} 63 64// like to_image, but we do 1x1 pixel + x, then embed it up 65// always make an unwrapped image for speed ... this gets used by ifthenelse 66// and stuff like that 67// format can be NULL, meaning set format from x 68to_image_size width height bands format x 69 = x, is_image x 70 = x.value, is_Image x 71 = im'' 72{ 73 // we want x to set the target format if we don't have one, so we 74 // can't use image_new 75 im = im_black 1 1 bands + x; 76 im' 77 = clip2fmt format im, format != NULL 78 = im; 79 im'' = embed 1 0 0 width height im'; 80} 81 82/* Try to make a Colour. 83 */ 84to_colour x 85 = to_colour x.expr, is_Expression x 86 = x, is_Colour x 87 = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x 88 = oo_unary_function to_colour_op x, is_class x 89 = toc x 90{ 91 to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; 92 93 toc x 94 = Colour (colour_space (get_type x)) 95 (map mean (bandsplit (get_image x))), 96 has_image x && has_type x 97 = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono 98 = Colour "sRGB" x, is_real_list x && is_list_len 3 x 99 = map toc x, is_matrix x 100 = error (_ "bad arguments to " ++ "to_colour"); 101 102 colour_space type 103 = table.get_name type, table.has_name type 104 = error (_ "unable to make Colour from " ++ table.get_name type ++ 105 _ " image") 106 { 107 table = Image_type.colour_spaces; 108 } 109} 110 111/* Try to make a real. (not a Real!) 112 */ 113to_real x 114 = to_real x.expr, is_Expression x 115 = oo_unary_function to_real_op x, is_class x 116 = tor x 117{ 118 to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; 119 120 tor x 121 = x, is_real x 122 = abs x, is_complex x 123 = 1, is_bool x && x 124 = 0, is_bool x && !x 125 = error (_ "bad arguments to " ++ "to_real"); 126} 127 128to_int x = (int) (to_real x); 129 130/* Try to make a list ... ungroup, basically. We remove the innermost layer of 131 * Groups. 132 */ 133to_list x 134 = x.value, is_Group x && !contains_Group x.value 135 = Group (map to_list x.value), is_Group x 136 = x; 137 138/* Try to make a group. The innermost list objects become Group()'d. 139 */ 140to_group x 141 = Group x, is_list x && !contains_Group x 142 = Group (map to_group x.value), is_Group x 143 = x; 144 145/* Parse a positive integer. 146 */ 147parse_pint l 148 = foldl acc 0 l 149{ 150 acc sofar ch = sofar * 10 + parse_c ch; 151 152 /* Turn a char digit to a number. 153 */ 154 parse_c ch 155 = error (_ "not a digit"), !is_digit ch 156 = (int) ch - (int) '0'; 157} 158 159/* Parse an integer, with an optional sign character. 160 */ 161parse_int l 162 = error (_ "badly formed number"), !is_list_len 2 parts 163 = sign * n 164{ 165 parts = splitpl [member "+-", is_digit] l; 166 167 n = parse_pint parts?1; 168 sign 169 = 1, parts?0 == [] || parts?0 == "+" 170 = -1; 171} 172 173/* Parse a float. 174 * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? 175 */ 176parse_float l 177 = err, !is_list_len 4 parts 178 = (ipart + fpart) * 10 ** exp 179{ 180 err = error (_ "badly formed number"); 181 182 parts = splitpl [ 183 member "+-0123456789", member ".0123456789", 184 member "eE", member "+-0123456789" 185 ] l; 186 187 ipart = parse_int parts?0; 188 fpart 189 = 0, parts?1 == []; 190 = err, parts?1?0 != '.' 191 = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); 192 exp 193 = 0, parts?2 == [] && parts?3 == [] 194 = err, parts?2 == [] 195 = parse_int parts?3; 196 197} 198 199/* Parse a time in "hh:mm:ss" into seconds. 200 201We could do this in one line :) 202 203 = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map 204 parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, 205 equal ':', is_digit] l))) [0,2,4]; 206 207but it's totally unreadable. 208 209 */ 210parse_time l 211 = error (_ "badly formed time"), !is_list_len 5 parts 212 = s + 60 * m + 60 * 60 * h 213{ 214 parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; 215 h = parse_int parts?0; 216 m = parse_int parts?2; 217 s = parse_int parts?4; 218} 219 220/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by 221 * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix 222 */ 223D652D50_direct = Matrix 224 [[ 1.13529, -0.0604663, -0.0606321 ], 225 [ 0.0975399, 0.935024, -0.0256156 ], 226 [ -0.0336428, 0.0414702, 0.994135 ]]; 227 228D502D65_direct = D652D50_direct ** -1; 229 230/* Convert normalised XYZ to bradford RGB. 231 */ 232XYZ2RGBbrad = Matrix 233 [[0.8951, 0.2664, -0.1614], 234 [-0.7502, 1.7135, 0.0367], 235 [0.0389, -0.0685, 1.0296]]; 236 237/* Convert bradford RGB to normalised XYZ. 238 */ 239RGBbrad2XYZ = XYZ2RGBbrad ** -1; 240 241D93_whitepoint = Vector [89.7400, 100, 130.7700]; 242D75_whitepoint = Vector [94.9682, 100, 122.5710]; 243D65_whitepoint = Vector [95.0470, 100, 108.8827]; 244D55_whitepoint = Vector [95.6831, 100, 92.0871]; 245D50_whitepoint = Vector [96.4250, 100, 82.4680]; 246A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K 247B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K 248C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K 249E_whitepoint = Vector [100, 100, 100]; // ill. free 250D3250_whitepoint = Vector [105.6590, 100, 45.8501]; 251 252Whitepoints = Enum [ 253 $D93 => D93_whitepoint, 254 $D75 => D75_whitepoint, 255 $D65 => D65_whitepoint, 256 $D55 => D55_whitepoint, 257 $D50 => D50_whitepoint, 258 $A => A_whitepoint, 259 $B => B_whitepoint, 260 $C => C_whitepoint, 261 $E => E_whitepoint, 262 $D3250 => D3250_whitepoint 263]; 264 265/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. 266 */ 267im_D502D65 xyz 268 = xyz''' 269{ 270 xyz' = xyz / D50_whitepoint; 271 272 rgb = recomb XYZ2RGBbrad xyz'; 273 274 // move white in bradford RGB 275 rgb' = rgb / Vector [0.94, 1.02, 1.33]; 276 277 xyz'' = recomb RGBbrad2XYZ rgb'; 278 279 // back to D65 280 xyz''' = xyz'' * D65_whitepoint; 281} 282 283/* Convert D65 XYZ to D50 using the bradford approx. 284 */ 285im_D652D50 xyz 286 = xyz''' 287{ 288 xyz' = xyz / D65_whitepoint; 289 290 rgb = recomb XYZ2RGBbrad xyz'; 291 292 // move white in bradford RGB 293 rgb' = rgb * Vector [0.94, 1.02, 1.33]; 294 295 xyz'' = recomb RGBbrad2XYZ rgb'; 296 297 xyz''' = xyz'' * D50_whitepoint; 298} 299 300/* Convert D50 XYZ to Lab. 301 */ 302im_D50XYZ2Lab xyz 303 = im_XYZ2Lab_temp xyz 304 D50_whitepoint.value?0 305 D50_whitepoint.value?1 306 D50_whitepoint.value?2; 307im_D50Lab2XYZ lab 308 = im_Lab2XYZ_temp lab 309 D50_whitepoint.value?0 310 D50_whitepoint.value?1 311 D50_whitepoint.value?2; 312 313/* ... and mono conversions 314 */ 315im_sRGB2mono in 316 = (image_set_type Image_type.B_W @ 317 clip2fmt (get_header "BandFmt" in) @ 318 recomb (Matrix [[.3, .6, .1]])) in; 319im_mono2sRGB in 320 = image_set_type Image_type.sRGB (in ++ in ++ in); 321 322im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; 323 324im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; 325 326// from the 16 bit RGB and GREY formats 327im_1628 x = im_clip (x >> 8); 328im_162f x = x / 256; 329 330im_8216 x = (im_clip2us x) << 8; 331im_f216 x = im_clip2us (x * 256); 332 333im_RGB162GREY16 in 334 = (image_set_type Image_type.GREY16 @ 335 clip2fmt (get_header "BandFmt" in) @ 336 recomb (Matrix [[.3, .6, .1]])) in; 337im_GREY162RGB16 in 338 = image_set_type Image_type.RGB16 (in ++ in ++ in); 339 340/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands 341 * on the way out. Except if it's LABPACK. 342 */ 343colour_apply fn x 344 = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK 345 = x'' 346{ 347 b = get_bands x; 348 c = get_coding x; 349 350 first 351 = extract_bands 0 3 x, b > 3 352 = extract_bands 0 1 x; 353 tail 354 = extract_bands 3 (b - 3) x, b > 3 355 = extract_bands 1 (b - 1) x; 356 x' = fn first; 357 x'' = x' ++ clip2fmt (get_format x') tail; 358} 359 360/* Any 1-ary colour op, applied to Vector/Image/Matrix or image 361 */ 362colour_unary fn x 363 = oo_unary_function colour_op x, is_class x 364 = colour_apply fn x, is_image x 365 = colour_apply fn [x], is_real x 366 = error (_ "bad arguments to " ++ "colour_unary") 367{ 368 // COMPOUND_REWRAP ... signal to the colour class to go to image and 369 // back 370 colour_op = Operator "colour_unary" 371 colour_object Operator_type.COMPOUND_REWRAP false; 372 373 colour_object x 374 = colour_real_list x, is_real_list x 375 = map colour_real_list x, is_matrix x 376 = colour_apply fn x, is_image x 377 = error (_ "bad arguments to " ++ "colour_unary"); 378 379 colour_real_list l 380 = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; 381} 382 383/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... 384 * name is op name for error messages etc. 385 */ 386colour_binary name fn x y 387 = oo_binary_function colour_op x y, is_class x 388 = oo_binary'_function colour_op x y, is_class y 389 = fn x y, is_image x && is_image y 390 = error (_ "bad arguments to " ++ name) 391{ 392 colour_op = Operator name 393 colour_object Operator_type.COMPOUND_REWRAP true; 394 395 colour_object x y 396 = fn x y, is_image x && is_image y 397 = colour_real_list fn x y, is_real_list x && is_real_list y 398 = map (colour_real_list fn x) y, is_real_list x && is_matrix y 399 = map (colour_real_list (converse fn) y) x, 400 is_matrix x && is_real_list y 401 = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y 402 = error (_ "bad arguments to " ++ name); 403 404 colour_real_list fn l1 l2 405 = (to_matrix (fn i1 i2)).value?0 406 { 407 i1 = (float) (to_image (Vector l1)).value; 408 i2 = (float) (to_image (Vector l2)).value; 409 } 410} 411 412_colour_conversion_table = [ 413 /* Lines are [space-from, space-to, conversion function]. Could do 414 * this as a big array, but table lookup feels safer. 415 */ 416 [B_W, B_W, image_set_type B_W], 417 [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], 418 [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], 419 [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], 420 [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], 421 [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], 422 [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], 423 [B_W, sRGB, im_mono2sRGB @ im_clip], 424 [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], 425 [B_W, GREY16, image_set_type GREY16 @ im_8216], 426 [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], 427 [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ 428 im_mono2sRGB @ im_clip], 429 430 [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], 431 [XYZ, XYZ, image_set_type XYZ], 432 [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], 433 [XYZ, LAB, im_XYZ2Lab @ im_clip2f], 434 [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], 435 [XYZ, UCS, im_XYZ2UCS @ im_clip2f], 436 [XYZ, RGB, im_XYZ2disp @ im_clip2f], 437 [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], 438 [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], 439 [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], 440 441 [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], 442 [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], 443 [YXY, YXY, image_set_type YXY], 444 [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], 445 [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], 446 [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], 447 [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], 448 [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], 449 [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], 450 [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ 451 im_clip2f], 452 453 [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], 454 [LAB, XYZ, im_Lab2XYZ @ im_clip2f], 455 [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], 456 [LAB, LAB, image_set_type LAB @ im_clip2f], 457 [LAB, LCH, im_Lab2LCh @ im_clip2f], 458 [LAB, UCS, im_Lab2UCS @ im_clip2f], 459 [LAB, RGB, im_Lab2disp @ im_clip2f], 460 [LAB, sRGB, im_Lab2sRGB @ im_clip2f], 461 [LAB, LABQ, im_Lab2LabQ @ im_clip2f], 462 [LAB, LABS, im_Lab2LabS @ im_clip2f], 463 464 [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], 465 [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], 466 [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], 467 [LCH, LAB, im_LCh2Lab @ im_clip2f], 468 [LCH, LCH, image_set_type LCH], 469 [LCH, UCS, im_LCh2UCS @ im_clip2f], 470 [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], 471 [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], 472 [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], 473 [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], 474 475 [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], 476 [UCS, XYZ, im_UCS2XYZ @ im_clip2f], 477 [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], 478 [UCS, LAB, im_UCS2Lab @ im_clip2f], 479 [UCS, LCH, im_UCS2LCh @ im_clip2f], 480 [UCS, UCS, image_set_type UCS], 481 [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], 482 [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], 483 [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], 484 [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], 485 486 [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], 487 [RGB, XYZ, im_disp2XYZ @ im_clip], 488 [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], 489 [RGB, LAB, im_disp2Lab @ im_clip], 490 [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], 491 [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], 492 [RGB, RGB, image_set_type RGB], 493 [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], 494 [RGB, RGB16, image_set_type RGB16 @ im_8216], 495 [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], 496 [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], 497 [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], 498 499 [sRGB, B_W, im_sRGB2mono], 500 [sRGB, XYZ, im_sRGB2XYZ @ im_clip], 501 [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], 502 [sRGB, LAB, im_sRGB2Lab @ im_clip], 503 [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], 504 [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], 505 [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], 506 [sRGB, sRGB, image_set_type sRGB], 507 [sRGB, RGB16, image_set_type RGB16 @ im_8216], 508 [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], 509 [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], 510 [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], 511 512 [RGB16, B_W, im_1628 @ im_sRGB2mono], 513 [RGB16, RGB, image_set_type RGB @ im_1628], 514 [RGB16, sRGB, image_set_type sRGB @ im_1628], 515 [RGB16, RGB16, image_set_type RGB16], 516 [RGB16, GREY16, im_RGB162GREY16], 517 518 [GREY16, B_W, image_set_type B_W @ im_1628], 519 [GREY16, RGB, im_mono2sRGB @ im_1628], 520 [GREY16, sRGB, im_mono2sRGB @ im_1628], 521 [GREY16, RGB16, im_GREY162RGB16], 522 [GREY16, GREY16, image_set_type GREY16], 523 524 [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], 525 [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], 526 [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], 527 [LABQ, LAB, im_LabQ2Lab], 528 [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], 529 [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], 530 [LABQ, RGB, im_LabQ2disp], 531 [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], 532 [LABQ, LABQ, image_set_type LABQ], 533 [LABQ, LABS, im_LabQ2LabS], 534 535 [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ 536 im_LabS2LabQ @ im_clip2s], 537 [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], 538 [LABS, YXY, im_XYZ2Yxy @ 539 im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], 540 [LABS, LAB, im_LabS2Lab], 541 [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], 542 [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], 543 [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], 544 [LABS, sRGB, im_XYZ2sRGB @ 545 im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], 546 [LABS, LABQ, im_LabS2LabQ @ im_clip2s], 547 [LABS, LABS, image_set_type LABS] 548] 549{ 550 /* From Image_type ... repeat here for brevity. Use same ordering as 551 * in Colour menu for consistency. 552 */ 553 B_W = 1; 554 XYZ = 12; 555 YXY = 23; 556 LAB = 13; 557 LCH = 19; 558 UCS = 18; 559 RGB = 17; 560 sRGB = 22; 561 RGB16 = 25; 562 GREY16 = 26; 563 LABQ = 16; 564 LABS = 21; 565} 566 567/* Transform between two colour spaces. 568 */ 569colour_transform from to in 570 = colour_unary _colour_conversion_table?i?2 in, i >= 0 571 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ 572 _ " to " ++ Image_type.type_names.get_name to) 573{ 574 match x = x?0 == from && x?1 == to; 575 i = index match _colour_conversion_table; 576} 577 578/* Transform to a colour space, assuming the type field in the input is 579 * correct 580 */ 581colour_transform_to to in = colour_transform (get_type in) to in; 582 583/* String for path separator on this platform. 584 */ 585path_separator = expand "$SEP"; 586 587/* Form a relative pathname. 588 * path_relative ["home", "john"] == "home/john" 589 * path_relative [] == "" 590 */ 591path_relative l = join_sep path_separator l; 592 593/* Form an absolute pathname. 594 * path_absolute ["home", "john"] == "/home/john" 595 * path_absolute [] == "/" 596 * If the first component looks like 'A:', don't add an initial separator. 597 */ 598path_absolute l 599 = path_relative l, 600 len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' 601 = path_separator ++ path_relative l; 602 603/* Parse a pathname. 604 * path_parse "/home/john" == ["home", "john"] 605 * path_parse "home/john" == ["home", "john"] 606 */ 607path_parse str 608 = split (equal path_separator?0) str; 609 610