Skip to content

Commit ddf17ce

Browse files
kainino0xsvgeesus
authored andcommitted
Use exact values for some matrices in conversions.js
These color space conversion matrices have exact rational values that can be computed from the numbers provided in the spec. Using exact values is more succinct for most of these matrices, and also makes it a nice reference implementation for other languages. This example code already uses exact inline formulations for a number of other things, like D50 and D65 definitions, so this is similar to that. I only did the XYZ conversion matrices for srgb, display-p3, a98-rgb, and rec2020. - I don't have code to easily compute the D65/D50 conversions or OKLab/OKLCH as I was only interested in the predefined color spaces. - The rational forms of prophoto-rgb's matrices exceed the precision of JavaScript math. I could include them as comments though. Source to compute these: https://github.com/kainino0x/exact_css_xyz_matrices using this Rust crate: https://crates.io/crates/rgb_derivation as described for sRGB on this page: https://mina86.com/2019/srgb-xyz-matrix/ but using the numbers from this spec. I used these in the WebGPU conformance test suite: gpuweb/cts#1089 WebGPU needed only srgb and display-p3, but it was easy to extend to the other predefined color spaces. (WebGPU may add some of those color spaces eventually anyway.)
1 parent 496e5c0 commit ddf17ce

File tree

1 file changed

+24
-25
lines changed

1 file changed

+24
-25
lines changed

css-color-4/conversions.js

+24-25
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ function lin_sRGB_to_XYZ(rgb) {
5252
// using sRGB's own white, D65 (no chromatic adaptation)
5353

5454
var M = [
55-
[ 0.41239079926595934, 0.357584339383878, 0.1804807884018343 ],
56-
[ 0.21263900587151027, 0.715168678767756, 0.07219231536073371 ],
57-
[ 0.01933081871559182, 0.11919477979462598, 0.9505321522496607 ]
55+
[ 506752 / 1228815, 87881 / 245763, 12673 / 70218 ],
56+
[ 87098 / 409605, 175762 / 245763, 12673 / 175545 ],
57+
[ 7918 / 409605, 87881 / 737289, 1001167 / 1053270 ],
5858
];
5959
return multiplyMatrices(M, rgb);
6060
}
@@ -63,9 +63,9 @@ function XYZ_to_lin_sRGB(XYZ) {
6363
// convert XYZ to linear-light sRGB
6464

6565
var M = [
66-
[ 3.2409699419045226, -1.537383177570094, -0.4986107602930034 ],
67-
[ -0.9692436362808796, 1.8759675015077202, 0.04155505740717559 ],
68-
[ 0.05563007969699366, -0.20397695888897652, 1.0569715142428786 ]
66+
[ 12831 / 3959, -329 / 214, -1974 / 3959 ],
67+
[ -851781 / 878810, 1648619 / 878810, 36519 / 878810 ],
68+
[ 705 / 12673, -2585 / 12673, 705 / 667 ],
6969
];
7070

7171
return multiplyMatrices(M, XYZ);
@@ -93,21 +93,20 @@ function lin_P3_to_XYZ(rgb) {
9393
// using D65 (no chromatic adaptation)
9494
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
9595
var M = [
96-
[0.4865709486482162, 0.26566769316909306, 0.1982172852343625],
97-
[0.2289745640697488, 0.6917385218365064, 0.079286914093745],
98-
[0.0000000000000000, 0.04511338185890264, 1.043944368900976]
96+
[ 608311 / 1250200, 189793 / 714400, 198249 / 1000160 ],
97+
[ 35783 / 156275, 247089 / 357200, 198249 / 2500400 ],
98+
[ 0 / 1, 32229 / 714400, 5220557 / 5000800 ],
9999
];
100-
// 0 was computed as -3.972075516933488e-17
101100

102101
return multiplyMatrices(M, rgb);
103102
}
104103

105104
function XYZ_to_lin_P3(XYZ) {
106105
// convert XYZ to linear-light P3
107106
var M = [
108-
[ 2.493496911941425, -0.9313836179191239, -0.40271078445071684],
109-
[-0.8294889695615747, 1.7626640603183463, 0.023624685841943577],
110-
[ 0.03584583024378447, -0.07617238926804182, 0.9568845240076872]
107+
[ 446124 / 178915, -333277 / 357830, -72051 / 178915 ],
108+
[ -14852 / 17905, 63121 / 35810, 423 / 17905 ],
109+
[ 11844 / 330415, -50337 / 660830, 316169 / 330415 ],
111110
];
112111

113112
return multiplyMatrices(M, XYZ);
@@ -211,9 +210,9 @@ function lin_a98rgb_to_XYZ(rgb) {
211210
// from the chromaticity coordinates of R G B W
212211
// see matrixmaker.html
213212
var M = [
214-
[ 0.5766690429101305, 0.1855582379065463, 0.1882286462349947 ],
215-
[ 0.29734497525053605, 0.6273635662554661, 0.07529145849399788 ],
216-
[ 0.02703136138641234, 0.07068885253582723, 0.9913375368376388 ]
213+
[ 573536 / 994567, 263643 / 1420810, 187206 / 994567 ],
214+
[ 591459 / 1989134, 6239551 / 9945670, 374412 / 4972835 ],
215+
[ 53769 / 1989134, 351524 / 4972835, 4929758 / 4972835 ],
217216
];
218217

219218
return multiplyMatrices(M, rgb);
@@ -222,9 +221,9 @@ function lin_a98rgb_to_XYZ(rgb) {
222221
function XYZ_to_lin_a98rgb(XYZ) {
223222
// convert XYZ to linear-light a98-rgb
224223
var M = [
225-
[ 2.0415879038107465, -0.5650069742788596, -0.34473135077832956 ],
226-
[ -0.9692436362808795, 1.8759675015077202, 0.04155505740717557 ],
227-
[ 0.013444280632031142, -0.11836239223101838, 1.0151749943912054 ]
224+
[ 1829569 / 896150, -506331 / 896150, -308931 / 896150 ],
225+
[ -851781 / 878810, 1648619 / 878810, 36519 / 878810 ],
226+
[ 16779 / 1248040, -147721 / 1248040, 1266979 / 1248040 ],
228227
];
229228

230229
return multiplyMatrices(M, XYZ);
@@ -278,9 +277,9 @@ function lin_2020_to_XYZ(rgb) {
278277
// using D65 (no chromatic adaptation)
279278
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
280279
var M = [
281-
[0.6369580483012914, 0.14461690358620832, 0.1688809751641721],
282-
[0.2627002120112671, 0.6779980715188708, 0.05930171646986196],
283-
[0.000000000000000, 0.028072693049087428, 1.060985057710791]
280+
[ 63426534 / 99577255, 20160776 / 139408157, 47086771 / 278816314 ],
281+
[ 26158966 / 99577255, 472592308 / 697040785, 8267143 / 139408157 ],
282+
[ 0 / 1, 19567812 / 697040785, 295819943 / 278816314 ],
284283
];
285284
// 0 is actually calculated as 4.994106574466076e-17
286285

@@ -290,9 +289,9 @@ function lin_2020_to_XYZ(rgb) {
290289
function XYZ_to_lin_2020(XYZ) {
291290
// convert XYZ to linear-light rec2020
292291
var M = [
293-
[1.7166511879712674, -0.35567078377639233, -0.25336628137365974],
294-
[-0.6666843518324892, 1.6164812366349395, 0.01576854581391113],
295-
[0.017639857445310783, -0.042770613257808524, 0.9421031212354738]
292+
[ 30757411 / 17917100, -6372589 / 17917100, -4539589 / 17917100 ],
293+
[ -19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200 ],
294+
[ 792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125 ],
296295
];
297296

298297
return multiplyMatrices(M, XYZ);

0 commit comments

Comments
 (0)