• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.hardware.DataSpace;
28 import android.platform.test.annotations.RequiresFlagsEnabled;
29 import android.platform.test.flag.junit.CheckFlagsRule;
30 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
31 import android.util.Log;
32 
33 import androidx.test.filters.SmallTest;
34 
35 import com.android.graphics.flags.Flags;
36 
37 import junitparams.JUnitParamsRunner;
38 import junitparams.Parameters;
39 
40 import org.junit.Rule;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 import java.util.Arrays;
45 import java.util.HashSet;
46 import java.util.function.DoubleUnaryOperator;
47 
48 @SmallTest
49 @RunWith(JUnitParamsRunner.class)
50 public class ColorSpaceTest {
51 
52     @Rule
53     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
54 
55     // Column-major RGB->XYZ transform matrix for the sRGB color space
56     private static final float[] SRGB_TO_XYZ = {
57             0.412391f, 0.212639f, 0.019331f,
58             0.357584f, 0.715169f, 0.119195f,
59             0.180481f, 0.072192f, 0.950532f
60     };
61     // Column-major XYZ->RGB transform matrix for the sRGB color space
62     private static final float[] XYZ_TO_SRGB = {
63             3.240970f, -0.969244f,  0.055630f,
64            -1.537383f,  1.875968f, -0.203977f,
65            -0.498611f,  0.041555f,  1.056971f
66     };
67 
68     // Column-major RGB->XYZ transform matrix for the sRGB color space and a D50 white point
69     private static final float[] SRGB_TO_XYZ_D50 = {
70             0.4360747f, 0.2225045f, 0.0139322f,
71             0.3850649f, 0.7168786f, 0.0971045f,
72             0.1430804f, 0.0606169f, 0.7141733f
73     };
74 
75     private static final float[] SRGB_PRIMARIES_xyY =
76             { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
77     private static final float[] SRGB_WHITE_POINT_xyY = { 0.3127f, 0.3290f };
78 
79     private static final float[] SRGB_PRIMARIES_XYZ = {
80             1.939394f, 1.000000f, 0.090909f,
81             0.500000f, 1.000000f, 0.166667f,
82             2.500000f, 1.000000f, 13.166667f
83     };
84     private static final float[] SRGB_WHITE_POINT_XYZ = { 0.950456f, 1.000f, 1.089058f };
85 
86     private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity();
87 
88     private static final HashSet<ColorSpace.Named> ALLOWED_NAMED_COLORSPACES =
89             new HashSet<>(Arrays.asList(
90                     ColorSpace.Named.SRGB,
91                     ColorSpace.Named.LINEAR_SRGB,
92                     ColorSpace.Named.EXTENDED_SRGB,
93                     ColorSpace.Named.LINEAR_EXTENDED_SRGB,
94                     ColorSpace.Named.BT709,
95                     ColorSpace.Named.BT2020,
96                     ColorSpace.Named.DCI_P3,
97                     ColorSpace.Named.DISPLAY_P3,
98                     ColorSpace.Named.NTSC_1953,
99                     ColorSpace.Named.SMPTE_C,
100                     ColorSpace.Named.ADOBE_RGB,
101                     ColorSpace.Named.PRO_PHOTO_RGB,
102                     ColorSpace.Named.ACES,
103                     ColorSpace.Named.ACESCG,
104                     ColorSpace.Named.CIE_XYZ,
105                     ColorSpace.Named.CIE_LAB,
106                     ColorSpace.Named.BT2020_HLG,
107                     ColorSpace.Named.BT2020_PQ));
108     static {
109         if (Flags.okLabColorspace()) {
110             ALLOWED_NAMED_COLORSPACES.add(ColorSpace.Named.OK_LAB);
111         }
112 
113         if (Flags.displayBt2020Colorspace()) {
114             ALLOWED_NAMED_COLORSPACES.add(ColorSpace.Named.DISPLAY_BT2020);
115         }
116     }
117 
118     @Test
testNamedColorSpaces()119     public void testNamedColorSpaces() {
120         for (ColorSpace.Named named : ALLOWED_NAMED_COLORSPACES) {
121             ColorSpace colorSpace = ColorSpace.get(named);
122             Log.v("ResolvedColorSpace", "ColorSpace: " + colorSpace);
123             assertNotNull(colorSpace.getName());
124             assertNotNull(colorSpace);
125             assertEquals(named.ordinal(), colorSpace.getId());
126             assertTrue(colorSpace.getComponentCount() >= 1);
127             assertTrue(colorSpace.getComponentCount() <= 4);
128         }
129     }
130 
131     @Test(expected = IllegalArgumentException.class)
testNullName()132     public void testNullName() {
133         new ColorSpace.Rgb(null, new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
134     }
135 
136     @Test(expected = IllegalArgumentException.class)
testEmptyName()137     public void testEmptyName() {
138         new ColorSpace.Rgb("", new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
139     }
140 
141     @Test
testName()142     public void testName() {
143         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
144                 sIdentity, sIdentity, 0.0f, 1.0f);
145         assertEquals("Test", cs.getName());
146     }
147 
148     @Test(expected = IllegalArgumentException.class)
testPrimariesLength()149     public void testPrimariesLength() {
150         new ColorSpace.Rgb("Test", new float[7], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
151     }
152 
153     @Test(expected = IllegalArgumentException.class)
testWhitePointLength()154     public void testWhitePointLength() {
155         new ColorSpace.Rgb("Test", new float[6], new float[1], sIdentity, sIdentity, 0.0f, 1.0f);
156     }
157 
158     @Test(expected = IllegalArgumentException.class)
testNullOETF()159     public void testNullOETF() {
160         new ColorSpace.Rgb("Test", new float[6], new float[2], null, sIdentity, 0.0f, 1.0f);
161     }
162 
163     @Test
testOETF()164     public void testOETF() {
165         DoubleUnaryOperator op = Math::sqrt;
166         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
167                 op, sIdentity, 0.0f, 1.0f);
168         assertEquals(0.5, cs.getOetf().applyAsDouble(0.25), 1e-5);
169     }
170 
171     @Test(expected = IllegalArgumentException.class)
testNullEOTF()172     public void testNullEOTF() {
173         new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, null, 0.0f, 1.0f);
174     }
175 
176     @Test
testEOTF()177     public void testEOTF() {
178         DoubleUnaryOperator op = x -> x * x;
179         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
180                 sIdentity, op, 0.0f, 1.0f);
181         assertEquals(0.0625, cs.getEotf().applyAsDouble(0.25), 1e-5);
182     }
183 
184     @Test(expected = IllegalArgumentException.class)
testInvalidRange()185     public void testInvalidRange() {
186         new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, sIdentity, 2.0f, 1.0f);
187     }
188 
189     @Test
testRanges()190     public void testRanges() {
191         ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
192 
193         float m1 = cs.getMinValue(0);
194         float m2 = cs.getMinValue(1);
195         float m3 = cs.getMinValue(2);
196 
197         assertEquals(0.0f, m1, 1e-9f);
198         assertEquals(0.0f, m2, 1e-9f);
199         assertEquals(0.0f, m3, 1e-9f);
200 
201         m1 = cs.getMaxValue(0);
202         m2 = cs.getMaxValue(1);
203         m3 = cs.getMaxValue(2);
204 
205         assertEquals(1.0f, m1, 1e-9f);
206         assertEquals(1.0f, m2, 1e-9f);
207         assertEquals(1.0f, m3, 1e-9f);
208 
209         cs = ColorSpace.get(ColorSpace.Named.CIE_LAB);
210 
211         m1 = cs.getMinValue(0);
212         m2 = cs.getMinValue(1);
213         m3 = cs.getMinValue(2);
214 
215         assertEquals(0.0f, m1, 1e-9f);
216         assertEquals(-128.0f, m2, 1e-9f);
217         assertEquals(-128.0f, m3, 1e-9f);
218 
219         m1 = cs.getMaxValue(0);
220         m2 = cs.getMaxValue(1);
221         m3 = cs.getMaxValue(2);
222 
223         assertEquals(100.0f, m1, 1e-9f);
224         assertEquals(128.0f, m2, 1e-9f);
225         assertEquals(128.0f, m3, 1e-9f);
226 
227         cs = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
228 
229         m1 = cs.getMinValue(0);
230         m2 = cs.getMinValue(1);
231         m3 = cs.getMinValue(2);
232 
233         assertEquals(-2.0f, m1, 1e-9f);
234         assertEquals(-2.0f, m2, 1e-9f);
235         assertEquals(-2.0f, m3, 1e-9f);
236 
237         m1 = cs.getMaxValue(0);
238         m2 = cs.getMaxValue(1);
239         m3 = cs.getMaxValue(2);
240 
241         assertEquals(2.0f, m1, 1e-9f);
242         assertEquals(2.0f, m2, 1e-9f);
243         assertEquals(2.0f, m3, 1e-9f);
244 
245         if (Flags.okLabColorspace()) {
246             cs = ColorSpace.get(ColorSpace.Named.OK_LAB);
247 
248             m1 = cs.getMinValue(0);
249             m2 = cs.getMinValue(1);
250             m3 = cs.getMinValue(2);
251 
252             assertEquals(0f, m1, 1e-9f);
253             assertEquals(-0.5f, m2, 1e-9f);
254             assertEquals(-0.5f, m3, 1e-9f);
255 
256             m1 = cs.getMaxValue(0);
257             m2 = cs.getMaxValue(1);
258             m3 = cs.getMaxValue(2);
259 
260             assertEquals(1f, m1, 1e-9f);
261             assertEquals(0.5f, m2, 1e-9f);
262             assertEquals(0.5f, m3, 1e-9f);
263         }
264     }
265 
266     @Test
testMat3x3()267     public void testMat3x3() {
268         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
269 
270         float[] rgbToXYZ = cs.getTransform();
271         for (int i = 0; i < 9; i++) {
272             assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
273         }
274     }
275 
276     @Test
testMat3x3Inverse()277     public void testMat3x3Inverse() {
278         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
279 
280         float[] xyzToRGB = cs.getInverseTransform();
281         for (int i = 0; i < 9; i++) {
282             assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
283         }
284     }
285 
286     @Test
testMat3x3Primaries()287     public void testMat3x3Primaries() {
288         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
289 
290         float[] primaries = cs.getPrimaries();
291 
292         assertNotNull(primaries);
293         assertEquals(6, primaries.length);
294 
295         assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-5f);
296         assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-5f);
297         assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-5f);
298         assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-5f);
299         assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-5f);
300         assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-5f);
301     }
302 
303     @Test
testMat3x3WhitePoint()304     public void testMat3x3WhitePoint() {
305         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
306 
307         float[] whitePoint = cs.getWhitePoint();
308 
309         assertNotNull(whitePoint);
310         assertEquals(2, whitePoint.length);
311 
312         assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-5f);
313         assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-5f);
314     }
315 
316     @Test
testXYZFromPrimaries_xyY()317     public void testXYZFromPrimaries_xyY() {
318         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_xyY, SRGB_WHITE_POINT_xyY,
319                 sIdentity, sIdentity, 0.0f, 1.0f);
320 
321         float[] rgbToXYZ = cs.getTransform();
322         for (int i = 0; i < 9; i++) {
323             assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
324         }
325 
326         float[] xyzToRGB = cs.getInverseTransform();
327         for (int i = 0; i < 9; i++) {
328             assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
329         }
330     }
331 
332     @Test
testXYZFromPrimaries_XYZ()333     public void testXYZFromPrimaries_XYZ() {
334         ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_XYZ, SRGB_WHITE_POINT_XYZ,
335                 sIdentity, sIdentity, 0.0f, 1.0f);
336 
337         float[] primaries = cs.getPrimaries();
338 
339         assertNotNull(primaries);
340         assertEquals(6, primaries.length);
341 
342         // SRGB_PRIMARIES_xyY only has 1e-3 of precision, match it
343         assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-3f);
344         assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-3f);
345         assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-3f);
346         assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-3f);
347         assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-3f);
348         assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-3f);
349 
350         float[] whitePoint = cs.getWhitePoint();
351 
352         assertNotNull(whitePoint);
353         assertEquals(2, whitePoint.length);
354 
355         // SRGB_WHITE_POINT_xyY only has 1e-3 of precision, match it
356         assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-3f);
357         assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-3f);
358 
359         float[] rgbToXYZ = cs.getTransform();
360         for (int i = 0; i < 9; i++) {
361             assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
362         }
363 
364         float[] xyzToRGB = cs.getInverseTransform();
365         for (int i = 0; i < 9; i++) {
366             assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
367         }
368     }
369 
370     @Test
testGetComponentCount()371     public void testGetComponentCount() {
372         assertEquals(3, ColorSpace.get(ColorSpace.Named.SRGB).getComponentCount());
373         assertEquals(3, ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).getComponentCount());
374         assertEquals(3, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).getComponentCount());
375         assertEquals(3, ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).getComponentCount());
376         assertEquals(3, ColorSpace.get(ColorSpace.Named.DISPLAY_P3).getComponentCount());
377         assertEquals(3, ColorSpace.get(ColorSpace.Named.CIE_LAB).getComponentCount());
378         assertEquals(3, ColorSpace.get(ColorSpace.Named.CIE_XYZ).getComponentCount());
379         if (Flags.okLabColorspace()) {
380             assertEquals(3, ColorSpace.get(ColorSpace.Named.OK_LAB).getComponentCount());
381         }
382     }
383 
384     @Test
testIsSRGB()385     public void testIsSRGB() {
386         for (ColorSpace.Named e : ColorSpace.Named.values()) {
387             ColorSpace colorSpace = ColorSpace.get(e);
388             // ColorSpace.get is guaranteed to return non-null. So if this is queried with
389             // a ColorSpace that is flagged, this falls back to return SRGB as a default.
390             // The values method of an enum will always return the full set of enum values
391             // regardless if they are flagged out or not
392             boolean isSrgbFallback = !ALLOWED_NAMED_COLORSPACES.contains(e);
393             if (e == ColorSpace.Named.SRGB || isSrgbFallback) {
394                 assertTrue(colorSpace.isSrgb());
395             } else {
396                 assertFalse("Incorrectly treating " + e + " as SRGB!",
397                             colorSpace.isSrgb());
398             }
399         }
400 
401         ColorSpace.Rgb cs = new ColorSpace.Rgb("Almost sRGB", SRGB_TO_XYZ,
402                 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f));
403         assertFalse(cs.isSrgb());
404     }
405 
406     @Test
testIsWideGamut()407     public void testIsWideGamut() {
408         assertFalse(ColorSpace.get(ColorSpace.Named.SRGB).isWideGamut());
409         assertFalse(ColorSpace.get(ColorSpace.Named.BT709).isWideGamut());
410         assertTrue(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isWideGamut());
411         assertTrue(ColorSpace.get(ColorSpace.Named.DCI_P3).isWideGamut());
412         assertTrue(ColorSpace.get(ColorSpace.Named.BT2020).isWideGamut());
413         assertTrue(ColorSpace.get(ColorSpace.Named.ACES).isWideGamut());
414         assertTrue(ColorSpace.get(ColorSpace.Named.CIE_LAB).isWideGamut());
415         assertTrue(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isWideGamut());
416         if (Flags.okLabColorspace()) {
417             assertTrue(ColorSpace.get(ColorSpace.Named.OK_LAB).isWideGamut());
418         }
419     }
420 
421     @Test
testWhitePoint()422     public void testWhitePoint() {
423         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
424 
425         float[] whitePoint = cs.getWhitePoint();
426 
427         assertNotNull(whitePoint);
428         assertEquals(2, whitePoint.length);
429 
430         // Make sure a copy is returned
431         Arrays.fill(whitePoint, Float.NaN);
432         assertArrayNotEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
433         assertSame(whitePoint, cs.getWhitePoint(whitePoint));
434         assertArrayEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
435     }
436 
437     @Test
testPrimaries()438     public void testPrimaries() {
439         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
440 
441         float[] primaries = cs.getPrimaries();
442 
443         assertNotNull(primaries);
444         assertEquals(6, primaries.length);
445 
446         // Make sure a copy is returned
447         Arrays.fill(primaries, Float.NaN);
448         assertArrayNotEquals(primaries, cs.getPrimaries(), 1e-5f);
449         assertSame(primaries, cs.getPrimaries(primaries));
450         assertArrayEquals(primaries, cs.getPrimaries(), 1e-5f);
451     }
452 
453     @Test
testRGBtoXYZMatrix()454     public void testRGBtoXYZMatrix() {
455         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
456 
457         float[] rgbToXYZ = cs.getTransform();
458 
459         assertNotNull(rgbToXYZ);
460         assertEquals(9, rgbToXYZ.length);
461 
462         // Make sure a copy is returned
463         Arrays.fill(rgbToXYZ, Float.NaN);
464         assertArrayNotEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
465         assertSame(rgbToXYZ, cs.getTransform(rgbToXYZ));
466         assertArrayEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
467     }
468 
469     @Test
testXYZtoRGBMatrix()470     public void testXYZtoRGBMatrix() {
471         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
472 
473         float[] xyzToRGB = cs.getInverseTransform();
474 
475         assertNotNull(xyzToRGB);
476         assertEquals(9, xyzToRGB.length);
477 
478         // Make sure a copy is returned
479         Arrays.fill(xyzToRGB, Float.NaN);
480         assertArrayNotEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
481         assertSame(xyzToRGB, cs.getInverseTransform(xyzToRGB));
482         assertArrayEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
483     }
484 
485     @Test
testRGBtoXYZ()486     public void testRGBtoXYZ() {
487         ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
488 
489         float[] source = { 0.75f, 0.5f, 0.25f };
490         float[] expected = { 0.3012f, 0.2679f, 0.0840f };
491 
492         float[] r1 = cs.toXyz(source[0], source[1], source[2]);
493         assertNotNull(r1);
494         assertEquals(3, r1.length);
495         assertArrayNotEquals(source, r1, 1e-5f);
496         assertArrayEquals(expected, r1, 1e-3f);
497 
498         float[] r3 = { source[0], source[1], source[2] };
499         assertSame(r3, cs.toXyz(r3));
500         assertEquals(3, r3.length);
501         assertArrayEquals(r1, r3, 1e-5f);
502     }
503 
504     @Test
testXYZtoRGB()505     public void testXYZtoRGB() {
506         ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
507 
508         float[] source = { 0.3012f, 0.2679f, 0.0840f };
509         float[] expected = { 0.75f, 0.5f, 0.25f };
510 
511         float[] r1 = cs.fromXyz(source[0], source[1], source[2]);
512         assertNotNull(r1);
513         assertEquals(3, r1.length);
514         assertArrayNotEquals(source, r1, 1e-5f);
515         assertArrayEquals(expected, r1, 1e-3f);
516 
517         float[] r3 = { source[0], source[1], source[2] };
518         assertSame(r3, cs.fromXyz(r3));
519         assertEquals(3, r3.length);
520         assertArrayEquals(r1, r3, 1e-5f);
521     }
522 
523     @Test
testConnect()524     public void testConnect() {
525         ColorSpace.Connector connector = ColorSpace.connect(
526                 ColorSpace.get(ColorSpace.Named.SRGB),
527                 ColorSpace.get(ColorSpace.Named.DCI_P3));
528 
529         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource());
530         assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination());
531         assertSame(ColorSpace.RenderIntent.PERCEPTUAL, connector.getRenderIntent());
532 
533         connector = ColorSpace.connect(
534                 ColorSpace.get(ColorSpace.Named.SRGB),
535                 ColorSpace.get(ColorSpace.Named.SRGB));
536 
537         assertSame(connector.getDestination(), connector.getSource());
538         assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent());
539 
540         connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3));
541         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination());
542 
543         connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.SRGB));
544         assertSame(connector.getSource(), connector.getDestination());
545     }
546 
547     @Test
testConnector()548     public void testConnector() {
549         // Connect color spaces with same white points
550         ColorSpace.Connector connector = ColorSpace.connect(
551                 ColorSpace.get(ColorSpace.Named.SRGB),
552                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
553 
554         float[] source = { 1.0f, 0.5f, 0.0f };
555         float[] expected = { 0.8912f, 0.4962f, 0.1164f };
556 
557         float[] r1 = connector.transform(source[0], source[1], source[2]);
558         assertNotNull(r1);
559         assertEquals(3, r1.length);
560         assertArrayNotEquals(source, r1, 1e-5f);
561         assertArrayEquals(expected, r1, 1e-3f);
562 
563         float[] r3 = { source[0], source[1], source[2] };
564         assertSame(r3, connector.transform(r3));
565         assertEquals(3, r3.length);
566         assertArrayEquals(r1, r3, 1e-5f);
567 
568         connector = ColorSpace.connect(
569                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
570                 ColorSpace.get(ColorSpace.Named.SRGB));
571 
572         float[] tmp = source;
573         source = expected;
574         expected = tmp;
575 
576         r1 = connector.transform(source[0], source[1], source[2]);
577         assertNotNull(r1);
578         assertEquals(3, r1.length);
579         assertArrayNotEquals(source, r1, 1e-5f);
580         assertArrayEquals(expected, r1, 1e-3f);
581 
582         r3 = new float[] { source[0], source[1], source[2] };
583         assertSame(r3, connector.transform(r3));
584         assertEquals(3, r3.length);
585         assertArrayEquals(r1, r3, 1e-5f);
586     }
587 
588     @Test
testAdaptedConnector()589     public void testAdaptedConnector() {
590         // Connect color spaces with different white points
591         ColorSpace.Connector connector = ColorSpace.connect(
592                 ColorSpace.get(ColorSpace.Named.SRGB),
593                 ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB));
594 
595         float[] source = new float[] { 1.0f, 0.0f, 0.0f };
596         float[] expected = new float[] { 0.70226f, 0.2757f, 0.1036f };
597 
598         float[] r = connector.transform(source[0], source[1], source[2]);
599         assertNotNull(r);
600         assertEquals(3, r.length);
601         assertArrayNotEquals(source, r, 1e-5f);
602         assertArrayEquals(expected, r, 1e-4f);
603     }
604 
605     @Test
testAdaptedConnectorWithRenderIntent()606     public void testAdaptedConnectorWithRenderIntent() {
607         // Connect a wider color space to a narrow color space
608         ColorSpace.Connector connector = ColorSpace.connect(
609                 ColorSpace.get(ColorSpace.Named.DCI_P3),
610                 ColorSpace.get(ColorSpace.Named.SRGB),
611                 ColorSpace.RenderIntent.RELATIVE);
612 
613         float[] source = { 0.9f, 0.9f, 0.9f };
614 
615         float[] relative = connector.transform(source[0], source[1], source[2]);
616         assertNotNull(relative);
617         assertEquals(3, relative.length);
618         assertArrayNotEquals(source, relative, 1e-5f);
619         assertArrayEquals(new float[] { 0.8862f, 0.8862f, 0.8862f }, relative, 1e-4f);
620 
621         connector = ColorSpace.connect(
622                 ColorSpace.get(ColorSpace.Named.DCI_P3),
623                 ColorSpace.get(ColorSpace.Named.SRGB),
624                 ColorSpace.RenderIntent.ABSOLUTE);
625 
626         float[] absolute = connector.transform(source[0], source[1], source[2]);
627         assertNotNull(absolute);
628         assertEquals(3, absolute.length);
629         assertArrayNotEquals(source, absolute, 1e-5f);
630         assertArrayNotEquals(relative, absolute, 1e-5f);
631         assertArrayEquals(new float[] { 0.8475f, 0.9217f, 0.8203f }, absolute, 1e-4f);
632     }
633 
634     @Test
testIdentityConnector()635     public void testIdentityConnector() {
636         ColorSpace.Connector connector = ColorSpace.connect(
637                 ColorSpace.get(ColorSpace.Named.SRGB),
638                 ColorSpace.get(ColorSpace.Named.SRGB));
639 
640         assertSame(connector.getSource(), connector.getDestination());
641         assertSame(ColorSpace.RenderIntent.RELATIVE, connector.getRenderIntent());
642 
643         float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f };
644 
645         float[] r = connector.transform(source[0], source[1], source[2]);
646         assertNotNull(r);
647         assertEquals(3, r.length);
648         assertArrayEquals(source, r, 1e-5f);
649     }
650 
651     @Test
testConnectorTransformIdentity()652     public void testConnectorTransformIdentity() {
653         ColorSpace.Connector connector = ColorSpace.connect(
654                 ColorSpace.get(ColorSpace.Named.DCI_P3),
655                 ColorSpace.get(ColorSpace.Named.DCI_P3));
656 
657         float[] source = { 1.0f, 0.0f, 0.0f };
658         float[] expected = { 1.0f, 0.0f, 0.0f };
659 
660         float[] r1 = connector.transform(source[0], source[1], source[2]);
661         assertNotNull(r1);
662         assertEquals(3, r1.length);
663         assertArrayEquals(expected, r1, 1e-3f);
664 
665         float[] r3 = { source[0], source[1], source[2] };
666         assertSame(r3, connector.transform(r3));
667         assertEquals(3, r3.length);
668         assertArrayEquals(r1, r3, 1e-5f);
669     }
670 
671     @Test
testAdaptation()672     public void testAdaptation() {
673         ColorSpace adapted = ColorSpace.adapt(
674                 ColorSpace.get(ColorSpace.Named.SRGB),
675                 ColorSpace.ILLUMINANT_D50);
676 
677         float[] sRGBD50 = {
678                 0.43602175f, 0.22247513f, 0.01392813f,
679                 0.38510883f, 0.71690667f, 0.09710153f,
680                 0.14308129f, 0.06061824f, 0.71415880f
681         };
682 
683         assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f);
684 
685         adapted = ColorSpace.adapt(
686                 ColorSpace.get(ColorSpace.Named.SRGB),
687                 ColorSpace.ILLUMINANT_D50,
688                 ColorSpace.Adaptation.BRADFORD);
689         assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f);
690     }
691 
692     @Test
testImplicitSRGBConnector()693     public void testImplicitSRGBConnector() {
694         ColorSpace.Connector connector1 = ColorSpace.connect(
695                 ColorSpace.get(ColorSpace.Named.DCI_P3));
696 
697         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector1.getDestination());
698 
699         ColorSpace.Connector connector2 = ColorSpace.connect(
700                 ColorSpace.get(ColorSpace.Named.DCI_P3),
701                 ColorSpace.get(ColorSpace.Named.SRGB));
702 
703         float[] source = { 0.6f, 0.9f, 0.7f };
704         assertArrayEquals(
705                 connector1.transform(source[0], source[1], source[2]),
706                 connector2.transform(source[0], source[1], source[2]), 1e-7f);
707     }
708 
709     @Test
testLab()710     public void testLab() {
711         ColorSpace.Connector connector = ColorSpace.connect(
712                 ColorSpace.get(ColorSpace.Named.CIE_LAB));
713 
714         float[] source = { 100.0f, 0.0f, 0.0f };
715         float[] expected = { 1.0f, 1.0f, 1.0f };
716 
717         float[] r1 = connector.transform(source[0], source[1], source[2]);
718         assertNotNull(r1);
719         assertEquals(3, r1.length);
720         assertArrayEquals(expected, r1, 1e-3f);
721 
722         source = new float[] { 100.0f, 0.0f, 54.0f };
723         expected = new float[] { 1.0f, 0.9925f, 0.5762f };
724 
725         float[] r2 = connector.transform(source[0], source[1], source[2]);
726         assertNotNull(r2);
727         assertEquals(3, r2.length);
728         assertArrayEquals(expected, r2, 1e-3f);
729 
730         connector = ColorSpace.connect(
731                 ColorSpace.get(ColorSpace.Named.CIE_LAB), ColorSpace.RenderIntent.ABSOLUTE);
732 
733         source = new float[] { 100.0f, 0.0f, 0.0f };
734         expected = new float[] { 1.0f, 0.9910f, 0.8651f };
735 
736         r1 = connector.transform(source[0], source[1], source[2]);
737         assertNotNull(r1);
738         assertEquals(3, r1.length);
739         assertArrayEquals(expected, r1, 1e-3f);
740 
741         source = new float[] { 100.0f, 0.0f, 54.0f };
742         expected = new float[] { 1.0f, 0.9853f, 0.4652f };
743 
744         r2 = connector.transform(source[0], source[1], source[2]);
745         assertNotNull(r2);
746         assertEquals(3, r2.length);
747         assertArrayEquals(expected, r2, 1e-3f);
748     }
749 
750     @RequiresFlagsEnabled(Flags.FLAG_OK_LAB_COLORSPACE)
751     @Test
testOkLab()752     public void testOkLab() {
753         ColorSpace.Connector connector = ColorSpace.connect(
754                 ColorSpace.get(ColorSpace.Named.OK_LAB));
755 
756         float[] source = { 100.0f, 0.0f, 0.0f };
757         float[] expected = { 1.0f, 1.0f, 1.0f };
758 
759         float[] r1 = connector.transform(source[0], source[1], source[2]);
760         assertNotNull(r1);
761         assertEquals(3, r1.length);
762         assertArrayEquals(expected, r1, 1e-3f);
763 
764         source = new float[] { 100.0f, 0.0f, 54.0f };
765         expected = new float[] { 1.0f, 0.8137f, 0f };
766 
767         float[] r2 = connector.transform(source[0], source[1], source[2]);
768         assertNotNull(r2);
769         assertEquals(3, r2.length);
770         assertArrayEquals(expected, r2, 1e-3f);
771 
772         connector = ColorSpace.connect(
773                 ColorSpace.get(ColorSpace.Named.OK_LAB), ColorSpace.RenderIntent.ABSOLUTE);
774 
775         source = new float[] { 100.0f, 0.0f, 0.0f };
776         expected = new float[] { 1.0f, 0.9910f, 0.8651f };
777 
778         r1 = connector.transform(source[0], source[1], source[2]);
779         assertNotNull(r1);
780         assertEquals(3, r1.length);
781         assertArrayEquals(expected, r1, 1e-3f);
782 
783         source = new float[] { 100.0f, 0.0f, 54.0f };
784         expected = new float[] { 1.0f, 0.80465f, 0.0f };
785 
786         r2 = connector.transform(source[0], source[1], source[2]);
787         assertNotNull(r2);
788         assertEquals(3, r2.length);
789         assertArrayEquals(expected, r2, 1e-3f);
790     }
791 
792     @Test
testXYZ()793     public void testXYZ() {
794         ColorSpace xyz = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
795 
796         float[] source = { 0.32f, 0.43f, 0.54f };
797 
798         float[] r1 = xyz.toXyz(source[0], source[1], source[2]);
799         assertNotNull(r1);
800         assertEquals(3, r1.length);
801         assertArrayEquals(source, r1, 1e-7f);
802 
803         float[] r2 = xyz.fromXyz(source[0], source[1], source[2]);
804         assertNotNull(r2);
805         assertEquals(3, r2.length);
806         assertArrayEquals(source, r2, 1e-7f);
807 
808         ColorSpace.Connector connector =
809                 ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_XYZ));
810 
811         float[] expected = { 0.2280f, 0.7541f, 0.8453f };
812 
813         float[] r3 = connector.transform(source[0], source[1], source[2]);
814         assertNotNull(r3);
815         assertEquals(3, r3.length);
816         assertArrayEquals(expected, r3, 1e-3f);
817     }
818 
819     @Test
testIDs()820     public void testIDs() {
821         // These cannot change
822         assertEquals(0, ColorSpace.get(ColorSpace.Named.SRGB).getId());
823         assertEquals(-1, ColorSpace.MIN_ID);
824         assertEquals(63, ColorSpace.MAX_ID);
825     }
826 
827     @Test
testFromLinear()828     public void testFromLinear() {
829         ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
830 
831         float[] source = { 0.0f, 0.5f, 1.0f };
832         float[] expected = { 0.0f, 0.7354f, 1.0f };
833 
834         float[] r1 = colorSpace.fromLinear(source[0], source[1], source[2]);
835         assertNotNull(r1);
836         assertEquals(3, r1.length);
837         assertArrayEquals(expected, r1, 1e-3f);
838 
839         float[] r2 = { source[0], source[1], source[2] };
840         assertSame(r2, colorSpace.fromLinear(r2));
841         assertEquals(3, r2.length);
842         assertArrayEquals(r1, r2, 1e-5f);
843     }
844 
845     @Test
testToLinear()846     public void testToLinear() {
847         ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
848 
849         float[] source = { 0.0f, 0.5f, 1.0f };
850         float[] expected = new float[] { 0.0f, 0.2140f, 1.0f };
851 
852         float[] r1 = colorSpace.toLinear(source[0], source[1], source[2]);
853         assertNotNull(r1);
854         assertEquals(3, r1.length);
855         assertArrayEquals(expected, r1, 1e-3f);
856 
857         float[] r2 = new float[] { source[0], source[1], source[2] };
858         assertSame(r2, colorSpace.toLinear(r2));
859         assertEquals(3, r2.length);
860         assertArrayEquals(r1, r2, 1e-5f);
861     }
862 
863     @Test
testTransferParameters()864     public void testTransferParameters() {
865         ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
866         assertNotNull(colorSpace.getTransferParameters());
867 
868         colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
869         assertNotNull(colorSpace.getTransferParameters());
870 
871         colorSpace = new ColorSpace.Rgb("Almost sRGB", SRGB_TO_XYZ,
872                 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f));
873         assertNull(colorSpace.getTransferParameters());
874     }
875 
876     @Test
testIdempotentTransferFunctions()877     public void testIdempotentTransferFunctions() {
878         Arrays.stream(ColorSpace.Named.values())
879                 .map(ColorSpace::get)
880                 .filter(cs -> cs.getModel() == ColorSpace.Model.RGB)
881                 .map(cs -> (ColorSpace.Rgb) cs)
882                 .forEach(cs -> {
883                         float[] source = { 0.0f, 0.5f, 1.0f };
884                         float[] r = cs.fromLinear(cs.toLinear(source[0], source[1], source[2]));
885                         assertArrayEquals(source, r, 1e-3f);
886                 });
887     }
888 
889     @Test
testMatch()890     public void testMatch() {
891         for (ColorSpace.Named named : ColorSpace.Named.values()) {
892             ColorSpace cs = ColorSpace.get(named);
893             if (cs.getModel() == ColorSpace.Model.RGB) {
894                 ColorSpace.Rgb rgb = (ColorSpace.Rgb) cs;
895                 // match() cannot match extended sRGB, BT2020_HLG, BT2020_PQ
896                 if (rgb != ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
897                         && rgb != ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)
898                         && rgb != ColorSpace.get(ColorSpace.Named.BT2020_HLG)
899                         && rgb != ColorSpace.get(ColorSpace.Named.BT2020_PQ)) {
900 
901                     // match() uses CIE XYZ D50
902                     rgb = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
903                     assertSame(cs,
904                             ColorSpace.match(rgb.getTransform(), rgb.getTransferParameters()));
905                 }
906             }
907         }
908 
909         assertSame(ColorSpace.get(ColorSpace.Named.SRGB),
910                 ColorSpace.match(SRGB_TO_XYZ_D50, new ColorSpace.Rgb.TransferParameters(
911                         1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4)));
912     }
913 
914     @Test(expected = IllegalArgumentException.class)
915     @Parameters({"0", "-1", "-50"})
testInvalidCct(int cct)916     public void testInvalidCct(int cct) {
917         ColorSpace.cctToXyz(cct);
918     }
919 
920     @Test
testCctToXyz()921     public void testCctToXyz() {
922         // Verify that range listed as meaningful by the API return float arrays as expected.
923         for (int i = 1667; i <= 25000; i++) {
924             float[] result = ColorSpace.cctToXyz(i);
925             assertNotNull(result);
926             assertEquals(3, result.length);
927         }
928     }
929 
cctToXyzExpected()930     private static Object[] cctToXyzExpected() {
931         return new Object[] {
932                 // ILLUMINANT_A
933                 new Object[] { 2856, new float[] { 1.0970824f, 1.0f, 0.3568525f }},
934                 // ILLUMINANT_B
935                 new Object[] { 4874, new float[] { 0.98355806f, 1.0f, 0.8376475f }},
936                 // ILLUMINANT_C
937                 new Object[] { 6774, new float[] { 0.9680535f, 1.0f, 1.1603559f }},
938                 // ILLUMINANT_D50
939                 new Object[] { 5003, new float[] { 0.9811904f, 1.0f, 0.86360276f }},
940                 // ILLUMINANT_D55
941                 new Object[] { 5503, new float[] { 0.97444946f, 1.0f, 0.9582717f }},
942                 // ILLUMINANT_D60
943                 new Object[] { 6004, new float[] { 0.9705604f, 1.0f, 1.0441511f }},
944                 // ILLUMINANT_D65
945                 new Object[] { 6504, new float[] { 0.968573f, 1.0f, 1.1216444f }},
946                 // ILLUMINANT_D75
947                 new Object[] { 7504, new float[] { 0.9679457f, 1.0f, 1.2551404f }},
948                 // ILLUMINANT_E
949                 new Object[] { 5454, new float[] { 0.9749648f, 1.0f, 0.9494016f }},
950                 // Test a sample of values in the meaningful range according to the API.
951                 new Object[] { 1667, new float[] { 1.4014802f, 1.0f, 0.08060435f }},
952                 new Object[] { 1668, new float[] { 1.4010513f, 1.0f, 0.08076303f }},
953                 new Object[] { 1700, new float[] { 1.3874257f, 1.0f, 0.08596305f }},
954                 new Object[] { 1701, new float[] { 1.3870035f, 1.0f, 0.08612958f }},
955                 new Object[] { 2020, new float[] { 1.2686056f, 1.0f, 0.14921218f }},
956                 new Object[] { 2102, new float[] { 1.2439337f, 1.0f, 0.1678791f }},
957                 new Object[] { 2360, new float[] { 1.1796018f, 1.0f, 0.2302558f }},
958                 new Object[] { 4688, new float[] { 0.9875373f, 1.0f, 0.79908675f }},
959                 new Object[] { 5797, new float[] { 0.97189087f, 1.0f, 1.0097121f }},
960                 new Object[] { 7625, new float[] { 0.96806175f, 1.0f, 1.2695707f }},
961                 new Object[] { 8222, new float[] { 0.9690009f, 1.0f, 1.3359972f }},
962                 new Object[] { 8330, new float[] { 0.9692224f, 1.0f, 1.3472213f }},
963                 new Object[] { 9374, new float[] { 0.9718307f, 1.0f, 1.4447508f }},
964                 new Object[] { 9604, new float[] { 0.97247595f, 1.0f, 1.4638413f }},
965                 new Object[] { 9894, new float[] { 0.9733059f, 1.0f, 1.4868189f }},
966                 new Object[] { 10764, new float[] { 0.97584003f, 1.0f, 1.5491791f }},
967                 new Object[] { 11735, new float[] { 0.97862047f, 1.0f, 1.6088297f }},
968                 new Object[] { 12819, new float[] { 0.98155034f, 1.0f, 1.6653923f }},
969                 new Object[] { 13607, new float[] { 0.98353446f, 1.0f, 1.7010691f }},
970                 new Object[] { 15185, new float[] { 0.98712224f, 1.0f, 1.7615601f }},
971                 new Object[] { 17474, new float[] { 0.9914801f, 1.0f, 1.8297766f }},
972                 new Object[] { 18788, new float[] { 0.9935937f, 1.0f, 1.8612393f }},
973                 new Object[] { 19119, new float[] { 0.99408686f, 1.0f, 1.8684553f }},
974                 new Object[] { 19174, new float[] { 0.99416786f, 1.0f, 1.8696303f }},
975                 new Object[] { 19437, new float[] { 0.9945476f, 1.0f, 1.8751476f }},
976                 new Object[] { 19533, new float[] { 0.99468416f, 1.0f, 1.8771234f }},
977                 new Object[] { 19548, new float[] { 0.99470526f, 1.0f, 1.8774294f }},
978                 new Object[] { 19762, new float[] { 0.995005f, 1.0f, 1.8817542f }},
979                 new Object[] { 19774, new float[] { 0.9950216f, 1.0f, 1.8819935f }},
980                 new Object[] { 20291, new float[] { 0.99572146f, 1.0f, 1.8920314f }},
981                 new Object[] { 23018, new float[] { 0.99893945f, 1.0f, 1.9371331f }},
982                 new Object[] { 23509, new float[] { 0.999445f, 1.0f, 1.9440757f }},
983                 new Object[] { 24761, new float[] { 1.0006485f, 1.0f, 1.9604537f }},
984 
985         };
986     }
987 
988     @Test
989     @Parameters(method = "cctToXyzExpected")
testCctToXyzValues(int cct, float[] xyz)990     public void testCctToXyzValues(int cct, float[] xyz) {
991         float[] result = ColorSpace.cctToXyz(cct);
992         assertArrayEquals(xyz, result, 1e-3f);
993     }
994 
chromaticAdaptationNullParameters()995     private static Object[] chromaticAdaptationNullParameters() {
996         return new Object[] {
997                 new Object[] { null, ColorSpace.ILLUMINANT_D50, ColorSpace.ILLUMINANT_D60 },
998                 new Object[] { ColorSpace.Adaptation.BRADFORD, null, ColorSpace.ILLUMINANT_D60 },
999                 new Object[] { ColorSpace.Adaptation.BRADFORD, ColorSpace.ILLUMINANT_D60, null },
1000         };
1001     }
1002 
1003     @Test(expected = NullPointerException.class)
1004     @Parameters(method = "chromaticAdaptationNullParameters")
testChromaticAdaptationNullParameters(ColorSpace.Adaptation adaptation, float[] srcWhitePoint, float[] dstWhitePoint)1005     public void testChromaticAdaptationNullParameters(ColorSpace.Adaptation adaptation,
1006             float[] srcWhitePoint, float[] dstWhitePoint) {
1007         ColorSpace.chromaticAdaptation(adaptation, srcWhitePoint, dstWhitePoint);
1008     }
1009 
chromaticAdaptationWrongSizedArrays()1010     private static Object[] chromaticAdaptationWrongSizedArrays() {
1011         return new Object[] {
1012                 new Object[] { ColorSpace.Adaptation.BRADFORD, new float[] { 1.0f },
1013                         ColorSpace.ILLUMINANT_D60 },
1014                 new Object[] { ColorSpace.Adaptation.BRADFORD, ColorSpace.ILLUMINANT_D60,
1015                         new float[] { 1.0f, 1.0f, 1.0f, 1.0f }},
1016         };
1017     }
1018 
1019     @Test(expected = IllegalArgumentException.class)
1020     @Parameters(method = "chromaticAdaptationWrongSizedArrays")
testChromaticAdaptationWrongSizedArrays(ColorSpace.Adaptation adaptation, float[] srcWhitePoint, float[] dstWhitePoint)1021     public void testChromaticAdaptationWrongSizedArrays(ColorSpace.Adaptation adaptation,
1022             float[] srcWhitePoint, float[] dstWhitePoint) {
1023         ColorSpace.chromaticAdaptation(adaptation, srcWhitePoint, dstWhitePoint);
1024     }
1025 
1026     private static float[] sIdentityMatrix = new float[] {
1027             1.0f, 0.0f, 0.0f,
1028             0.0f, 1.0f, 0.0f,
1029             0.0f, 0.0f, 1.0f
1030     };
1031 
1032     @Test
testChromaticAdaptation()1033     public void testChromaticAdaptation() {
1034         for (ColorSpace.Adaptation adaptation : ColorSpace.Adaptation.values()) {
1035             float[][] whitePoints = {
1036                     ColorSpace.ILLUMINANT_A,
1037                     ColorSpace.ILLUMINANT_B,
1038                     ColorSpace.ILLUMINANT_C,
1039                     ColorSpace.ILLUMINANT_D50,
1040                     ColorSpace.ILLUMINANT_D55,
1041                     ColorSpace.ILLUMINANT_D60,
1042                     ColorSpace.ILLUMINANT_D65,
1043                     ColorSpace.ILLUMINANT_D75,
1044                     ColorSpace.ILLUMINANT_E,
1045             };
1046             for (float[] srcWhitePoint : whitePoints) {
1047                 for (float[] dstWhitePoint : whitePoints) {
1048                     float[] result = ColorSpace.chromaticAdaptation(adaptation, srcWhitePoint,
1049                             dstWhitePoint);
1050                     assertNotNull(result);
1051                     assertEquals(9, result.length);
1052                     if (Arrays.equals(srcWhitePoint, dstWhitePoint)) {
1053                         assertArrayEquals(sIdentityMatrix, result, 0f);
1054                     }
1055                 }
1056             }
1057         }
1058     }
1059 
1060     @Test
getDataSpaceFromColorSpace()1061     public void getDataSpaceFromColorSpace() {
1062         ColorSpace cs = ColorSpace.get(ColorSpace.Named.BT709);
1063         assertNotNull(cs);
1064         assertEquals(DataSpace.DATASPACE_BT709, cs.getDataSpace());
1065 
1066         cs = ColorSpace.get(ColorSpace.Named.ACES);
1067         assertEquals(DataSpace.DATASPACE_UNKNOWN, cs.getDataSpace());
1068     }
1069 
1070     @Test
getColorSpaceFromDataSpace()1071     public void getColorSpaceFromDataSpace() {
1072         ColorSpace cs = ColorSpace.getFromDataSpace(DataSpace.DATASPACE_SRGB);
1073         assertNotNull(cs);
1074         assertEquals(DataSpace.DATASPACE_SRGB, cs.getDataSpace());
1075 
1076         assertNull(ColorSpace.getFromDataSpace(DataSpace.DATASPACE_JFIF));
1077     }
1078 
1079     @SuppressWarnings("SameParameterValue")
assertArrayNotEquals(float[] a, float[] b, float eps)1080     private void assertArrayNotEquals(float[] a, float[] b, float eps) {
1081         for (int i = 0; i < a.length; i++) {
1082             if (Float.compare(a[i], b[i]) == 0 || Math.abs(a[i] - b[i]) < eps) {
1083                 fail("Expected " + a[i] + ", received " + b[i]);
1084             }
1085         }
1086     }
1087 
assertArrayEquals(float[] a, float[] b, float eps)1088     private void assertArrayEquals(float[] a, float[] b, float eps) {
1089         for (int i = 0; i < a.length; i++) {
1090             if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > eps) {
1091                 fail("Expected " + a[i] + ", received " + b[i]);
1092             }
1093         }
1094     }
1095 }
1096