1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.graphics.cts; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.graphics.ColorSpace; 27 import android.support.test.filters.SmallTest; 28 import android.support.test.runner.AndroidJUnit4; 29 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 33 import java.util.Arrays; 34 import java.util.function.DoubleUnaryOperator; 35 36 @SmallTest 37 @RunWith(AndroidJUnit4.class) 38 public class ColorSpaceTest { 39 // Column-major RGB->XYZ transform matrix for the sRGB color space 40 private static final float[] SRGB_TO_XYZ = { 41 0.412391f, 0.212639f, 0.019331f, 42 0.357584f, 0.715169f, 0.119195f, 43 0.180481f, 0.072192f, 0.950532f 44 }; 45 // Column-major XYZ->RGB transform matrix for the sRGB color space 46 private static final float[] XYZ_TO_SRGB = { 47 3.240970f, -0.969244f, 0.055630f, 48 -1.537383f, 1.875968f, -0.203977f, 49 -0.498611f, 0.041555f, 1.056971f 50 }; 51 52 // Column-major RGB->XYZ transform matrix for the sRGB color space and a D50 white point 53 private static final float[] SRGB_TO_XYZ_D50 = { 54 0.4360747f, 0.2225045f, 0.0139322f, 55 0.3850649f, 0.7168786f, 0.0971045f, 56 0.1430804f, 0.0606169f, 0.7141733f 57 }; 58 59 private static final float[] SRGB_PRIMARIES_xyY = 60 { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }; 61 private static final float[] SRGB_WHITE_POINT_xyY = { 0.3127f, 0.3290f }; 62 63 private static final float[] SRGB_PRIMARIES_XYZ = { 64 1.939394f, 1.000000f, 0.090909f, 65 0.500000f, 1.000000f, 0.166667f, 66 2.500000f, 1.000000f, 13.166667f 67 }; 68 private static final float[] SRGB_WHITE_POINT_XYZ = { 0.950456f, 1.000f, 1.089058f }; 69 70 private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity(); 71 72 @Test testNamedColorSpaces()73 public void testNamedColorSpaces() { 74 for (ColorSpace.Named named : ColorSpace.Named.values()) { 75 ColorSpace colorSpace = ColorSpace.get(named); 76 assertNotNull(colorSpace.getName()); 77 assertNotNull(colorSpace); 78 assertEquals(named.ordinal(), colorSpace.getId()); 79 assertTrue(colorSpace.getComponentCount() >= 1); 80 assertTrue(colorSpace.getComponentCount() <= 4); 81 } 82 } 83 84 @Test(expected = IllegalArgumentException.class) testNullName()85 public void testNullName() { 86 new ColorSpace.Rgb(null, new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f); 87 } 88 89 @Test(expected = IllegalArgumentException.class) testEmptyName()90 public void testEmptyName() { 91 new ColorSpace.Rgb("", new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f); 92 } 93 94 @Test testName()95 public void testName() { 96 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2], 97 sIdentity, sIdentity, 0.0f, 1.0f); 98 assertEquals("Test", cs.getName()); 99 } 100 101 @Test(expected = IllegalArgumentException.class) testPrimariesLength()102 public void testPrimariesLength() { 103 new ColorSpace.Rgb("Test", new float[7], new float[2], sIdentity, sIdentity, 0.0f, 1.0f); 104 } 105 106 @Test(expected = IllegalArgumentException.class) testWhitePointLength()107 public void testWhitePointLength() { 108 new ColorSpace.Rgb("Test", new float[6], new float[1], sIdentity, sIdentity, 0.0f, 1.0f); 109 } 110 111 @Test(expected = IllegalArgumentException.class) testNullOETF()112 public void testNullOETF() { 113 new ColorSpace.Rgb("Test", new float[6], new float[2], null, sIdentity, 0.0f, 1.0f); 114 } 115 116 @Test testOETF()117 public void testOETF() { 118 DoubleUnaryOperator op = Math::sqrt; 119 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2], 120 op, sIdentity, 0.0f, 1.0f); 121 assertEquals(0.5, cs.getOetf().applyAsDouble(0.25), 1e-5); 122 } 123 124 @Test(expected = IllegalArgumentException.class) testNullEOTF()125 public void testNullEOTF() { 126 new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, null, 0.0f, 1.0f); 127 } 128 129 @Test testEOTF()130 public void testEOTF() { 131 DoubleUnaryOperator op = x -> x * x; 132 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2], 133 sIdentity, op, 0.0f, 1.0f); 134 assertEquals(0.0625, cs.getEotf().applyAsDouble(0.25), 1e-5); 135 } 136 137 @Test(expected = IllegalArgumentException.class) testInvalidRange()138 public void testInvalidRange() { 139 new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, sIdentity, 2.0f, 1.0f); 140 } 141 142 @Test testRanges()143 public void testRanges() { 144 ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB); 145 146 float m1 = cs.getMinValue(0); 147 float m2 = cs.getMinValue(1); 148 float m3 = cs.getMinValue(2); 149 150 assertEquals(0.0f, m1, 1e-9f); 151 assertEquals(0.0f, m2, 1e-9f); 152 assertEquals(0.0f, m3, 1e-9f); 153 154 m1 = cs.getMaxValue(0); 155 m2 = cs.getMaxValue(1); 156 m3 = cs.getMaxValue(2); 157 158 assertEquals(1.0f, m1, 1e-9f); 159 assertEquals(1.0f, m2, 1e-9f); 160 assertEquals(1.0f, m3, 1e-9f); 161 162 cs = ColorSpace.get(ColorSpace.Named.CIE_LAB); 163 164 m1 = cs.getMinValue(0); 165 m2 = cs.getMinValue(1); 166 m3 = cs.getMinValue(2); 167 168 assertEquals(0.0f, m1, 1e-9f); 169 assertEquals(-128.0f, m2, 1e-9f); 170 assertEquals(-128.0f, m3, 1e-9f); 171 172 m1 = cs.getMaxValue(0); 173 m2 = cs.getMaxValue(1); 174 m3 = cs.getMaxValue(2); 175 176 assertEquals(100.0f, m1, 1e-9f); 177 assertEquals(128.0f, m2, 1e-9f); 178 assertEquals(128.0f, m3, 1e-9f); 179 180 cs = ColorSpace.get(ColorSpace.Named.CIE_XYZ); 181 182 m1 = cs.getMinValue(0); 183 m2 = cs.getMinValue(1); 184 m3 = cs.getMinValue(2); 185 186 assertEquals(-2.0f, m1, 1e-9f); 187 assertEquals(-2.0f, m2, 1e-9f); 188 assertEquals(-2.0f, m3, 1e-9f); 189 190 m1 = cs.getMaxValue(0); 191 m2 = cs.getMaxValue(1); 192 m3 = cs.getMaxValue(2); 193 194 assertEquals(2.0f, m1, 1e-9f); 195 assertEquals(2.0f, m2, 1e-9f); 196 assertEquals(2.0f, m3, 1e-9f); 197 } 198 199 @Test testMat3x3()200 public void testMat3x3() { 201 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity); 202 203 float[] rgbToXYZ = cs.getTransform(); 204 for (int i = 0; i < 9; i++) { 205 assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f); 206 } 207 } 208 209 @Test testMat3x3Inverse()210 public void testMat3x3Inverse() { 211 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity); 212 213 float[] xyzToRGB = cs.getInverseTransform(); 214 for (int i = 0; i < 9; i++) { 215 assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f); 216 } 217 } 218 219 @Test testMat3x3Primaries()220 public void testMat3x3Primaries() { 221 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity); 222 223 float[] primaries = cs.getPrimaries(); 224 225 assertNotNull(primaries); 226 assertEquals(6, primaries.length); 227 228 assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-5f); 229 assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-5f); 230 assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-5f); 231 assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-5f); 232 assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-5f); 233 assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-5f); 234 } 235 236 @Test testMat3x3WhitePoint()237 public void testMat3x3WhitePoint() { 238 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity); 239 240 float[] whitePoint = cs.getWhitePoint(); 241 242 assertNotNull(whitePoint); 243 assertEquals(2, whitePoint.length); 244 245 assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-5f); 246 assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-5f); 247 } 248 249 @Test testXYZFromPrimaries_xyY()250 public void testXYZFromPrimaries_xyY() { 251 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_xyY, SRGB_WHITE_POINT_xyY, 252 sIdentity, sIdentity, 0.0f, 1.0f); 253 254 float[] rgbToXYZ = cs.getTransform(); 255 for (int i = 0; i < 9; i++) { 256 assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f); 257 } 258 259 float[] xyzToRGB = cs.getInverseTransform(); 260 for (int i = 0; i < 9; i++) { 261 assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f); 262 } 263 } 264 265 @Test testXYZFromPrimaries_XYZ()266 public void testXYZFromPrimaries_XYZ() { 267 ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_XYZ, SRGB_WHITE_POINT_XYZ, 268 sIdentity, sIdentity, 0.0f, 1.0f); 269 270 float[] primaries = cs.getPrimaries(); 271 272 assertNotNull(primaries); 273 assertEquals(6, primaries.length); 274 275 // SRGB_PRIMARIES_xyY only has 1e-3 of precision, match it 276 assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-3f); 277 assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-3f); 278 assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-3f); 279 assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-3f); 280 assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-3f); 281 assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-3f); 282 283 float[] whitePoint = cs.getWhitePoint(); 284 285 assertNotNull(whitePoint); 286 assertEquals(2, whitePoint.length); 287 288 // SRGB_WHITE_POINT_xyY only has 1e-3 of precision, match it 289 assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-3f); 290 assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-3f); 291 292 float[] rgbToXYZ = cs.getTransform(); 293 for (int i = 0; i < 9; i++) { 294 assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f); 295 } 296 297 float[] xyzToRGB = cs.getInverseTransform(); 298 for (int i = 0; i < 9; i++) { 299 assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f); 300 } 301 } 302 303 @Test testGetComponentCount()304 public void testGetComponentCount() { 305 assertEquals(3, ColorSpace.get(ColorSpace.Named.SRGB).getComponentCount()); 306 assertEquals(3, ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).getComponentCount()); 307 assertEquals(3, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).getComponentCount()); 308 assertEquals(3, ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).getComponentCount()); 309 assertEquals(3, ColorSpace.get(ColorSpace.Named.DISPLAY_P3).getComponentCount()); 310 assertEquals(3, ColorSpace.get(ColorSpace.Named.CIE_LAB).getComponentCount()); 311 assertEquals(3, ColorSpace.get(ColorSpace.Named.CIE_XYZ).getComponentCount()); 312 } 313 314 @Test testIsSRGB()315 public void testIsSRGB() { 316 assertTrue(ColorSpace.get(ColorSpace.Named.SRGB).isSrgb()); 317 assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).isSrgb()); 318 assertFalse(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isSrgb()); 319 assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).isSrgb()); 320 assertFalse(ColorSpace.get(ColorSpace.Named.DISPLAY_P3).isSrgb()); 321 assertFalse(ColorSpace.get(ColorSpace.Named.CIE_LAB).isSrgb()); 322 assertFalse(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isSrgb()); 323 324 ColorSpace.Rgb cs = new ColorSpace.Rgb("My sRGB", SRGB_TO_XYZ, 325 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f)); 326 assertTrue(cs.isSrgb()); 327 } 328 329 @Test testIsWideGamut()330 public void testIsWideGamut() { 331 assertFalse(ColorSpace.get(ColorSpace.Named.SRGB).isWideGamut()); 332 assertFalse(ColorSpace.get(ColorSpace.Named.BT709).isWideGamut()); 333 assertTrue(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isWideGamut()); 334 assertTrue(ColorSpace.get(ColorSpace.Named.DCI_P3).isWideGamut()); 335 assertTrue(ColorSpace.get(ColorSpace.Named.BT2020).isWideGamut()); 336 assertTrue(ColorSpace.get(ColorSpace.Named.ACES).isWideGamut()); 337 assertTrue(ColorSpace.get(ColorSpace.Named.CIE_LAB).isWideGamut()); 338 assertTrue(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isWideGamut()); 339 } 340 341 @Test testWhitePoint()342 public void testWhitePoint() { 343 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 344 345 float[] whitePoint = cs.getWhitePoint(); 346 347 assertNotNull(whitePoint); 348 assertEquals(2, whitePoint.length); 349 350 // Make sure a copy is returned 351 Arrays.fill(whitePoint, Float.NaN); 352 assertArrayNotEquals(whitePoint, cs.getWhitePoint(), 1e-5f); 353 assertSame(whitePoint, cs.getWhitePoint(whitePoint)); 354 assertArrayEquals(whitePoint, cs.getWhitePoint(), 1e-5f); 355 } 356 357 @Test testPrimaries()358 public void testPrimaries() { 359 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 360 361 float[] primaries = cs.getPrimaries(); 362 363 assertNotNull(primaries); 364 assertEquals(6, primaries.length); 365 366 // Make sure a copy is returned 367 Arrays.fill(primaries, Float.NaN); 368 assertArrayNotEquals(primaries, cs.getPrimaries(), 1e-5f); 369 assertSame(primaries, cs.getPrimaries(primaries)); 370 assertArrayEquals(primaries, cs.getPrimaries(), 1e-5f); 371 } 372 373 @Test testRGBtoXYZMatrix()374 public void testRGBtoXYZMatrix() { 375 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 376 377 float[] rgbToXYZ = cs.getTransform(); 378 379 assertNotNull(rgbToXYZ); 380 assertEquals(9, rgbToXYZ.length); 381 382 // Make sure a copy is returned 383 Arrays.fill(rgbToXYZ, Float.NaN); 384 assertArrayNotEquals(rgbToXYZ, cs.getTransform(), 1e-5f); 385 assertSame(rgbToXYZ, cs.getTransform(rgbToXYZ)); 386 assertArrayEquals(rgbToXYZ, cs.getTransform(), 1e-5f); 387 } 388 389 @Test testXYZtoRGBMatrix()390 public void testXYZtoRGBMatrix() { 391 ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 392 393 float[] xyzToRGB = cs.getInverseTransform(); 394 395 assertNotNull(xyzToRGB); 396 assertEquals(9, xyzToRGB.length); 397 398 // Make sure a copy is returned 399 Arrays.fill(xyzToRGB, Float.NaN); 400 assertArrayNotEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f); 401 assertSame(xyzToRGB, cs.getInverseTransform(xyzToRGB)); 402 assertArrayEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f); 403 } 404 405 @Test testRGBtoXYZ()406 public void testRGBtoXYZ() { 407 ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB); 408 409 float[] source = { 0.75f, 0.5f, 0.25f }; 410 float[] expected = { 0.3012f, 0.2679f, 0.0840f }; 411 412 float[] r1 = cs.toXyz(source[0], source[1], source[2]); 413 assertNotNull(r1); 414 assertEquals(3, r1.length); 415 assertArrayNotEquals(source, r1, 1e-5f); 416 assertArrayEquals(expected, r1, 1e-3f); 417 418 float[] r3 = { source[0], source[1], source[2] }; 419 assertSame(r3, cs.toXyz(r3)); 420 assertEquals(3, r3.length); 421 assertArrayEquals(r1, r3, 1e-5f); 422 } 423 424 @Test testXYZtoRGB()425 public void testXYZtoRGB() { 426 ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB); 427 428 float[] source = { 0.3012f, 0.2679f, 0.0840f }; 429 float[] expected = { 0.75f, 0.5f, 0.25f }; 430 431 float[] r1 = cs.fromXyz(source[0], source[1], source[2]); 432 assertNotNull(r1); 433 assertEquals(3, r1.length); 434 assertArrayNotEquals(source, r1, 1e-5f); 435 assertArrayEquals(expected, r1, 1e-3f); 436 437 float[] r3 = { source[0], source[1], source[2] }; 438 assertSame(r3, cs.fromXyz(r3)); 439 assertEquals(3, r3.length); 440 assertArrayEquals(r1, r3, 1e-5f); 441 } 442 443 @Test testConnect()444 public void testConnect() { 445 ColorSpace.Connector connector = ColorSpace.connect( 446 ColorSpace.get(ColorSpace.Named.SRGB), 447 ColorSpace.get(ColorSpace.Named.DCI_P3)); 448 449 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource()); 450 assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination()); 451 assertSame(ColorSpace.RenderIntent.PERCEPTUAL, connector.getRenderIntent()); 452 453 connector = ColorSpace.connect( 454 ColorSpace.get(ColorSpace.Named.SRGB), 455 ColorSpace.get(ColorSpace.Named.SRGB)); 456 457 assertSame(connector.getDestination(), connector.getSource()); 458 assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent()); 459 460 connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3)); 461 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination()); 462 463 connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.SRGB)); 464 assertSame(connector.getSource(), connector.getDestination()); 465 } 466 467 @Test testConnector()468 public void testConnector() { 469 // Connect color spaces with same white points 470 ColorSpace.Connector connector = ColorSpace.connect( 471 ColorSpace.get(ColorSpace.Named.SRGB), 472 ColorSpace.get(ColorSpace.Named.ADOBE_RGB)); 473 474 float[] source = { 1.0f, 0.5f, 0.0f }; 475 float[] expected = { 0.8912f, 0.4962f, 0.1164f }; 476 477 float[] r1 = connector.transform(source[0], source[1], source[2]); 478 assertNotNull(r1); 479 assertEquals(3, r1.length); 480 assertArrayNotEquals(source, r1, 1e-5f); 481 assertArrayEquals(expected, r1, 1e-3f); 482 483 float[] r3 = { source[0], source[1], source[2] }; 484 assertSame(r3, connector.transform(r3)); 485 assertEquals(3, r3.length); 486 assertArrayEquals(r1, r3, 1e-5f); 487 488 connector = ColorSpace.connect( 489 ColorSpace.get(ColorSpace.Named.ADOBE_RGB), 490 ColorSpace.get(ColorSpace.Named.SRGB)); 491 492 float[] tmp = source; 493 source = expected; 494 expected = tmp; 495 496 r1 = connector.transform(source[0], source[1], source[2]); 497 assertNotNull(r1); 498 assertEquals(3, r1.length); 499 assertArrayNotEquals(source, r1, 1e-5f); 500 assertArrayEquals(expected, r1, 1e-3f); 501 502 r3 = new float[] { source[0], source[1], source[2] }; 503 assertSame(r3, connector.transform(r3)); 504 assertEquals(3, r3.length); 505 assertArrayEquals(r1, r3, 1e-5f); 506 } 507 508 @Test testAdaptedConnector()509 public void testAdaptedConnector() { 510 // Connect color spaces with different white points 511 ColorSpace.Connector connector = ColorSpace.connect( 512 ColorSpace.get(ColorSpace.Named.SRGB), 513 ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB)); 514 515 float[] source = new float[] { 1.0f, 0.0f, 0.0f }; 516 float[] expected = new float[] { 0.70226f, 0.2757f, 0.1036f }; 517 518 float[] r = connector.transform(source[0], source[1], source[2]); 519 assertNotNull(r); 520 assertEquals(3, r.length); 521 assertArrayNotEquals(source, r, 1e-5f); 522 assertArrayEquals(expected, r, 1e-4f); 523 } 524 525 @Test testAdaptedConnectorWithRenderIntent()526 public void testAdaptedConnectorWithRenderIntent() { 527 // Connect a wider color space to a narrow color space 528 ColorSpace.Connector connector = ColorSpace.connect( 529 ColorSpace.get(ColorSpace.Named.DCI_P3), 530 ColorSpace.get(ColorSpace.Named.SRGB), 531 ColorSpace.RenderIntent.RELATIVE); 532 533 float[] source = { 0.9f, 0.9f, 0.9f }; 534 535 float[] relative = connector.transform(source[0], source[1], source[2]); 536 assertNotNull(relative); 537 assertEquals(3, relative.length); 538 assertArrayNotEquals(source, relative, 1e-5f); 539 assertArrayEquals(new float[] { 0.8862f, 0.8862f, 0.8862f }, relative, 1e-4f); 540 541 connector = ColorSpace.connect( 542 ColorSpace.get(ColorSpace.Named.DCI_P3), 543 ColorSpace.get(ColorSpace.Named.SRGB), 544 ColorSpace.RenderIntent.ABSOLUTE); 545 546 float[] absolute = connector.transform(source[0], source[1], source[2]); 547 assertNotNull(absolute); 548 assertEquals(3, absolute.length); 549 assertArrayNotEquals(source, absolute, 1e-5f); 550 assertArrayNotEquals(relative, absolute, 1e-5f); 551 assertArrayEquals(new float[] { 0.8475f, 0.9217f, 0.8203f }, absolute, 1e-4f); 552 } 553 554 @Test testIdentityConnector()555 public void testIdentityConnector() { 556 ColorSpace.Connector connector = ColorSpace.connect( 557 ColorSpace.get(ColorSpace.Named.SRGB), 558 ColorSpace.get(ColorSpace.Named.SRGB)); 559 560 assertSame(connector.getSource(), connector.getDestination()); 561 assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent()); 562 563 float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f }; 564 565 float[] r = connector.transform(source[0], source[1], source[2]); 566 assertNotNull(r); 567 assertEquals(3, r.length); 568 assertArrayEquals(source, r, 1e-5f); 569 } 570 571 @Test testConnectorTransformIdentity()572 public void testConnectorTransformIdentity() { 573 ColorSpace.Connector connector = ColorSpace.connect( 574 ColorSpace.get(ColorSpace.Named.DCI_P3), 575 ColorSpace.get(ColorSpace.Named.DCI_P3)); 576 577 float[] source = { 1.0f, 0.0f, 0.0f }; 578 float[] expected = { 1.0f, 0.0f, 0.0f }; 579 580 float[] r1 = connector.transform(source[0], source[1], source[2]); 581 assertNotNull(r1); 582 assertEquals(3, r1.length); 583 assertArrayEquals(expected, r1, 1e-3f); 584 585 float[] r3 = { source[0], source[1], source[2] }; 586 assertSame(r3, connector.transform(r3)); 587 assertEquals(3, r3.length); 588 assertArrayEquals(r1, r3, 1e-5f); 589 } 590 591 @Test testAdaptation()592 public void testAdaptation() { 593 ColorSpace adapted = ColorSpace.adapt( 594 ColorSpace.get(ColorSpace.Named.SRGB), 595 ColorSpace.ILLUMINANT_D50); 596 597 float[] sRGBD50 = { 598 0.43602175f, 0.22247513f, 0.01392813f, 599 0.38510883f, 0.71690667f, 0.09710153f, 600 0.14308129f, 0.06061824f, 0.71415880f 601 }; 602 603 assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f); 604 605 adapted = ColorSpace.adapt( 606 ColorSpace.get(ColorSpace.Named.SRGB), 607 ColorSpace.ILLUMINANT_D50, 608 ColorSpace.Adaptation.BRADFORD); 609 assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f); 610 } 611 612 @Test testImplicitSRGBConnector()613 public void testImplicitSRGBConnector() { 614 ColorSpace.Connector connector1 = ColorSpace.connect( 615 ColorSpace.get(ColorSpace.Named.DCI_P3)); 616 617 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector1.getDestination()); 618 619 ColorSpace.Connector connector2 = ColorSpace.connect( 620 ColorSpace.get(ColorSpace.Named.DCI_P3), 621 ColorSpace.get(ColorSpace.Named.SRGB)); 622 623 float[] source = { 0.6f, 0.9f, 0.7f }; 624 assertArrayEquals( 625 connector1.transform(source[0], source[1], source[2]), 626 connector2.transform(source[0], source[1], source[2]), 1e-7f); 627 } 628 629 @Test testLab()630 public void testLab() { 631 ColorSpace.Connector connector = ColorSpace.connect( 632 ColorSpace.get(ColorSpace.Named.CIE_LAB)); 633 634 float[] source = { 100.0f, 0.0f, 0.0f }; 635 float[] expected = { 1.0f, 1.0f, 1.0f }; 636 637 float[] r1 = connector.transform(source[0], source[1], source[2]); 638 assertNotNull(r1); 639 assertEquals(3, r1.length); 640 assertArrayEquals(expected, r1, 1e-3f); 641 642 source = new float[] { 100.0f, 0.0f, 54.0f }; 643 expected = new float[] { 1.0f, 0.9925f, 0.5762f }; 644 645 float[] r2 = connector.transform(source[0], source[1], source[2]); 646 assertNotNull(r2); 647 assertEquals(3, r2.length); 648 assertArrayEquals(expected, r2, 1e-3f); 649 650 connector = ColorSpace.connect( 651 ColorSpace.get(ColorSpace.Named.CIE_LAB), ColorSpace.RenderIntent.ABSOLUTE); 652 653 source = new float[] { 100.0f, 0.0f, 0.0f }; 654 expected = new float[] { 1.0f, 0.9910f, 0.8651f }; 655 656 r1 = connector.transform(source[0], source[1], source[2]); 657 assertNotNull(r1); 658 assertEquals(3, r1.length); 659 assertArrayEquals(expected, r1, 1e-3f); 660 661 source = new float[] { 100.0f, 0.0f, 54.0f }; 662 expected = new float[] { 1.0f, 0.9853f, 0.4652f }; 663 664 r2 = connector.transform(source[0], source[1], source[2]); 665 assertNotNull(r2); 666 assertEquals(3, r2.length); 667 assertArrayEquals(expected, r2, 1e-3f); 668 } 669 670 @Test testXYZ()671 public void testXYZ() { 672 ColorSpace xyz = ColorSpace.get(ColorSpace.Named.CIE_XYZ); 673 674 float[] source = { 0.32f, 0.43f, 0.54f }; 675 676 float[] r1 = xyz.toXyz(source[0], source[1], source[2]); 677 assertNotNull(r1); 678 assertEquals(3, r1.length); 679 assertArrayEquals(source, r1, 1e-7f); 680 681 float[] r2 = xyz.fromXyz(source[0], source[1], source[2]); 682 assertNotNull(r2); 683 assertEquals(3, r2.length); 684 assertArrayEquals(source, r2, 1e-7f); 685 686 ColorSpace.Connector connector = 687 ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_XYZ)); 688 689 float[] expected = { 0.2280f, 0.7541f, 0.8453f }; 690 691 float[] r3 = connector.transform(source[0], source[1], source[2]); 692 assertNotNull(r3); 693 assertEquals(3, r3.length); 694 assertArrayEquals(expected, r3, 1e-3f); 695 } 696 697 @Test testIDs()698 public void testIDs() { 699 // These cannot change 700 assertEquals(0, ColorSpace.get(ColorSpace.Named.SRGB).getId()); 701 assertEquals(-1, ColorSpace.MIN_ID); 702 assertEquals(63, ColorSpace.MAX_ID); 703 } 704 705 @Test testFromLinear()706 public void testFromLinear() { 707 ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 708 709 float[] source = { 0.0f, 0.5f, 1.0f }; 710 float[] expected = { 0.0f, 0.7354f, 1.0f }; 711 712 float[] r1 = colorSpace.fromLinear(source[0], source[1], source[2]); 713 assertNotNull(r1); 714 assertEquals(3, r1.length); 715 assertArrayEquals(expected, r1, 1e-3f); 716 717 float[] r2 = { source[0], source[1], source[2] }; 718 assertSame(r2, colorSpace.fromLinear(r2)); 719 assertEquals(3, r2.length); 720 assertArrayEquals(r1, r2, 1e-5f); 721 } 722 723 @Test testToLinear()724 public void testToLinear() { 725 ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 726 727 float[] source = { 0.0f, 0.5f, 1.0f }; 728 float[] expected = new float[] { 0.0f, 0.2140f, 1.0f }; 729 730 float[] r1 = colorSpace.toLinear(source[0], source[1], source[2]); 731 assertNotNull(r1); 732 assertEquals(3, r1.length); 733 assertArrayEquals(expected, r1, 1e-3f); 734 735 float[] r2 = new float[] { source[0], source[1], source[2] }; 736 assertSame(r2, colorSpace.toLinear(r2)); 737 assertEquals(3, r2.length); 738 assertArrayEquals(r1, r2, 1e-5f); 739 } 740 741 @Test testTransferParameters()742 public void testTransferParameters() { 743 ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB); 744 assertNotNull(colorSpace.getTransferParameters()); 745 746 colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB); 747 assertNull(colorSpace.getTransferParameters()); 748 } 749 750 @Test testIdempotentTransferFunctions()751 public void testIdempotentTransferFunctions() { 752 Arrays.stream(ColorSpace.Named.values()) 753 .map(ColorSpace::get) 754 .filter(cs -> cs.getModel() == ColorSpace.Model.RGB) 755 .map(cs -> (ColorSpace.Rgb) cs) 756 .forEach(cs -> { 757 float[] source = { 0.0f, 0.5f, 1.0f }; 758 float[] r = cs.fromLinear(cs.toLinear(source[0], source[1], source[2])); 759 assertArrayEquals(source, r, 1e-3f); 760 }); 761 } 762 763 @Test testMatch()764 public void testMatch() { 765 for (ColorSpace.Named named : ColorSpace.Named.values()) { 766 ColorSpace cs = ColorSpace.get(named); 767 if (cs.getModel() == ColorSpace.Model.RGB) { 768 ColorSpace.Rgb rgb = (ColorSpace.Rgb) cs; 769 // match() cannot match extended sRGB 770 if (rgb != ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB) && 771 rgb != ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)) { 772 773 // match() uses CIE XYZ D50 774 rgb = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50); 775 assertSame(cs, 776 ColorSpace.match(rgb.getTransform(), rgb.getTransferParameters())); 777 } 778 } 779 } 780 781 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), 782 ColorSpace.match(SRGB_TO_XYZ_D50, new ColorSpace.Rgb.TransferParameters( 783 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4))); 784 } 785 786 787 @SuppressWarnings("SameParameterValue") assertArrayNotEquals(float[] a, float[] b, float eps)788 private static void assertArrayNotEquals(float[] a, float[] b, float eps) { 789 for (int i = 0; i < a.length; i++) { 790 if (Float.compare(a[i], b[i]) == 0 || Math.abs(a[i] - b[i]) < eps) { 791 fail("Expected " + a[i] + ", received " + b[i]); 792 } 793 } 794 } 795 assertArrayEquals(float[] a, float[] b, float eps)796 private static void assertArrayEquals(float[] a, float[] b, float eps) { 797 for (int i = 0; i < a.length; i++) { 798 if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > eps) { 799 fail("Expected " + a[i] + ", received " + b[i]); 800 } 801 } 802 } 803 } 804