001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.imaging.color; 018 019 020public final class ColorConversions { 021 private static final double REF_X = 95.047; // Observer= 2°, Illuminant= D65 022 private static final double REF_Y = 100.000; 023 private static final double REF_Z = 108.883; 024 025 private ColorConversions() { 026 } 027 028 public static ColorCieLab convertXYZtoCIELab(final ColorXyz xyz) { 029 return convertXYZtoCIELab(xyz.X, xyz.Y, xyz.Z); 030 } 031 032 public static ColorCieLab convertXYZtoCIELab(final double X, final double Y, 033 final double Z) { 034 035 double var_X = X / REF_X; // REF_X = 95.047 Observer= 2°, Illuminant= 036 // D65 037 double var_Y = Y / REF_Y; // REF_Y = 100.000 038 double var_Z = Z / REF_Z; // REF_Z = 108.883 039 040 if (var_X > 0.008856) { 041 var_X = Math.pow(var_X, (1 / 3.0)); 042 } else { 043 var_X = (7.787 * var_X) + (16 / 116.0); 044 } 045 if (var_Y > 0.008856) { 046 var_Y = Math.pow(var_Y, 1 / 3.0); 047 } else { 048 var_Y = (7.787 * var_Y) + (16 / 116.0); 049 } 050 if (var_Z > 0.008856) { 051 var_Z = Math.pow(var_Z, 1 / 3.0); 052 } else { 053 var_Z = (7.787 * var_Z) + (16 / 116.0); 054 } 055 056 final double L = (116 * var_Y) - 16; 057 final double a = 500 * (var_X - var_Y); 058 final double b = 200 * (var_Y - var_Z); 059 return new ColorCieLab(L, a, b); 060 } 061 062 public static ColorXyz convertCIELabtoXYZ(final ColorCieLab cielab) { 063 return convertCIELabtoXYZ(cielab.L, cielab.a, cielab.b); 064 } 065 066 public static ColorXyz convertCIELabtoXYZ(final double L, final double a, final double b) { 067 double var_Y = (L + 16) / 116.0; 068 double var_X = a / 500 + var_Y; 069 double var_Z = var_Y - b / 200.0; 070 071 if (Math.pow(var_Y, 3) > 0.008856) { 072 var_Y = Math.pow(var_Y, 3); 073 } else { 074 var_Y = (var_Y - 16 / 116.0) / 7.787; 075 } 076 if (Math.pow(var_X, 3) > 0.008856) { 077 var_X = Math.pow(var_X, 3); 078 } else { 079 var_X = (var_X - 16 / 116.0) / 7.787; 080 } 081 if (Math.pow(var_Z, 3) > 0.008856) { 082 var_Z = Math.pow(var_Z, 3); 083 } else { 084 var_Z = (var_Z - 16 / 116.0) / 7.787; 085 } 086 087 final double X = REF_X * var_X; // REF_X = 95.047 Observer= 2°, Illuminant= 088 // D65 089 final double Y = REF_Y * var_Y; // REF_Y = 100.000 090 final double Z = REF_Z * var_Z; // REF_Z = 108.883 091 092 return new ColorXyz(X, Y, Z); 093 } 094 095 public static ColorHunterLab convertXYZtoHunterLab(final ColorXyz xyz) { 096 return convertXYZtoHunterLab(xyz.X, xyz.Y, xyz.Z); 097 } 098 099 public static ColorHunterLab convertXYZtoHunterLab(final double X, 100 final double Y, final double Z) { 101 final double L = 10 * Math.sqrt(Y); 102 final double a = 17.5 * (((1.02 * X) - Y) / Math.sqrt(Y)); 103 final double b = 7 * ((Y - (0.847 * Z)) / Math.sqrt(Y)); 104 105 return new ColorHunterLab(L, a, b); 106 } 107 108 public static ColorXyz convertHunterLabtoXYZ(final ColorHunterLab cielab) { 109 return convertHunterLabtoXYZ(cielab.L, cielab.a, cielab.b); 110 } 111 112 public static ColorXyz convertHunterLabtoXYZ(final double L, final double a, 113 final double b) { 114 final double var_Y = L / 10; 115 final double var_X = a / 17.5 * L / 10; 116 final double var_Z = b / 7 * L / 10; 117 118 final double Y = Math.pow(var_Y, 2); 119 final double X = (var_X + Y) / 1.02; 120 final double Z = -(var_Z - Y) / 0.847; 121 122 return new ColorXyz(X, Y, Z); 123 } 124 125 public static int convertXYZtoRGB(final ColorXyz xyz) { 126 return convertXYZtoRGB(xyz.X, xyz.Y, xyz.Z); 127 } 128 129 public static int convertXYZtoRGB(final double X, final double Y, final double Z) { 130 // Observer = 2°, Illuminant = D65 131 final double var_X = X / 100.0; // Where X = 0 ÷ 95.047 132 final double var_Y = Y / 100.0; // Where Y = 0 ÷ 100.000 133 final double var_Z = Z / 100.0; // Where Z = 0 ÷ 108.883 134 135 double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; 136 double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; 137 double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; 138 139 if (var_R > 0.0031308) { 140 var_R = 1.055 * Math.pow(var_R, (1 / 2.4)) - 0.055; 141 } else { 142 var_R = 12.92 * var_R; 143 } 144 if (var_G > 0.0031308) { 145 var_G = 1.055 * Math.pow(var_G, (1 / 2.4)) - 0.055; 146 } else { 147 var_G = 12.92 * var_G; 148 } 149 if (var_B > 0.0031308) { 150 var_B = 1.055 * Math.pow(var_B, (1 / 2.4)) - 0.055; 151 } else { 152 var_B = 12.92 * var_B; 153 } 154 155 final double R = (var_R * 255); 156 final double G = (var_G * 255); 157 final double B = (var_B * 255); 158 159 return convertRGBtoRGB(R, G, B); 160 } 161 162 public static ColorXyz convertRGBtoXYZ(final int rgb) { 163 final int r = 0xff & (rgb >> 16); 164 final int g = 0xff & (rgb >> 8); 165 final int b = 0xff & (rgb >> 0); 166 167 double var_R = r / 255.0; // Where R = 0 ÷ 255 168 double var_G = g / 255.0; // Where G = 0 ÷ 255 169 double var_B = b / 255.0; // Where B = 0 ÷ 255 170 171 if (var_R > 0.04045) { 172 var_R = Math.pow((var_R + 0.055) / 1.055, 2.4); 173 } else { 174 var_R = var_R / 12.92; 175 } 176 if (var_G > 0.04045) { 177 var_G = Math.pow((var_G + 0.055) / 1.055, 2.4); 178 } else { 179 var_G = var_G / 12.92; 180 } 181 if (var_B > 0.04045) { 182 var_B = Math.pow((var_B + 0.055) / 1.055, 2.4); 183 } else { 184 var_B = var_B / 12.92; 185 } 186 187 var_R = var_R * 100; 188 var_G = var_G * 100; 189 var_B = var_B * 100; 190 191 // Observer. = 2°, Illuminant = D65 192 final double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; 193 final double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; 194 final double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; 195 196 return new ColorXyz(X, Y, Z); 197 } 198 199 public static ColorCmy convertRGBtoCMY(final int rgb) { 200 final int R = 0xff & (rgb >> 16); 201 final int G = 0xff & (rgb >> 8); 202 final int B = 0xff & (rgb >> 0); 203 204 // RGB values = 0 ÷ 255 205 // CMY values = 0 ÷ 1 206 207 final double C = 1 - (R / 255.0); 208 final double M = 1 - (G / 255.0); 209 final double Y = 1 - (B / 255.0); 210 211 return new ColorCmy(C, M, Y); 212 } 213 214 public static int convertCMYtoRGB(final ColorCmy cmy) { 215 // From Ghostscript's gdevcdj.c: 216 // * Ghostscript: R = (1.0 - C) * (1.0 - K) 217 // * Adobe: R = 1.0 - min(1.0, C + K) 218 // and similarly for G and B. 219 // This is Ghostscript's formula with K = 0. 220 221 // CMY values = 0 ÷ 1 222 // RGB values = 0 ÷ 255 223 224 final double R = (1 - cmy.C) * 255.0; 225 final double G = (1 - cmy.M) * 255.0; 226 final double B = (1 - cmy.Y) * 255.0; 227 228 return convertRGBtoRGB(R, G, B); 229 } 230 231 public static ColorCmyk convertCMYtoCMYK(final ColorCmy cmy) { 232 // Where CMYK and CMY values = 0 ÷ 1 233 234 double C = cmy.C; 235 double M = cmy.M; 236 double Y = cmy.Y; 237 238 double var_K = 1.0; 239 240 if (C < var_K) { 241 var_K = C; 242 } 243 if (M < var_K) { 244 var_K = M; 245 } 246 if (Y < var_K) { 247 var_K = Y; 248 } 249 if (var_K == 1) { // Black 250 C = 0; 251 M = 0; 252 Y = 0; 253 } else { 254 C = (C - var_K) / (1 - var_K); 255 M = (M - var_K) / (1 - var_K); 256 Y = (Y - var_K) / (1 - var_K); 257 } 258 return new ColorCmyk(C, M, Y, var_K); 259 } 260 261 public static ColorCmy convertCMYKtoCMY(final ColorCmyk cmyk) { 262 return convertCMYKtoCMY(cmyk.C, cmyk.M, cmyk.Y, cmyk.K); 263 } 264 265 public static ColorCmy convertCMYKtoCMY(double C, double M, double Y, 266 final double K) { 267 // Where CMYK and CMY values = 0 ÷ 1 268 269 C = (C * (1 - K) + K); 270 M = (M * (1 - K) + K); 271 Y = (Y * (1 - K) + K); 272 273 return new ColorCmy(C, M, Y); 274 } 275 276 public static int convertCMYKtoRGB(final int c, final int m, final int y, final int k) { 277 final double C = c / 255.0; 278 final double M = m / 255.0; 279 final double Y = y / 255.0; 280 final double K = k / 255.0; 281 282 return convertCMYtoRGB(convertCMYKtoCMY(C, M, Y, K)); 283 } 284 285 public static ColorHsl convertRGBtoHSL(final int rgb) { 286 287 final int R = 0xff & (rgb >> 16); 288 final int G = 0xff & (rgb >> 8); 289 final int B = 0xff & (rgb >> 0); 290 291 final double var_R = (R / 255.0); // Where RGB values = 0 ÷ 255 292 final double var_G = (G / 255.0); 293 final double var_B = (B / 255.0); 294 295 final double var_Min = Math.min(var_R, Math.min(var_G, var_B)); // Min. value 296 // of RGB 297 double var_Max; 298 boolean maxIsR = false; 299 boolean maxIsG = false; 300 if (var_R >= var_G && var_R >= var_B) { 301 var_Max = var_R; 302 maxIsR = true; 303 } else if (var_G > var_B) { 304 var_Max = var_G; 305 maxIsG = true; 306 } else { 307 var_Max = var_B; 308 } 309 final double del_Max = var_Max - var_Min; // Delta RGB value 310 311 final double L = (var_Max + var_Min) / 2.0; 312 313 double H, S; 314 // Debug.debug("del_Max", del_Max); 315 if (del_Max == 0) { 316 // This is a gray, no chroma... 317 318 H = 0; // HSL results = 0 ÷ 1 319 S = 0; 320 } else { 321 // Chromatic data... 322 323 // Debug.debug("L", L); 324 325 if (L < 0.5) { 326 S = del_Max / (var_Max + var_Min); 327 } else { 328 S = del_Max / (2 - var_Max - var_Min); 329 } 330 331 // Debug.debug("S", S); 332 333 final double del_R = (((var_Max - var_R) / 6) + (del_Max / 2)) / del_Max; 334 final double del_G = (((var_Max - var_G) / 6) + (del_Max / 2)) / del_Max; 335 final double del_B = (((var_Max - var_B) / 6) + (del_Max / 2)) / del_Max; 336 337 if (maxIsR) { 338 H = del_B - del_G; 339 } else if (maxIsG) { 340 H = (1 / 3.0) + del_R - del_B; 341 } else { 342 H = (2 / 3.0) + del_G - del_R; 343 } 344 345 // Debug.debug("H1", H); 346 347 if (H < 0) { 348 H += 1; 349 } 350 if (H > 1) { 351 H -= 1; 352 } 353 354 // Debug.debug("H2", H); 355 } 356 357 return new ColorHsl(H, S, L); 358 } 359 360 public static int convertHSLtoRGB(final ColorHsl hsl) { 361 return convertHSLtoRGB(hsl.H, hsl.S, hsl.L); 362 } 363 364 public static int convertHSLtoRGB(final double H, final double S, final double L) { 365 double R, G, B; 366 367 if (S == 0) { 368 // HSL values = 0 ÷ 1 369 R = L * 255; // RGB results = 0 ÷ 255 370 G = L * 255; 371 B = L * 255; 372 } else { 373 double var_2; 374 375 if (L < 0.5) { 376 var_2 = L * (1 + S); 377 } else { 378 var_2 = (L + S) - (S * L); 379 } 380 381 final double var_1 = 2 * L - var_2; 382 383 R = 255 * convertHuetoRGB(var_1, var_2, H + (1 / 3.0)); 384 G = 255 * convertHuetoRGB(var_1, var_2, H); 385 B = 255 * convertHuetoRGB(var_1, var_2, H - (1 / 3.0)); 386 } 387 388 return convertRGBtoRGB(R, G, B); 389 } 390 391 private static double convertHuetoRGB(final double v1, final double v2, double vH) { 392 if (vH < 0) { 393 vH += 1; 394 } 395 if (vH > 1) { 396 vH -= 1; 397 } 398 if ((6 * vH) < 1) { 399 return (v1 + (v2 - v1) * 6 * vH); 400 } 401 if ((2 * vH) < 1) { 402 return (v2); 403 } 404 if ((3 * vH) < 2) { 405 return (v1 + (v2 - v1) * ((2 / 3.0) - vH) * 6); 406 } 407 return (v1); 408 } 409 410 public static ColorHsv convertRGBtoHSV(final int rgb) { 411 final int R = 0xff & (rgb >> 16); 412 final int G = 0xff & (rgb >> 8); 413 final int B = 0xff & (rgb >> 0); 414 415 final double var_R = (R / 255.0); // RGB values = 0 ÷ 255 416 final double var_G = (G / 255.0); 417 final double var_B = (B / 255.0); 418 419 final double var_Min = Math.min(var_R, Math.min(var_G, var_B)); // Min. value 420 // of RGB 421 boolean maxIsR = false; 422 boolean maxIsG = false; 423 double var_Max; 424 if (var_R >= var_G && var_R >= var_B) { 425 var_Max = var_R; 426 maxIsR = true; 427 } else if (var_G > var_B) { 428 var_Max = var_G; 429 maxIsG = true; 430 } else { 431 var_Max = var_B; 432 } 433 final double del_Max = var_Max - var_Min; // Delta RGB value 434 435 final double V = var_Max; 436 437 double H, S; 438 if (del_Max == 0) { 439 // This is a gray, no chroma... 440 H = 0; // HSV results = 0 ÷ 1 441 S = 0; 442 } else { 443 // Chromatic data... 444 S = del_Max / var_Max; 445 446 final double del_R = (((var_Max - var_R) / 6) + (del_Max / 2)) / del_Max; 447 final double del_G = (((var_Max - var_G) / 6) + (del_Max / 2)) / del_Max; 448 final double del_B = (((var_Max - var_B) / 6) + (del_Max / 2)) / del_Max; 449 450 if (maxIsR) { 451 H = del_B - del_G; 452 } else if (maxIsG) { 453 H = (1 / 3.0) + del_R - del_B; 454 } else { 455 H = (2 / 3.0) + del_G - del_R; 456 } 457 458 if (H < 0) { 459 H += 1; 460 } 461 if (H > 1) { 462 H -= 1; 463 } 464 } 465 466 return new ColorHsv(H, S, V); 467 } 468 469 public static int convertHSVtoRGB(final ColorHsv HSV) { 470 return convertHSVtoRGB(HSV.H, HSV.S, HSV.V); 471 } 472 473 public static int convertHSVtoRGB(final double H, final double S, final double V) { 474 double R, G, B; 475 476 if (S == 0) { 477 // HSV values = 0 ÷ 1 478 R = V * 255; 479 G = V * 255; 480 B = V * 255; 481 } else { 482 double var_h = H * 6; 483 if (var_h == 6) { 484 var_h = 0; // H must be < 1 485 } 486 final double var_i = Math.floor(var_h); // Or ... var_i = floor( var_h ) 487 final double var_1 = V * (1 - S); 488 final double var_2 = V * (1 - S * (var_h - var_i)); 489 final double var_3 = V * (1 - S * (1 - (var_h - var_i))); 490 491 double var_r, var_g, var_b; 492 493 if (var_i == 0) { 494 var_r = V; 495 var_g = var_3; 496 var_b = var_1; 497 } else if (var_i == 1) { 498 var_r = var_2; 499 var_g = V; 500 var_b = var_1; 501 } else if (var_i == 2) { 502 var_r = var_1; 503 var_g = V; 504 var_b = var_3; 505 } else if (var_i == 3) { 506 var_r = var_1; 507 var_g = var_2; 508 var_b = V; 509 } else if (var_i == 4) { 510 var_r = var_3; 511 var_g = var_1; 512 var_b = V; 513 } else { 514 var_r = V; 515 var_g = var_1; 516 var_b = var_2; 517 } 518 519 R = var_r * 255; // RGB results = 0 ÷ 255 520 G = var_g * 255; 521 B = var_b * 255; 522 } 523 524 return convertRGBtoRGB(R, G, B); 525 } 526 527 public static int convertCMYKtoRGB_Adobe(final int sc, final int sm, final int sy, 528 final int sk) { 529 final int red = 255 - (sc + sk); 530 final int green = 255 - (sm + sk); 531 final int blue = 255 - (sy + sk); 532 533 return convertRGBtoRGB(red, green, blue); 534 } 535 536 private static double cube(final double f) { 537 return f * f * f; 538 } 539 540 private static double square(final double f) { 541 return f * f; 542 } 543 544 public static int convertCIELabtoARGBTest(final int cieL, final int cieA, final int cieB) { 545 double X, Y, Z; 546 547 { 548 549 double var_Y = ((cieL * 100.0 / 255.0) + 16.0) / 116.0; 550 double var_X = cieA / 500.0 + var_Y; 551 double var_Z = var_Y - cieB / 200.0; 552 553 final double var_x_cube = cube(var_X); 554 final double var_y_cube = cube(var_Y); 555 final double var_z_cube = cube(var_Z); 556 557 if (var_y_cube > 0.008856) { 558 var_Y = var_y_cube; 559 } else { 560 var_Y = (var_Y - 16 / 116.0) / 7.787; 561 } 562 563 if (var_x_cube > 0.008856) { 564 var_X = var_x_cube; 565 } else { 566 var_X = (var_X - 16 / 116.0) / 7.787; 567 } 568 569 if (var_z_cube > 0.008856) { 570 var_Z = var_z_cube; 571 } else { 572 var_Z = (var_Z - 16 / 116.0) / 7.787; 573 } 574 575 // double REF_X = 95.047; 576 // double REF_Y = 100.000; 577 // double REF_Z = 108.883; 578 579 X = REF_X * var_X; // REF_X = 95.047 Observer= 2°, Illuminant= D65 580 Y = REF_Y * var_Y; // REF_Y = 100.000 581 Z = REF_Z * var_Z; // REF_Z = 108.883 582 583 } 584 585 double R, G, B; 586 { 587 final double var_X = X / 100; // X = From 0 to REF_X 588 final double var_Y = Y / 100; // Y = From 0 to REF_Y 589 final double var_Z = Z / 100; // Z = From 0 to REF_Y 590 591 double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; 592 double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; 593 double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; 594 595 if (var_R > 0.0031308) { 596 var_R = 1.055 * Math.pow(var_R, (1 / 2.4)) - 0.055; 597 } else { 598 var_R = 12.92 * var_R; 599 } 600 if (var_G > 0.0031308) { 601 var_G = 1.055 * Math.pow(var_G, (1 / 2.4)) - 0.055; 602 } else { 603 var_G = 12.92 * var_G; 604 } 605 606 if (var_B > 0.0031308) { 607 var_B = 1.055 * Math.pow(var_B, (1 / 2.4)) - 0.055; 608 } else { 609 var_B = 12.92 * var_B; 610 } 611 612 R = (var_R * 255); 613 G = (var_G * 255); 614 B = (var_B * 255); 615 } 616 617 return convertRGBtoRGB(R, G, B); 618 } 619 620 private static int convertRGBtoRGB(final double R, final double G, final double B) { 621 int red = (int) Math.round(R); 622 int green = (int) Math.round(G); 623 int blue = (int) Math.round(B); 624 625 red = Math.min(255, Math.max(0, red)); 626 green = Math.min(255, Math.max(0, green)); 627 blue = Math.min(255, Math.max(0, blue)); 628 629 final int alpha = 0xff; 630 final int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); 631 632 return rgb; 633 } 634 635 private static int convertRGBtoRGB(int red, int green, int blue) { 636 red = Math.min(255, Math.max(0, red)); 637 green = Math.min(255, Math.max(0, green)); 638 blue = Math.min(255, Math.max(0, blue)); 639 640 final int alpha = 0xff; 641 final int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); 642 643 return rgb; 644 } 645 646 public static ColorCieLch convertCIELabtoCIELCH(final ColorCieLab cielab) { 647 return convertCIELabtoCIELCH(cielab.L, cielab.a, cielab.b); 648 } 649 650 public static ColorCieLch convertCIELabtoCIELCH(final double L, final double a, final double b) { 651 double var_H = Math.atan2(b, a); // Quadrant by signs 652 653 if (var_H > 0) { 654 var_H = (var_H / Math.PI) * 180.0; 655 } else { 656 var_H = 360 - radian_2_degree(Math.abs(var_H)); 657 } 658 659 // L = L; 660 final double C = Math.sqrt(square(a) + square(b)); 661 final double H = var_H; 662 663 return new ColorCieLch(L, C, H); 664 } 665 666 public static ColorCieLab convertCIELCHtoCIELab(final ColorCieLch cielch) { 667 return convertCIELCHtoCIELab(cielch.L, cielch.C, cielch.H); 668 } 669 670 public static ColorCieLab convertCIELCHtoCIELab(final double L, final double C, final double H) { 671 // Where CIE-H° = 0 ÷ 360° 672 673 // CIE-L* = CIE-L; 674 final double a = Math.cos(degree_2_radian(H)) * C; 675 final double b = Math.sin(degree_2_radian(H)) * C; 676 677 return new ColorCieLab(L, a, b); 678 } 679 680 public static double degree_2_radian(final double degree) { 681 return degree * Math.PI / 180.0; 682 } 683 684 public static double radian_2_degree(final double radian) { 685 return radian * 180.0 / Math.PI; 686 } 687 688 public static ColorCieLuv convertXYZtoCIELuv(final ColorXyz xyz) { 689 return convertXYZtoCIELuv(xyz.X, xyz.Y, xyz.Z); 690 } 691 692 public static ColorCieLuv convertXYZtoCIELuv(final double X, final double Y, final double Z) { 693 // problems here with div by zero 694 695 final double var_U = (4 * X) / (X + (15 * Y) + (3 * Z)); 696 final double var_V = (9 * Y) / (X + (15 * Y) + (3 * Z)); 697 698 // Debug.debug("var_U", var_U); 699 // Debug.debug("var_V", var_V); 700 701 double var_Y = Y / 100.0; 702 // Debug.debug("var_Y", var_Y); 703 704 if (var_Y > 0.008856) { 705 var_Y = Math.pow(var_Y, (1 / 3.0)); 706 } else { 707 var_Y = (7.787 * var_Y) + (16 / 116.0); 708 } 709 710 // Debug.debug("var_Y", var_Y); 711 712 final double ref_U = (4 * REF_X) / (REF_X + (15 * REF_Y) + (3 * REF_Z)); 713 final double ref_V = (9 * REF_Y) / (REF_X + (15 * REF_Y) + (3 * REF_Z)); 714 715 // Debug.debug("ref_U", ref_U); 716 // Debug.debug("ref_V", ref_V); 717 718 final double L = (116 * var_Y) - 16; 719 final double u = 13 * L * (var_U - ref_U); 720 final double v = 13 * L * (var_V - ref_V); 721 722 return new ColorCieLuv(L, u, v); 723 } 724 725 public static ColorXyz convertCIELuvtoXYZ(final ColorCieLuv cielch) { 726 return convertCIELuvtoXYZ(cielch.L, cielch.u, cielch.v); 727 } 728 729 public static ColorXyz convertCIELuvtoXYZ(final double L, final double u, final double v) { 730 // problems here with div by zero 731 732 double var_Y = (L + 16) / 116; 733 if (Math.pow(var_Y, 3) > 0.008856) { 734 var_Y = Math.pow(var_Y, 3); 735 } else { 736 var_Y = (var_Y - 16 / 116) / 7.787; 737 } 738 739 final double ref_U = (4 * REF_X) / (REF_X + (15 * REF_Y) + (3 * REF_Z)); 740 final double ref_V = (9 * REF_Y) / (REF_X + (15 * REF_Y) + (3 * REF_Z)); 741 final double var_U = u / (13 * L) + ref_U; 742 final double var_V = v / (13 * L) + ref_V; 743 744 final double Y = var_Y * 100; 745 final double X = -(9 * Y * var_U) / ((var_U - 4) * var_V - var_U * var_V); 746 final double Z = (9 * Y - (15 * var_V * Y) - (var_V * X)) / (3 * var_V); 747 748 return new ColorXyz(X, Y, Z); 749 } 750}