/src/openexr/src/lib/OpenEXR/ImfChromaticities.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // SPDX-License-Identifier: BSD-3-Clause |
3 | | // Copyright (c) Contributors to the OpenEXR Project. |
4 | | // |
5 | | |
6 | | //----------------------------------------------------------------------------- |
7 | | // |
8 | | // CIE (x,y) chromaticities, and conversions between |
9 | | // RGB triples and CIE XYZ tristimulus values. |
10 | | // |
11 | | //----------------------------------------------------------------------------- |
12 | | |
13 | | #include "ImfNamespace.h" |
14 | | #include <ImfChromaticities.h> |
15 | | #include <string.h> |
16 | | |
17 | | #include <float.h> |
18 | | #include <stdexcept> |
19 | | |
20 | | #if defined(_MSC_VER) |
21 | | // suppress warning about non-exported base classes |
22 | | # pragma warning(disable : 4251) |
23 | | #endif |
24 | | |
25 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
26 | | |
27 | | Chromaticities::Chromaticities ( |
28 | | const IMATH_NAMESPACE::V2f& red, |
29 | | const IMATH_NAMESPACE::V2f& green, |
30 | | const IMATH_NAMESPACE::V2f& blue, |
31 | | const IMATH_NAMESPACE::V2f& white) |
32 | 18.1k | : red (red), green (green), blue (blue), white (white) |
33 | 18.1k | { |
34 | | // empty |
35 | 18.1k | } |
36 | | |
37 | | bool |
38 | | Chromaticities::operator== (const Chromaticities& c) const |
39 | 0 | { |
40 | 0 | return red == c.red && green == c.green && blue == c.blue && |
41 | 0 | white == c.white; |
42 | 0 | } |
43 | | |
44 | | bool |
45 | | Chromaticities::operator!= (const Chromaticities& c) const |
46 | 0 | { |
47 | 0 | return red != c.red || green != c.green || blue != c.blue || |
48 | 0 | white != c.white; |
49 | 0 | } |
50 | | |
51 | | IMATH_NAMESPACE::M44f |
52 | | RGBtoXYZ (const Chromaticities& chroma, float Y) |
53 | 864 | { |
54 | | // |
55 | | // For an explanation of how the color conversion matrix is derived, |
56 | | // see Roy Hall, "Illumination and Color in Computer Generated Imagery", |
57 | | // Springer-Verlag, 1989, chapter 3, "Perceptual Response"; and |
58 | | // Charles A. Poynton, "A Technical Introduction to Digital Video", |
59 | | // John Wiley & Sons, 1996, chapter 7, "Color science for video". |
60 | | // |
61 | | |
62 | | // |
63 | | // X and Z values of RGB value (1, 1, 1), or "white" |
64 | | // |
65 | | |
66 | | // prevent a division that rounds to zero |
67 | 864 | if (std::abs (chroma.white.y) <= 1.f && |
68 | 864 | std::abs (chroma.white.x * Y) >= std::abs (chroma.white.y) * FLT_MAX) |
69 | 0 | { |
70 | 0 | throw std::invalid_argument ( |
71 | 0 | "Bad chromaticities: white.y cannot be zero"); |
72 | 0 | } |
73 | | |
74 | 864 | float X = chroma.white.x * Y / chroma.white.y; |
75 | 864 | float Z = (1 - chroma.white.x - chroma.white.y) * Y / chroma.white.y; |
76 | | |
77 | | // |
78 | | // Scale factors for matrix rows, compute numerators and common denominator |
79 | | // |
80 | | |
81 | 864 | float d = chroma.red.x * (chroma.blue.y - chroma.green.y) + |
82 | 864 | chroma.blue.x * (chroma.green.y - chroma.red.y) + |
83 | 864 | chroma.green.x * (chroma.red.y - chroma.blue.y); |
84 | | |
85 | 864 | float SrN = |
86 | 864 | (X * (chroma.blue.y - chroma.green.y) - |
87 | 864 | chroma.green.x * (Y * (chroma.blue.y - 1) + chroma.blue.y * (X + Z)) + |
88 | 864 | chroma.blue.x * (Y * (chroma.green.y - 1) + chroma.green.y * (X + Z))); |
89 | | |
90 | 864 | float SgN = |
91 | 864 | (X * (chroma.red.y - chroma.blue.y) + |
92 | 864 | chroma.red.x * (Y * (chroma.blue.y - 1) + chroma.blue.y * (X + Z)) - |
93 | 864 | chroma.blue.x * (Y * (chroma.red.y - 1) + chroma.red.y * (X + Z))); |
94 | | |
95 | 864 | float SbN = |
96 | 864 | (X * (chroma.green.y - chroma.red.y) - |
97 | 864 | chroma.red.x * (Y * (chroma.green.y - 1) + chroma.green.y * (X + Z)) + |
98 | 864 | chroma.green.x * (Y * (chroma.red.y - 1) + chroma.red.y * (X + Z))); |
99 | | |
100 | 864 | if (std::abs (d) < 1.f && (std::abs (SrN) >= std::abs (d) * FLT_MAX || |
101 | 842 | std::abs (SgN) >= std::abs (d) * FLT_MAX || |
102 | 842 | std::abs (SbN) >= std::abs (d) * FLT_MAX)) |
103 | 2 | { |
104 | | // cannot generate matrix if all RGB primaries have the same y value |
105 | | // or if they all have the an x value of zero |
106 | | // in both cases, the primaries are colinear, which makes them unusable |
107 | 2 | throw std::invalid_argument ( |
108 | 2 | "Bad chromaticities: RGBtoXYZ matrix is degenerate"); |
109 | 2 | } |
110 | | |
111 | 862 | float Sr = SrN / d; |
112 | 862 | float Sg = SgN / d; |
113 | 862 | float Sb = SbN / d; |
114 | | |
115 | | // |
116 | | // Assemble the matrix |
117 | | // |
118 | | |
119 | 862 | IMATH_NAMESPACE::M44f M; |
120 | | |
121 | 862 | M[0][0] = Sr * chroma.red.x; |
122 | 862 | M[0][1] = Sr * chroma.red.y; |
123 | 862 | M[0][2] = Sr * (1 - chroma.red.x - chroma.red.y); |
124 | | |
125 | 862 | M[1][0] = Sg * chroma.green.x; |
126 | 862 | M[1][1] = Sg * chroma.green.y; |
127 | 862 | M[1][2] = Sg * (1 - chroma.green.x - chroma.green.y); |
128 | | |
129 | 862 | M[2][0] = Sb * chroma.blue.x; |
130 | 862 | M[2][1] = Sb * chroma.blue.y; |
131 | 862 | M[2][2] = Sb * (1 - chroma.blue.x - chroma.blue.y); |
132 | | |
133 | 862 | return M; |
134 | 864 | } |
135 | | |
136 | | IMATH_NAMESPACE::M44f |
137 | | XYZtoRGB (const Chromaticities& chroma, float Y) |
138 | 0 | { |
139 | 0 | return RGBtoXYZ (chroma, Y).inverse (); |
140 | 0 | } |
141 | | |
142 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |