diff --git a/.github/bin/license/check-license.mjs b/.github/bin/license/check-license.mjs index fffcf8076..eb3d45cdd 100644 --- a/.github/bin/license/check-license.mjs +++ b/.github/bin/license/check-license.mjs @@ -57,7 +57,7 @@ const allFiles = (await getFiles('./')).filter((file) => { for (const line of lines) { if (line.includes('@license')) { - if (line === ' * @license W3C') { + if (line.startsWith(' * @license W3C')) { // W3C license is ok continue; } diff --git a/package-lock.json b/package-lock.json index 6126a5680..a7cfc614b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1823,6 +1823,10 @@ "resolved": "packages/cascade-layer-name-parser", "link": true }, + "node_modules/@csstools/color-helpers": { + "resolved": "packages/color-helpers", + "link": true + }, "node_modules/@csstools/css-has-pseudo-experimental": { "resolved": "experimental/css-has-pseudo", "link": true @@ -7031,6 +7035,18 @@ "@csstools/css-tokenizer": "^2.0.0" } }, + "packages/color-helpers": { + "name": "@csstools/color-helpers", + "version": "0.0.0", + "license": "CC0-1.0", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, "packages/css-parser-algorithms": { "name": "@csstools/css-parser-algorithms", "version": "2.0.1", diff --git a/packages/color-helpers/.gitignore b/packages/color-helpers/.gitignore new file mode 100644 index 000000000..1069fe212 --- /dev/null +++ b/packages/color-helpers/.gitignore @@ -0,0 +1,5 @@ +node_modules +package-lock.json +yarn.lock +*.result.css +*.result.css.map diff --git a/packages/color-helpers/.nvmrc b/packages/color-helpers/.nvmrc new file mode 100644 index 000000000..f0b10f153 --- /dev/null +++ b/packages/color-helpers/.nvmrc @@ -0,0 +1 @@ +v16.13.1 diff --git a/packages/color-helpers/CHANGELOG.md b/packages/color-helpers/CHANGELOG.md new file mode 100644 index 000000000..4d98f656e --- /dev/null +++ b/packages/color-helpers/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changes to Color Helpers + +### Unreleased (major) + +- Initial version diff --git a/packages/color-helpers/LICENSE.md b/packages/color-helpers/LICENSE.md new file mode 100644 index 000000000..0bc1fa706 --- /dev/null +++ b/packages/color-helpers/LICENSE.md @@ -0,0 +1,108 @@ +# CC0 1.0 Universal + +## Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an “owner”) of an original work of +authorship and/or a database (each, a “Work”). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +(“Commons”) that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further +production of creative, cultural and scientific works, or to gain reputation or +greater distribution for their Work in part through the use and efforts of +others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a +Work (the “Affirmer”), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights (“Copyright and + Related Rights”). Copyright and Related Rights include, but are not limited + to, the following: + 1. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + 2. moral rights retained by the original author(s) and/or performer(s); + 3. publicity and privacy rights pertaining to a person’s image or likeness + depicted in a Work; + 4. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(i), below; + 5. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + 6. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + 7. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “Waiver”). Affirmer + makes the Waiver for the benefit of each member of the public at large and + to the detriment of Affirmer’s heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer’s express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer’s express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person a + royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer’s Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “License”). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any + of his or her remaining Copyright and Related Rights in the Work or (ii) + assert any associated claims and causes of action with respect to the Work, + in either case contrary to Affirmer’s express Statement of Purpose. + +4. Limitations and Disclaimers. + 1. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + 2. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or + otherwise, including without limitation warranties of title, + merchantability, fitness for a particular purpose, non infringement, or + the absence of latent or other defects, accuracy, or the present or + absence of errors, whether or not discoverable, all to the greatest + extent permissible under applicable law. + 3. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person’s Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the Work. + 4. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see +http://creativecommons.org/publicdomain/zero/1.0/. diff --git a/packages/color-helpers/README.md b/packages/color-helpers/README.md new file mode 100644 index 000000000..8da7235c2 --- /dev/null +++ b/packages/color-helpers/README.md @@ -0,0 +1,32 @@ +# Color Helpers + +[npm version][npm-url] +[Build Status][cli-url] +[Discord][discord] + +## Usage + +Add [Color Helpers] to your project: + +```bash +npm install postcss @csstools/color-helpers --save-dev +``` + +This package exists to join all the different color functions scattered among the Colors 4 and Colors 5 plugins we maintain such as: + +* [PostCSS Color Function] +* [PostCSS Lab Function] +* [PostCSS OKLab Function] + +## Copyright + +This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/tree/main/css-color-4. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + +[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test +[discord]: https://discord.gg/bUadyRwkJS +[npm-url]: https://www.npmjs.com/package/@csstools/color-helpers + +[Color Helpers]: https://github.com/csstools/postcss-plugins/tree/main/packages/color-helpers +[PostCSS Color Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-color-function +[PostCSS Lab Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-lab-functionw +[PostCSS OKLab Function]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-oklab-function diff --git a/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts b/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts new file mode 100644 index 000000000..c8b03e7c2 --- /dev/null +++ b/packages/color-helpers/dist/calculations/binary-search-gamut.d.ts @@ -0,0 +1 @@ +export declare function binarySearchGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color; diff --git a/packages/color-helpers/dist/calculations/contrast.d.ts b/packages/color-helpers/dist/calculations/contrast.d.ts new file mode 100644 index 000000000..118a372f3 --- /dev/null +++ b/packages/color-helpers/dist/calculations/contrast.d.ts @@ -0,0 +1 @@ +export declare function contrast(RGB1: Color, RGB2: Color): number; diff --git a/packages/color-helpers/dist/calculations/delta-EOK.d.ts b/packages/color-helpers/dist/calculations/delta-EOK.d.ts new file mode 100644 index 000000000..94efb8d53 --- /dev/null +++ b/packages/color-helpers/dist/calculations/delta-EOK.d.ts @@ -0,0 +1,13 @@ +/** + * @description Calculate deltaE OK which is the simple root sum of squares + * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1 + * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1 + * @return {number} How different a color sample is from reference + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js + */ +export declare function deltaEOK(reference: Color, sample: Color): number; diff --git a/packages/color-helpers/dist/calculations/index.d.ts b/packages/color-helpers/dist/calculations/index.d.ts new file mode 100644 index 000000000..3db911c00 --- /dev/null +++ b/packages/color-helpers/dist/calculations/index.d.ts @@ -0,0 +1,6 @@ +export * from './binary-search-gamut'; +export * from './polar-premultiply'; +export * from './map-gamut'; +export * from './delta-EOK'; +export * from './contrast'; +export * from './multiply-matrices'; diff --git a/packages/color-helpers/dist/calculations/map-gamut.d.ts b/packages/color-helpers/dist/calculations/map-gamut.d.ts new file mode 100644 index 000000000..b5ef8c32f --- /dev/null +++ b/packages/color-helpers/dist/calculations/map-gamut.d.ts @@ -0,0 +1 @@ +export declare function mapGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color; diff --git a/plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts b/packages/color-helpers/dist/calculations/multiply-matrices.d.ts similarity index 87% rename from plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts rename to packages/color-helpers/dist/calculations/multiply-matrices.d.ts index 3055a8245..b78e13fd5 100644 --- a/plugins/postcss-oklab-function/dist/css-color-4/multiply-matrices.d.ts +++ b/packages/color-helpers/dist/calculations/multiply-matrices.d.ts @@ -3,8 +3,7 @@ * Warning: No error handling for incompatible dimensions! * @author Lea Verou 2020 MIT License * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). * diff --git a/packages/color-helpers/dist/calculations/polar-premultiply.d.ts b/packages/color-helpers/dist/calculations/polar-premultiply.d.ts new file mode 100644 index 000000000..b2188d710 --- /dev/null +++ b/packages/color-helpers/dist/calculations/polar-premultiply.d.ts @@ -0,0 +1,15 @@ +/** + * Given a color in a cylindical polar colorspace and an alpha value + * return the premultiplied form. The index says which entry in the + * color array corresponds to hue angle for example, in OKLCH it + * would be 2 while in HSL it would be 0 + * + * @param color + * @param alpha + * @param hueIndex + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function polarPremultiply(color: Color, alpha: number, hueIndex: number): Color; diff --git a/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts new file mode 100644 index 000000000..74b497bd1 --- /dev/null +++ b/packages/color-helpers/dist/conversions/a98-rgb-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function a98_RGB_to_sRGB(a98: Color): Color; diff --git a/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts b/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts new file mode 100644 index 000000000..4cebd73a8 --- /dev/null +++ b/packages/color-helpers/dist/conversions/cie-xyz-50-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function cie_XYZ_50_to_sRGB(xyz: Color): Color; diff --git a/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts b/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts new file mode 100644 index 000000000..2d0e0d610 --- /dev/null +++ b/packages/color-helpers/dist/conversions/cie-xyz-65-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function cie_XYZ_65_to_sRGB(xyz: Color): Color; diff --git a/packages/color-helpers/dist/conversions/constants.d.ts b/packages/color-helpers/dist/conversions/constants.d.ts new file mode 100644 index 000000000..4d2e7a1e4 --- /dev/null +++ b/packages/color-helpers/dist/conversions/constants.d.ts @@ -0,0 +1,2 @@ +export declare const D50: number[]; +export declare const D65: number[]; diff --git a/packages/color-helpers/dist/conversions/d50-to-d65.d.ts b/packages/color-helpers/dist/conversions/d50-to-d65.d.ts new file mode 100644 index 000000000..77e2aab0b --- /dev/null +++ b/packages/color-helpers/dist/conversions/d50-to-d65.d.ts @@ -0,0 +1 @@ +export declare function D50_to_D65(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/d65-to-d50.d.ts b/packages/color-helpers/dist/conversions/d65-to-d50.d.ts new file mode 100644 index 000000000..1593ec542 --- /dev/null +++ b/packages/color-helpers/dist/conversions/d65-to-d50.d.ts @@ -0,0 +1 @@ +export declare function D65_to_D50(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/gam-2020.d.ts b/packages/color-helpers/dist/conversions/gam-2020.d.ts new file mode 100644 index 000000000..7ebd87cd9 --- /dev/null +++ b/packages/color-helpers/dist/conversions/gam-2020.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0 + * to gamma corrected form ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function gam_2020(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts b/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts new file mode 100644 index 000000000..3199b23dd --- /dev/null +++ b/packages/color-helpers/dist/conversions/gam-a98rgb.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of linear-light a98-rgb in the range 0.0-1.0 + * to gamma corrected form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function gam_a98rgb(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/gam-p3.d.ts b/packages/color-helpers/dist/conversions/gam-p3.d.ts new file mode 100644 index 000000000..bb8cddac0 --- /dev/null +++ b/packages/color-helpers/dist/conversions/gam-p3.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0 + * to gamma corrected form + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function gam_P3(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts b/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts new file mode 100644 index 000000000..99a411e03 --- /dev/null +++ b/packages/color-helpers/dist/conversions/gam-pro-photo.d.ts @@ -0,0 +1,10 @@ +/** + * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0 + * to gamma corrected form. + * Transfer curve is gamma 1.8 with a small linear portion. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function gam_ProPhoto(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/gam-srgb.d.ts b/packages/color-helpers/dist/conversions/gam-srgb.d.ts new file mode 100644 index 000000000..59850f13e --- /dev/null +++ b/packages/color-helpers/dist/conversions/gam-srgb.d.ts @@ -0,0 +1,13 @@ +/** + * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form + * Extended transfer function: + * For negative values, linear portion extends on reflection + * of axis, then uses reflected pow below that + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */ +export declare function gam_sRGB(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts b/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts new file mode 100644 index 000000000..1b4cc2617 --- /dev/null +++ b/packages/color-helpers/dist/conversions/hsl-to-srgb.d.ts @@ -0,0 +1,13 @@ +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} sat - Saturation as percentage 0..100 + * @param {number} light - Lightness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js + */ +export declare function HSL_to_sRGB(HSL: Color): number[]; diff --git a/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts b/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts new file mode 100644 index 000000000..8cb5ff7cd --- /dev/null +++ b/packages/color-helpers/dist/conversions/hue-to-rgb.d.ts @@ -0,0 +1,8 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function hueToRGB(t1: number, t2: number, hue: number): number; diff --git a/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts new file mode 100644 index 000000000..93f053db8 --- /dev/null +++ b/packages/color-helpers/dist/conversions/hwb-to-srgb.d.ts @@ -0,0 +1,13 @@ +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} white - Whiteness as percentage 0..100 + * @param {number} black - Blackness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js + */ +export declare function HWB_to_sRGB(HWB: Color): number[]; diff --git a/packages/color-helpers/dist/conversions/index.d.ts b/packages/color-helpers/dist/conversions/index.d.ts new file mode 100644 index 000000000..539f7ab8f --- /dev/null +++ b/packages/color-helpers/dist/conversions/index.d.ts @@ -0,0 +1,58 @@ +export * from './a98-rgb-to-srgb'; +export * from './cie-xyz-50-to-srgb'; +export * from './cie-xyz-65-to-srgb'; +export * from './constants'; +export * from './d50-to-d65'; +export * from './d65-to-d50'; +export * from './gam-2020'; +export * from './gam-a98rgb'; +export * from './gam-p3'; +export * from './gam-pro-photo'; +export * from './gam-srgb'; +export * from './hsl-to-srgb'; +export * from './hue-to-rgb'; +export * from './hwb-to-srgb'; +export * from './lab-to-lch'; +export * from './lab-to-p3'; +export * from './lab-to-srgb'; +export * from './lab-to-xyz'; +export * from './lch-to-lab'; +export * from './lch-to-p3'; +export * from './lch-to-rec2020'; +export * from './lch-to-srgb'; +export * from './lin-2020'; +export * from './lin-2020-to-xyz'; +export * from './lin-a98rgb'; +export * from './lin-a98rgb-to-xyz'; +export * from './lin-p3'; +export * from './lin-p3-to-xyz'; +export * from './lin-pro-photo'; +export * from './lin-pro-photo-to-xyz'; +export * from './lin-srgb'; +export * from './lin-srgb-to-xyz'; +export * from './naive-cmyk-to-srgb'; +export * from './oklab-to-oklch'; +export * from './oklab-to-p3'; +export * from './oklab-to-srgb'; +export * from './oklab-to-xyz'; +export * from './oklch-to-oklab'; +export * from './oklch-to-p3'; +export * from './oklch-to-srgb'; +export * from './p3-to-lch'; +export * from './p3-to-srgb'; +export * from './pro-photo-rgb-to-srgb'; +export * from './rec2020-to-lch'; +export * from './rec2020-to-srgb'; +export * from './srgb-linear-to-srgb'; +export * from './srgb-to-lch'; +export * from './srgb-to-luminance'; +export * from './srgb-to-srgb'; +export * from './xyz-to-lab'; +export * from './xyz-to-lin-2020'; +export * from './xyz-to-lin-a98rgb'; +export * from './xyz-to-lin-p3'; +export * from './xyz-to-lin-pro-photo'; +export * from './xyz-to-lin-srgb'; +export * from './xyz-to-oklab'; +export * from './xyz-to-uv'; +export * from './xyz-to-xy'; diff --git a/packages/color-helpers/dist/conversions/lab-to-lch.d.ts b/packages/color-helpers/dist/conversions/lab-to-lch.d.ts new file mode 100644 index 000000000..45149efa4 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lab-to-lch.d.ts @@ -0,0 +1,6 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function Lab_to_LCH(Lab: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lab-to-p3.d.ts b/packages/color-helpers/dist/conversions/lab-to-p3.d.ts new file mode 100644 index 000000000..63bb93acf --- /dev/null +++ b/packages/color-helpers/dist/conversions/lab-to-p3.d.ts @@ -0,0 +1 @@ +export declare function Lab_to_P3(labRaw: Color): [Color, boolean]; diff --git a/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts b/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts new file mode 100644 index 000000000..7e35606af --- /dev/null +++ b/packages/color-helpers/dist/conversions/lab-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function Lab_to_sRGB(labRaw: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts new file mode 100644 index 000000000..4f6851006 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lab-to-xyz.d.ts @@ -0,0 +1 @@ +export declare function Lab_to_XYZ(Lab: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lch-to-lab.d.ts b/packages/color-helpers/dist/conversions/lch-to-lab.d.ts new file mode 100644 index 000000000..798a55f9e --- /dev/null +++ b/packages/color-helpers/dist/conversions/lch-to-lab.d.ts @@ -0,0 +1,6 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function LCH_to_Lab(LCH: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lch-to-p3.d.ts b/packages/color-helpers/dist/conversions/lch-to-p3.d.ts new file mode 100644 index 000000000..25e86b490 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lch-to-p3.d.ts @@ -0,0 +1 @@ +export declare function LCH_to_P3(lchRaw: Color): [Color, boolean]; diff --git a/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts b/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts new file mode 100644 index 000000000..7195ff086 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lch-to-rec2020.d.ts @@ -0,0 +1,14 @@ +/** + * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from + * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma + * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0 + * range out of gamut colors may have negative components or components greater + * than 1.0 so check for that :) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function LCH_to_rec2020(LCH: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts b/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts new file mode 100644 index 000000000..0fa4a5817 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lch-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function LCH_to_sRGB(lchRaw: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts new file mode 100644 index 000000000..f1b43f4de --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-2020-to-xyz.d.ts @@ -0,0 +1,11 @@ +/** + * Convert an array of linear-light rec2020 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export declare function lin_2020_to_XYZ(rgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-2020.d.ts b/packages/color-helpers/dist/conversions/lin-2020.d.ts new file mode 100644 index 000000000..0c951201f --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-2020.d.ts @@ -0,0 +1,10 @@ +/** + * Convert an array of rec2020 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function lin_2020(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts new file mode 100644 index 000000000..eab3ddfe8 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-a98rgb-to-xyz.d.ts @@ -0,0 +1,17 @@ +/** + * Convert an array of linear-light a98-rgb values to CIE XYZ + * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * has greater numerical precision than section 4.3.5.3 of + * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * but the values below were calculated from first principles + * from the chromaticity coordinates of R G B W + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html + */ +export declare function lin_a98rgb_to_XYZ(rgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts b/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts new file mode 100644 index 000000000..3ccd0d9ea --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-a98rgb.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of a98-rgb values in the range 0.0 - 1.0 + * to linear light (un-companded) form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function lin_a98rgb(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts new file mode 100644 index 000000000..44e270378 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-p3-to-xyz.d.ts @@ -0,0 +1,11 @@ +/** + * Convert an array of linear-light display-p3 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export declare function lin_P3_to_XYZ(rgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-p3.d.ts b/packages/color-helpers/dist/conversions/lin-p3.d.ts new file mode 100644 index 000000000..dd20b3ec7 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-p3.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of display-p3 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function lin_P3(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts new file mode 100644 index 000000000..076b6996e --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-pro-photo-to-xyz.d.ts @@ -0,0 +1,11 @@ +/** + * Convert an array of linear-light prophoto-rgb values to CIE XYZ + * using D50 (so no chromatic adaptation needed afterwards) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export declare function lin_ProPhoto_to_XYZ(rgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts b/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts new file mode 100644 index 000000000..6a7151928 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-pro-photo.d.ts @@ -0,0 +1,10 @@ +/** + * Convert an array of prophoto-rgb values where in-gamut Colors are in the + * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is + * gamma 1.8 with a small linear portion. Extended transfer function + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function lin_ProPhoto(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts b/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts new file mode 100644 index 000000000..4e11938fe --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-srgb-to-xyz.d.ts @@ -0,0 +1,9 @@ +/** + * Convert an array of linear-light sRGB values to CIE XYZ + * using sRGB's own white, D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function lin_sRGB_to_XYZ(rgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/lin-srgb.d.ts b/packages/color-helpers/dist/conversions/lin-srgb.d.ts new file mode 100644 index 000000000..419a77ff3 --- /dev/null +++ b/packages/color-helpers/dist/conversions/lin-srgb.d.ts @@ -0,0 +1,14 @@ +/** + * Convert an array of of sRGB values where in-gamut values are in the range + * [0 - 1] to linear light (un-companded) form. + * Extended transfer function: + * For negative values, linear portion is extended on reflection of axis, + * then reflected power function is used. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */ +export declare function lin_sRGB(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts b/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts new file mode 100644 index 000000000..ed3590c98 --- /dev/null +++ b/packages/color-helpers/dist/conversions/naive-cmyk-to-srgb.d.ts @@ -0,0 +1,13 @@ +/** + * CMYK is an array of four values in the range [0.0, 1.0] the output is an + * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm + * does not generate out of gamut colors neither does it generate accurate + * simulations of practical CMYK colors + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): Color; diff --git a/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts b/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts new file mode 100644 index 000000000..bfead2074 --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklab-to-oklch.d.ts @@ -0,0 +1,8 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */ +export declare function OKLab_to_OKLCH(OKLab: Color): Color; diff --git a/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts b/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts new file mode 100644 index 000000000..ff65fa2cb --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklab-to-p3.d.ts @@ -0,0 +1 @@ +export declare function OKLab_to_P3(oklabRaw: Color): [Color, boolean]; diff --git a/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts b/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts new file mode 100644 index 000000000..03a97297d --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklab-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function OKLab_to_sRGB(oklabRaw: Color): Color; diff --git a/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts b/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts new file mode 100644 index 000000000..8f58814f4 --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklab-to-xyz.d.ts @@ -0,0 +1 @@ +export declare function OKLab_to_XYZ(OKLab: Color): Color; diff --git a/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts b/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts new file mode 100644 index 000000000..4ea09dd2e --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklch-to-oklab.d.ts @@ -0,0 +1,8 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */ +export declare function OKLCH_to_OKLab(OKLCH: Color): Color; diff --git a/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts b/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts new file mode 100644 index 000000000..60512c304 --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklch-to-p3.d.ts @@ -0,0 +1 @@ +export declare function OKLCH_to_P3(oklchRaw: Color): [Color, boolean]; diff --git a/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts b/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts new file mode 100644 index 000000000..d12c5a3f4 --- /dev/null +++ b/packages/color-helpers/dist/conversions/oklch-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function OKLCH_to_sRGB(oklchRaw: Color): Color; diff --git a/packages/color-helpers/dist/conversions/p3-to-lch.d.ts b/packages/color-helpers/dist/conversions/p3-to-lch.d.ts new file mode 100644 index 000000000..167543696 --- /dev/null +++ b/packages/color-helpers/dist/conversions/p3-to-lch.d.ts @@ -0,0 +1,12 @@ +/** + * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0 + * range to linear-light display-p3, then to CIE XYZ, then adapt from D65 + * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function P3_to_LCH(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts b/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts new file mode 100644 index 000000000..d91f0503a --- /dev/null +++ b/packages/color-helpers/dist/conversions/p3-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function p3_to_sRGB(displayP3: Color): Color; diff --git a/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts new file mode 100644 index 000000000..9ca6a410f --- /dev/null +++ b/packages/color-helpers/dist/conversions/pro-photo-rgb-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function proPhoto_RGB_to_sRGB(proPhoto: Color): Color; diff --git a/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts b/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts new file mode 100644 index 000000000..8ea2244cd --- /dev/null +++ b/packages/color-helpers/dist/conversions/rec2020-to-lch.d.ts @@ -0,0 +1,12 @@ +/** + * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function rec_2020_to_LCH(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts b/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts new file mode 100644 index 000000000..b35a0fdda --- /dev/null +++ b/packages/color-helpers/dist/conversions/rec2020-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function rec_2020_to_sRGB(rec: Color): Color; diff --git a/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts b/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts new file mode 100644 index 000000000..860d1a4f4 --- /dev/null +++ b/packages/color-helpers/dist/conversions/srgb-linear-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function sRGB_linear_to_sRGB(linearSRgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts b/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts new file mode 100644 index 000000000..30d9bee35 --- /dev/null +++ b/packages/color-helpers/dist/conversions/srgb-to-lch.d.ts @@ -0,0 +1,12 @@ +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to + * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function sRGB_to_LCH(RGB: Color): Color; diff --git a/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts b/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts new file mode 100644 index 000000000..71f9e589e --- /dev/null +++ b/packages/color-helpers/dist/conversions/srgb-to-luminance.d.ts @@ -0,0 +1,11 @@ +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function sRGB_to_luminance(RGB: Color): number; diff --git a/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts b/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts new file mode 100644 index 000000000..45e78c8fc --- /dev/null +++ b/packages/color-helpers/dist/conversions/srgb-to-srgb.d.ts @@ -0,0 +1 @@ +export declare function sRGB_to_sRGB(sRgb: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts new file mode 100644 index 000000000..79377c3b1 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lab.d.ts @@ -0,0 +1 @@ +export declare function XYZ_to_Lab(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts new file mode 100644 index 000000000..cea7ab42e --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lin-2020.d.ts @@ -0,0 +1,8 @@ +/** + * Convert XYZ to linear-light rec2020 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function XYZ_to_lin_2020(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts new file mode 100644 index 000000000..b628d1586 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lin-a98rgb.d.ts @@ -0,0 +1,8 @@ +/** + * Convert XYZ to linear-light a98-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function XYZ_to_lin_a98rgb(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts new file mode 100644 index 000000000..66cb1676a --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lin-p3.d.ts @@ -0,0 +1,8 @@ +/** + * Convert XYZ to linear-light P3 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function XYZ_to_lin_P3(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts new file mode 100644 index 000000000..f58fdcef2 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lin-pro-photo.d.ts @@ -0,0 +1,10 @@ +/** + * Convert XYZ to linear-light prophoto-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export declare function XYZ_to_lin_ProPhoto(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts b/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts new file mode 100644 index 000000000..ea6ec1cc5 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-lin-srgb.d.ts @@ -0,0 +1,6 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function XYZ_to_lin_sRGB(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts b/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts new file mode 100644 index 000000000..6fccfee6f --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-oklab.d.ts @@ -0,0 +1,9 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * XYZ <-> LMS matrices recalculated for consistent reference white + * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 + */ +export declare function XYZ_to_OKLab(XYZ: Color): Color; diff --git a/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts b/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts new file mode 100644 index 000000000..67970ebc2 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-uv.d.ts @@ -0,0 +1,10 @@ +/** + * Convert an array of three XYZ values to u*,v* chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function XYZ_to_uv(XYZ: Color): [number, number]; diff --git a/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts b/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts new file mode 100644 index 000000000..b14a797a0 --- /dev/null +++ b/packages/color-helpers/dist/conversions/xyz-to-xy.d.ts @@ -0,0 +1,10 @@ +/** + * Convert an array of three XYZ values to x,y chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export declare function XYZ_to_xy(XYZ: Color): [number, number]; diff --git a/packages/color-helpers/dist/index.cjs b/packages/color-helpers/dist/index.cjs new file mode 100644 index 000000000..6b73cf1c6 --- /dev/null +++ b/packages/color-helpers/dist/index.cjs @@ -0,0 +1,441 @@ +"use strict"; +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function clip(_){return _.map((_=>_<0?0:_>1?1:_))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLCH_to_OKLab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]} +/** + * @description Calculate deltaE OK which is the simple root sum of squares + * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1 + * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1 + * @return {number} How different a color sample is from reference + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js + */function deltaEOK(_,t){const[o,a,n]=_,[i,e,l]=t,r=o-i,s=a-e,u=n-l;return Math.sqrt(r**2+s**2+u**2)}function binarySearchGamut(_,t,o){let a=0,n=_[1];const i=_;for(;n-a>1e-4;){const _=clip(t(i));deltaEOK(OKLCH_to_OKLab(i),OKLCH_to_OKLab(o(_)))-.02<1e-4?a=i[1]:n=i[1],i[1]=(n+a)/2}return clip(t([...i]))} +/** + * Given a color in a cylindical polar colorspace and an alpha value + * return the premultiplied form. The index says which entry in the + * color array corresponds to hue angle for example, in OKLCH it + * would be 2 while in HSL it would be 0 + * + * @param color + * @param alpha + * @param hueIndex + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function mapGamut(_,t,o){return binarySearchGamut(_,t,o)} +/** + * Simple matrix (and vector) multiplication + * Warning: No error handling for incompatible dimensions! + * @author Lea Verou 2020 MIT License + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js + */function multiplyMatrices(_,t){const o=_.length;let a,n;a=Array.isArray(_[0])?_:[_],Array.isArray(t[0])||(n=t.map((_=>[_])));const i=n[0].length,e=n[0].map(((_,t)=>n.map((_=>_[t]))));let l=a.map((_=>e.map((t=>Array.isArray(_)?_.reduce(((_,o,a)=>_+o*(t[a]||0)),0):t.reduce(((t,o)=>t+o*_),0)))));return 1===o&&(l=l[0]),1===i?l.map((_=>_[0])):l} +/** + * Convert an array of linear-light sRGB values to CIE XYZ + * using sRGB's own white, D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_sRGB_to_XYZ(_){return multiplyMatrices([[506752/1228815,87881/245763,12673/70218],[87098/409605,175762/245763,12673/175545],[7918/409605,87881/737289,1001167/1053270]],_)} +/** + * Convert an array of of sRGB values where in-gamut values are in the range + * [0 - 1] to linear light (un-companded) form. + * Extended transfer function: + * For negative values, linear portion is extended on reflection of axis, + * then reflected power function is used. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */function lin_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<.04045?_/12.92:t*Math.pow((o+.055)/1.055,2.4)}))} +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */function sRGB_to_luminance(_){return lin_sRGB_to_XYZ(lin_sRGB(_))[1]} +/** + * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays + * + * of 0.0 to 1.0 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio + */var _=Object.freeze({__proto__:null,binarySearchGamut:binarySearchGamut,contrast:function contrast(_,t){const o=sRGB_to_luminance(_),a=sRGB_to_luminance(t);return o>a?(o+.05)/(a+.05):(a+.05)/(o+.05)},deltaEOK:deltaEOK,mapGamut:mapGamut,multiplyMatrices:multiplyMatrices,polarPremultiply:function polarPremultiply(_,t,o){return _.map(((_,a)=>_*(o===a?1:t)))}}); +/** + * Convert an array of a98-rgb values in the range 0.0 - 1.0 + * to linear light (un-companded) form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,563/256)}))} +/** + * Convert an array of linear-light a98-rgb values to CIE XYZ + * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * has greater numerical precision than section 4.3.5.3 of + * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * but the values below were calculated from first principles + * from the chromaticity coordinates of R G B W + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html + */function lin_a98rgb_to_XYZ(_){return multiplyMatrices([[573536/994567,263643/1420810,187206/994567],[591459/1989134,6239551/9945670,374412/4972835],[53769/1989134,351524/4972835,4929758/4972835]],_)} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * XYZ <-> LMS matrices recalculated for consistent reference white + * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 + */function XYZ_to_OKLab(_){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],_);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((_=>Math.cbrt(_))))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLab_to_OKLCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(_[1]**2+_[2]**2),t>=0?t:t+360]} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function XYZ_to_lin_sRGB(_){return multiplyMatrices([[12831/3959,-329/214,-1974/3959],[-851781/878810,1648619/878810,36519/878810],[705/12673,-2585/12673,705/667]],_)} +/** + * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form + * Extended transfer function: + * For negative values, linear portion extends on reflection + * of axis, then uses reflected pow below that + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */function gam_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>.0031308?t*(1.055*Math.pow(o,1/2.4)-.055):12.92*_}))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function inGamut(_){const[t,o,a]=_;return t>=-1e-4&&t<=1.0001&&o>=-1e-4&&o<=1.0001&&a>=-1e-4&&a<=1.0001} +/** + * Given OKLab, convert to XYZ relative to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLab_to_XYZ(_){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],_);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((_=>_**3)))} +/** + * Bradford chromatic adaptation from D50 to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function D50_to_D65(_){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],_)}const t=[.3457/.3585,1,.2958/.3585]; +/** + * Bradford chromatic adaptation from D65 to D50 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html + */ +function D65_to_D50(_){return multiplyMatrices([[1.0479298208405488,.022946793341019088,-.05019222954313557],[.029627815688159344,.990434484573249,-.01707382502938514],[-.009243058152591178,.015055144896577895,.7518742899580008]],_)} +/** + * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0 + * to gamma corrected form ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function gam_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a>.018053968510807?o*(t*Math.pow(a,.45)-(t-1)):4.5*_}))} +/** + * Convert an array of linear-light a98-rgb in the range 0.0-1.0 + * to gamma corrected form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +/** + * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0 + * to gamma corrected form + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function gam_P3(_){return gam_sRGB(_)} +/** + * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0 + * to gamma corrected form. + * Transfer curve is gamma 1.8 with a small linear portion. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} sat - Saturation as percentage 0..100 + * @param {number} light - Lightness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js + */ +function HSL_to_sRGB(_){let t=_[0],o=_[1],a=_[2];function f(_){const n=(_+t/30)%12,i=o*Math.min(a,1-a);return a-i*Math.max(-1,Math.min(n-3,9-n,1))}return t%=360,t<0&&(t+=360),o/=100,a/=100,[f(0),f(8),f(4)]} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function Lab_to_LCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(Math.pow(_[1],2)+Math.pow(_[2],2)),t>=0?t:t+360]} +/** + * Convert Lab to D50-adapted XYZ + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function Lab_to_XYZ(_){const o=24389/27,a=216/24389,n=[];n[1]=(_[0]+16)/116,n[0]=_[1]/500+n[1],n[2]=n[1]-_[2]/200;return[Math.pow(n[0],3)>a?Math.pow(n[0],3):(116*n[0]-16)/o,_[0]>8?Math.pow((_[0]+16)/116,3):_[0]/o,Math.pow(n[2],3)>a?Math.pow(n[2],3):(116*n[2]-16)/o].map(((_,o)=>_*t[o]))} +/** + * Convert XYZ to linear-light P3 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function XYZ_to_lin_P3(_){return multiplyMatrices([[446124/178915,-333277/357830,-72051/178915],[-14852/17905,63121/35810,423/17905],[11844/330415,-50337/660830,316169/330415]],_)} +/** + * Convert an array of display-p3 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_P3(_){return lin_sRGB(_)} +/** + * Convert an array of linear-light display-p3 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_P3_to_XYZ(_){return multiplyMatrices([[608311/1250200,189793/714400,198249/1000160],[35783/156275,247089/357200,198249/2500400],[0,32229/714400,5220557/5000800]],_)} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function LCH_to_Lab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]} +/** + * Convert XYZ to linear-light rec2020 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_lin_2020(_){return multiplyMatrices([[30757411/17917100,-6372589/17917100,-4539589/17917100],[-.666684351832489,1.616481236634939,467509/29648200],[792561/44930125,-1921689/44930125,.942103121235474]],_)} +/** + * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from + * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma + * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0 + * range out of gamut colors may have negative components or components greater + * than 1.0 so check for that :) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * Convert an array of rec2020 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function lin_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a<.08124285829863151?_/4.5:o*Math.pow((a+t-1)/t,1/.45)}))} +/** + * Convert an array of linear-light rec2020 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_2020_to_XYZ(_){return multiplyMatrices([[63426534/99577255,20160776/139408157,47086771/278816314],[26158966/99577255,.677998071518871,8267143/139408157],[0,19567812/697040785,1.0609850577107909]],_)} +/** + * Convert an array of prophoto-rgb values where in-gamut Colors are in the + * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is + * gamma 1.8 with a small linear portion. Extended transfer function + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<=.03125?_/16:t*Math.pow(o,1.8)}))} +/** + * Convert an array of linear-light prophoto-rgb values to CIE XYZ + * using D50 (so no chromatic adaptation needed afterwards) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_ProPhoto_to_XYZ(_){return multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],_)} +/** + * CMYK is an array of four values in the range [0.0, 1.0] the output is an + * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm + * does not generate out of gamut colors neither does it generate accurate + * simulations of practical CMYK colors + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * Assuming XYZ is relative to D50, convert to CIE Lab + * from CIE standard, which now defines these as a rational fraction + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_Lab(_){const o=_.map(((_,o)=>_/t[o])).map((_=>_>.008856451679035631?Math.cbrt(_):(903.2962962962963*_+16)/116));return[116*o[1]-16,500*(o[0]-o[1]),200*(o[1]-o[2])]} +/** + * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0 + * range to linear-light display-p3, then to CIE XYZ, then adapt from D65 + * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */var o=Object.freeze({__proto__:null,D50:t,D50_to_D65:D50_to_D65,D65:[.3127/.329,1,.3583/.329],D65_to_D50:D65_to_D50,HSL_to_sRGB:HSL_to_sRGB,HWB_to_sRGB: +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} white - Whiteness as percentage 0..100 + * @param {number} black - Blackness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js + */ +function HWB_to_sRGB(_){const t=_[0];let o=_[1],a=_[2];if(o/=100,a/=100,o+a>=1){const _=o/(o+a);return[_,_,_]}const n=HSL_to_sRGB([t,100,50]);for(let _=0;_<3;_++)n[_]*=1-o-a,n[_]+=o;return n},LCH_to_Lab:LCH_to_Lab,LCH_to_P3:function LCH_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},LCH_to_rec2020:function LCH_to_rec2020(_){return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(_)))))},LCH_to_sRGB:function LCH_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},Lab_to_LCH:Lab_to_LCH,Lab_to_P3:function Lab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},Lab_to_XYZ:Lab_to_XYZ,Lab_to_sRGB:function Lab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLCH_to_OKLab:OKLCH_to_OKLab,OKLCH_to_P3:function OKLCH_to_P3(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_P3(i),i=gam_P3(i),inGamut(i)?[clip(i),!0]:[mapGamut(n,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLCH_to_sRGB:function OKLCH_to_sRGB(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_sRGB(i),i=gam_sRGB(i),inGamut(i)?clip(i).map((_=>Math.round(255*_))):mapGamut(n,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLab_to_OKLCH:OKLab_to_OKLCH,OKLab_to_P3:function OKLab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLab_to_XYZ:OKLab_to_XYZ,OKLab_to_sRGB:function OKLab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},P3_to_LCH:function P3_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(_)))))},XYZ_to_Lab:XYZ_to_Lab,XYZ_to_OKLab:XYZ_to_OKLab,XYZ_to_lin_2020:XYZ_to_lin_2020,XYZ_to_lin_P3:XYZ_to_lin_P3,XYZ_to_lin_ProPhoto: +/** + * Convert XYZ to linear-light prophoto-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +function XYZ_to_lin_ProPhoto(_){return multiplyMatrices([[1.3457989731028281,-.25558010007997534,-.05110628506753401],[-.5446224939028347,1.5082327413132781,.02053603239147973],[0,0,1.2119675456389454]],_)} +/** + * Convert an array of three XYZ values to u*,v* chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,XYZ_to_lin_a98rgb: +/** + * Convert XYZ to linear-light a98-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_lin_a98rgb(_){return multiplyMatrices([[1829569/896150,-506331/896150,-308931/896150],[-851781/878810,1648619/878810,36519/878810],[16779/1248040,-147721/1248040,1266979/1248040]],_)},XYZ_to_lin_sRGB:XYZ_to_lin_sRGB,XYZ_to_uv:function XYZ_to_uv(_){const t=_[0],o=_[1],a=t+15*o+3*_[2];return[4*t/a,9*o/a]} +/** + * Convert an array of three XYZ values to x,y chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,XYZ_to_xy:function XYZ_to_xy(_){const t=_[0],o=_[1],a=t+o+_[2];return[t/a,o/a]},a98_RGB_to_sRGB:function a98_RGB_to_sRGB(_){let t=_.slice();t=lin_a98rgb(t),t=lin_a98rgb_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_50_to_sRGB:function cie_XYZ_50_to_sRGB(_){let t=_.slice();t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_65_to_sRGB:function cie_XYZ_65_to_sRGB(_){let t=_.slice(),o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},gam_2020:gam_2020,gam_P3:gam_P3,gam_ProPhoto:function gam_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>=.001953125?t*Math.pow(o,1/1.8):16*_}))},gam_a98rgb:function gam_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,256/563)}))},gam_sRGB:gam_sRGB,hueToRGB:function hueToRGB(_,t,o){return o<0&&(o+=6),o>=6&&(o-=6),o<1?(t-_)*o+_:o<3?t:o<4?(t-_)*(4-o)+_:_},lin_2020:lin_2020,lin_2020_to_XYZ:lin_2020_to_XYZ,lin_P3:lin_P3,lin_P3_to_XYZ:lin_P3_to_XYZ,lin_ProPhoto:lin_ProPhoto,lin_ProPhoto_to_XYZ:lin_ProPhoto_to_XYZ,lin_a98rgb:lin_a98rgb,lin_a98rgb_to_XYZ:lin_a98rgb_to_XYZ,lin_sRGB:lin_sRGB,lin_sRGB_to_XYZ:lin_sRGB_to_XYZ,naive_CMYK_to_sRGB:function naive_CMYK_to_sRGB(_){const t=_[0],o=_[1],a=_[2],n=_[3];return[1-Math.min(1,t*(1-n)+n),1-Math.min(1,o*(1-n)+n),1-Math.min(1,a*(1-n)+n)]},p3_to_sRGB:function p3_to_sRGB(_){let t=_.slice();t=lin_P3(t),t=lin_P3_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},proPhoto_RGB_to_sRGB:function proPhoto_RGB_to_sRGB(_){let t=_.slice();t=lin_ProPhoto(t),t=lin_ProPhoto_to_XYZ(t),t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))} +/** + * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,rec_2020_to_LCH:function rec_2020_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(_)))))},rec_2020_to_sRGB:function rec_2020_to_sRGB(_){let t=_.slice();t=lin_2020(t),t=lin_2020_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},sRGB_linear_to_sRGB:function sRGB_linear_to_sRGB(_){let t=_.slice();t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))} +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to + * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,sRGB_to_LCH:function sRGB_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(_)))))},sRGB_to_luminance:sRGB_to_luminance,sRGB_to_sRGB:function sRGB_to_sRGB(_){let t=_.slice();t=lin_sRGB(t),t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}}),a=Object.freeze({__proto__:null,clip:clip,inGamut:inGamut});exports.calculations=_,exports.conversions=o,exports.namedColors={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},exports.utils=a; diff --git a/packages/color-helpers/dist/index.d.ts b/packages/color-helpers/dist/index.d.ts new file mode 100644 index 000000000..2a876cf2f --- /dev/null +++ b/packages/color-helpers/dist/index.d.ts @@ -0,0 +1,4 @@ +export * as calculations from './calculations'; +export * as conversions from './conversions'; +export * as utils from './utils'; +export { namedColors } from './named-colors'; diff --git a/packages/color-helpers/dist/index.mjs b/packages/color-helpers/dist/index.mjs new file mode 100644 index 000000000..f023dc9e3 --- /dev/null +++ b/packages/color-helpers/dist/index.mjs @@ -0,0 +1,441 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function clip(_){return _.map((_=>_<0?0:_>1?1:_))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLCH_to_OKLab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]} +/** + * @description Calculate deltaE OK which is the simple root sum of squares + * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1 + * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1 + * @return {number} How different a color sample is from reference + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js + */function deltaEOK(_,t){const[o,a,n]=_,[i,e,l]=t,r=o-i,s=a-e,u=n-l;return Math.sqrt(r**2+s**2+u**2)}function binarySearchGamut(_,t,o){let a=0,n=_[1];const i=_;for(;n-a>1e-4;){const _=clip(t(i));deltaEOK(OKLCH_to_OKLab(i),OKLCH_to_OKLab(o(_)))-.02<1e-4?a=i[1]:n=i[1],i[1]=(n+a)/2}return clip(t([...i]))} +/** + * Given a color in a cylindical polar colorspace and an alpha value + * return the premultiplied form. The index says which entry in the + * color array corresponds to hue angle for example, in OKLCH it + * would be 2 while in HSL it would be 0 + * + * @param color + * @param alpha + * @param hueIndex + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function mapGamut(_,t,o){return binarySearchGamut(_,t,o)} +/** + * Simple matrix (and vector) multiplication + * Warning: No error handling for incompatible dimensions! + * @author Lea Verou 2020 MIT License + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js + */function multiplyMatrices(_,t){const o=_.length;let a,n;a=Array.isArray(_[0])?_:[_],Array.isArray(t[0])||(n=t.map((_=>[_])));const i=n[0].length,e=n[0].map(((_,t)=>n.map((_=>_[t]))));let l=a.map((_=>e.map((t=>Array.isArray(_)?_.reduce(((_,o,a)=>_+o*(t[a]||0)),0):t.reduce(((t,o)=>t+o*_),0)))));return 1===o&&(l=l[0]),1===i?l.map((_=>_[0])):l} +/** + * Convert an array of linear-light sRGB values to CIE XYZ + * using sRGB's own white, D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_sRGB_to_XYZ(_){return multiplyMatrices([[506752/1228815,87881/245763,12673/70218],[87098/409605,175762/245763,12673/175545],[7918/409605,87881/737289,1001167/1053270]],_)} +/** + * Convert an array of of sRGB values where in-gamut values are in the range + * [0 - 1] to linear light (un-companded) form. + * Extended transfer function: + * For negative values, linear portion is extended on reflection of axis, + * then reflected power function is used. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */function lin_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<.04045?_/12.92:t*Math.pow((o+.055)/1.055,2.4)}))} +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */function sRGB_to_luminance(_){return lin_sRGB_to_XYZ(lin_sRGB(_))[1]} +/** + * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays + * + * of 0.0 to 1.0 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio + */var _=Object.freeze({__proto__:null,binarySearchGamut:binarySearchGamut,contrast:function contrast(_,t){const o=sRGB_to_luminance(_),a=sRGB_to_luminance(t);return o>a?(o+.05)/(a+.05):(a+.05)/(o+.05)},deltaEOK:deltaEOK,mapGamut:mapGamut,multiplyMatrices:multiplyMatrices,polarPremultiply:function polarPremultiply(_,t,o){return _.map(((_,a)=>_*(o===a?1:t)))}}); +/** + * Convert an array of a98-rgb values in the range 0.0 - 1.0 + * to linear light (un-companded) form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,563/256)}))} +/** + * Convert an array of linear-light a98-rgb values to CIE XYZ + * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * has greater numerical precision than section 4.3.5.3 of + * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * but the values below were calculated from first principles + * from the chromaticity coordinates of R G B W + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html + */function lin_a98rgb_to_XYZ(_){return multiplyMatrices([[573536/994567,263643/1420810,187206/994567],[591459/1989134,6239551/9945670,374412/4972835],[53769/1989134,351524/4972835,4929758/4972835]],_)} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * XYZ <-> LMS matrices recalculated for consistent reference white + * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 + */function XYZ_to_OKLab(_){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],_);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((_=>Math.cbrt(_))))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLab_to_OKLCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(_[1]**2+_[2]**2),t>=0?t:t+360]} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function XYZ_to_lin_sRGB(_){return multiplyMatrices([[12831/3959,-329/214,-1974/3959],[-851781/878810,1648619/878810,36519/878810],[705/12673,-2585/12673,705/667]],_)} +/** + * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form + * Extended transfer function: + * For negative values, linear portion extends on reflection + * of axis, then uses reflected pow below that + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */function gam_sRGB(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>.0031308?t*(1.055*Math.pow(o,1/2.4)-.055):12.92*_}))} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function inGamut(_){const[t,o,a]=_;return t>=-1e-4&&t<=1.0001&&o>=-1e-4&&o<=1.0001&&a>=-1e-4&&a<=1.0001} +/** + * Given OKLab, convert to XYZ relative to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */function OKLab_to_XYZ(_){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],_);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((_=>_**3)))} +/** + * Bradford chromatic adaptation from D50 to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function D50_to_D65(_){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],_)}const t=[.3457/.3585,1,.2958/.3585]; +/** + * Bradford chromatic adaptation from D65 to D50 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html + */ +function D65_to_D50(_){return multiplyMatrices([[1.0479298208405488,.022946793341019088,-.05019222954313557],[.029627815688159344,.990434484573249,-.01707382502938514],[-.009243058152591178,.015055144896577895,.7518742899580008]],_)} +/** + * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0 + * to gamma corrected form ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function gam_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a>.018053968510807?o*(t*Math.pow(a,.45)-(t-1)):4.5*_}))} +/** + * Convert an array of linear-light a98-rgb in the range 0.0-1.0 + * to gamma corrected form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +/** + * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0 + * to gamma corrected form + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function gam_P3(_){return gam_sRGB(_)} +/** + * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0 + * to gamma corrected form. + * Transfer curve is gamma 1.8 with a small linear portion. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} sat - Saturation as percentage 0..100 + * @param {number} light - Lightness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js + */ +function HSL_to_sRGB(_){let t=_[0],o=_[1],a=_[2];function f(_){const n=(_+t/30)%12,i=o*Math.min(a,1-a);return a-i*Math.max(-1,Math.min(n-3,9-n,1))}return t%=360,t<0&&(t+=360),o/=100,a/=100,[f(0),f(8),f(4)]} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function Lab_to_LCH(_){const t=180*Math.atan2(_[2],_[1])/Math.PI;return[_[0],Math.sqrt(Math.pow(_[1],2)+Math.pow(_[2],2)),t>=0?t:t+360]} +/** + * Convert Lab to D50-adapted XYZ + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function Lab_to_XYZ(_){const o=24389/27,a=216/24389,n=[];n[1]=(_[0]+16)/116,n[0]=_[1]/500+n[1],n[2]=n[1]-_[2]/200;return[Math.pow(n[0],3)>a?Math.pow(n[0],3):(116*n[0]-16)/o,_[0]>8?Math.pow((_[0]+16)/116,3):_[0]/o,Math.pow(n[2],3)>a?Math.pow(n[2],3):(116*n[2]-16)/o].map(((_,o)=>_*t[o]))} +/** + * Convert XYZ to linear-light P3 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function XYZ_to_lin_P3(_){return multiplyMatrices([[446124/178915,-333277/357830,-72051/178915],[-14852/17905,63121/35810,423/17905],[11844/330415,-50337/660830,316169/330415]],_)} +/** + * Convert an array of display-p3 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_P3(_){return lin_sRGB(_)} +/** + * Convert an array of linear-light display-p3 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_P3_to_XYZ(_){return multiplyMatrices([[608311/1250200,189793/714400,198249/1000160],[35783/156275,247089/357200,198249/2500400],[0,32229/714400,5220557/5000800]],_)} +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function LCH_to_Lab(_){return[_[0],_[1]*Math.cos(_[2]*Math.PI/180),_[1]*Math.sin(_[2]*Math.PI/180)]} +/** + * Convert XYZ to linear-light rec2020 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_lin_2020(_){return multiplyMatrices([[30757411/17917100,-6372589/17917100,-4539589/17917100],[-.666684351832489,1.616481236634939,467509/29648200],[792561/44930125,-1921689/44930125,.942103121235474]],_)} +/** + * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from + * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma + * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0 + * range out of gamut colors may have negative components or components greater + * than 1.0 so check for that :) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * Convert an array of rec2020 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function lin_2020(_){const t=1.09929682680944;return _.map((function(_){const o=_<0?-1:1,a=Math.abs(_);return a<.08124285829863151?_/4.5:o*Math.pow((a+t-1)/t,1/.45)}))} +/** + * Convert an array of linear-light rec2020 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_2020_to_XYZ(_){return multiplyMatrices([[63426534/99577255,20160776/139408157,47086771/278816314],[26158966/99577255,.677998071518871,8267143/139408157],[0,19567812/697040785,1.0609850577107909]],_)} +/** + * Convert an array of prophoto-rgb values where in-gamut Colors are in the + * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is + * gamma 1.8 with a small linear portion. Extended transfer function + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */function lin_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o<=.03125?_/16:t*Math.pow(o,1.8)}))} +/** + * Convert an array of linear-light prophoto-rgb values to CIE XYZ + * using D50 (so no chromatic adaptation needed afterwards) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */function lin_ProPhoto_to_XYZ(_){return multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],_)} +/** + * CMYK is an array of four values in the range [0.0, 1.0] the output is an + * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm + * does not generate out of gamut colors neither does it generate accurate + * simulations of practical CMYK colors + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +/** + * Assuming XYZ is relative to D50, convert to CIE Lab + * from CIE standard, which now defines these as a rational fraction + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_Lab(_){const o=_.map(((_,o)=>_/t[o])).map((_=>_>.008856451679035631?Math.cbrt(_):(903.2962962962963*_+16)/116));return[116*o[1]-16,500*(o[0]-o[1]),200*(o[1]-o[2])]} +/** + * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0 + * range to linear-light display-p3, then to CIE XYZ, then adapt from D65 + * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */var o=Object.freeze({__proto__:null,D50:t,D50_to_D65:D50_to_D65,D65:[.3127/.329,1,.3583/.329],D65_to_D50:D65_to_D50,HSL_to_sRGB:HSL_to_sRGB,HWB_to_sRGB: +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} white - Whiteness as percentage 0..100 + * @param {number} black - Blackness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js + */ +function HWB_to_sRGB(_){const t=_[0];let o=_[1],a=_[2];if(o/=100,a/=100,o+a>=1){const _=o/(o+a);return[_,_,_]}const n=HSL_to_sRGB([t,100,50]);for(let _=0;_<3;_++)n[_]*=1-o-a,n[_]+=o;return n},LCH_to_Lab:LCH_to_Lab,LCH_to_P3:function LCH_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},LCH_to_rec2020:function LCH_to_rec2020(_){return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(_)))))},LCH_to_sRGB:function LCH_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a%360];n=LCH_to_Lab(n),n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},Lab_to_LCH:Lab_to_LCH,Lab_to_P3:function Lab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},Lab_to_XYZ:Lab_to_XYZ,Lab_to_sRGB:function Lab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),Math.min(Math.max(o,-160),160),Math.min(Math.max(a,-160),160)];n=Lab_to_XYZ(n);let i=n.slice();return i=D50_to_D65(i),i=XYZ_to_OKLab(i),i=OKLab_to_OKLCH(i),i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=D50_to_D65(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLCH_to_OKLab:OKLCH_to_OKLab,OKLCH_to_P3:function OKLCH_to_P3(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_P3(i),i=gam_P3(i),inGamut(i)?[clip(i),!0]:[mapGamut(n,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLCH_to_sRGB:function OKLCH_to_sRGB(_){const[t,o,a]=_,n=[Math.max(t,0),o,a%360];let i=n;return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),i=OKLCH_to_OKLab(i),i=OKLab_to_XYZ(i),i=XYZ_to_lin_sRGB(i),i=gam_sRGB(i),inGamut(i)?clip(i).map((_=>Math.round(255*_))):mapGamut(n,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},OKLab_to_OKLCH:OKLab_to_OKLCH,OKLab_to_P3:function OKLab_to_P3(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_P3(n),n=gam_P3(n),inGamut(n)?[clip(n),!0]:[mapGamut(i,(_=>gam_P3(_=XYZ_to_lin_P3(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_P3_to_XYZ(_=lin_P3(_)))))),!1]},OKLab_to_XYZ:OKLab_to_XYZ,OKLab_to_sRGB:function OKLab_to_sRGB(_){const[t,o,a]=_;let n=[Math.max(t,0),o,a],i=OKLab_to_OKLCH(n);return i[0]<1e-6&&(i=[0,0,0]),i[0]>.999999&&(i=[1,0,0]),n=OKLab_to_XYZ(n),n=XYZ_to_lin_sRGB(n),n=gam_sRGB(n),inGamut(n)?clip(n).map((_=>Math.round(255*_))):mapGamut(i,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_)))))).map((_=>Math.round(255*_)))},P3_to_LCH:function P3_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(_)))))},XYZ_to_Lab:XYZ_to_Lab,XYZ_to_OKLab:XYZ_to_OKLab,XYZ_to_lin_2020:XYZ_to_lin_2020,XYZ_to_lin_P3:XYZ_to_lin_P3,XYZ_to_lin_ProPhoto: +/** + * Convert XYZ to linear-light prophoto-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +function XYZ_to_lin_ProPhoto(_){return multiplyMatrices([[1.3457989731028281,-.25558010007997534,-.05110628506753401],[-.5446224939028347,1.5082327413132781,.02053603239147973],[0,0,1.2119675456389454]],_)} +/** + * Convert an array of three XYZ values to u*,v* chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,XYZ_to_lin_a98rgb: +/** + * Convert XYZ to linear-light a98-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +function XYZ_to_lin_a98rgb(_){return multiplyMatrices([[1829569/896150,-506331/896150,-308931/896150],[-851781/878810,1648619/878810,36519/878810],[16779/1248040,-147721/1248040,1266979/1248040]],_)},XYZ_to_lin_sRGB:XYZ_to_lin_sRGB,XYZ_to_uv:function XYZ_to_uv(_){const t=_[0],o=_[1],a=t+15*o+3*_[2];return[4*t/a,9*o/a]} +/** + * Convert an array of three XYZ values to x,y chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,XYZ_to_xy:function XYZ_to_xy(_){const t=_[0],o=_[1],a=t+o+_[2];return[t/a,o/a]},a98_RGB_to_sRGB:function a98_RGB_to_sRGB(_){let t=_.slice();t=lin_a98rgb(t),t=lin_a98rgb_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_50_to_sRGB:function cie_XYZ_50_to_sRGB(_){let t=_.slice();t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},cie_XYZ_65_to_sRGB:function cie_XYZ_65_to_sRGB(_){let t=_.slice(),o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},gam_2020:gam_2020,gam_P3:gam_P3,gam_ProPhoto:function gam_ProPhoto(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return o>=.001953125?t*Math.pow(o,1/1.8):16*_}))},gam_a98rgb:function gam_a98rgb(_){return _.map((function(_){const t=_<0?-1:1,o=Math.abs(_);return t*Math.pow(o,256/563)}))},gam_sRGB:gam_sRGB,hueToRGB:function hueToRGB(_,t,o){return o<0&&(o+=6),o>=6&&(o-=6),o<1?(t-_)*o+_:o<3?t:o<4?(t-_)*(4-o)+_:_},lin_2020:lin_2020,lin_2020_to_XYZ:lin_2020_to_XYZ,lin_P3:lin_P3,lin_P3_to_XYZ:lin_P3_to_XYZ,lin_ProPhoto:lin_ProPhoto,lin_ProPhoto_to_XYZ:lin_ProPhoto_to_XYZ,lin_a98rgb:lin_a98rgb,lin_a98rgb_to_XYZ:lin_a98rgb_to_XYZ,lin_sRGB:lin_sRGB,lin_sRGB_to_XYZ:lin_sRGB_to_XYZ,naive_CMYK_to_sRGB:function naive_CMYK_to_sRGB(_){const t=_[0],o=_[1],a=_[2],n=_[3];return[1-Math.min(1,t*(1-n)+n),1-Math.min(1,o*(1-n)+n),1-Math.min(1,a*(1-n)+n)]},p3_to_sRGB:function p3_to_sRGB(_){let t=_.slice();t=lin_P3(t),t=lin_P3_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},proPhoto_RGB_to_sRGB:function proPhoto_RGB_to_sRGB(_){let t=_.slice();t=lin_ProPhoto(t),t=lin_ProPhoto_to_XYZ(t),t=D50_to_D65(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))} +/** + * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,rec_2020_to_LCH:function rec_2020_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(_)))))},rec_2020_to_sRGB:function rec_2020_to_sRGB(_){let t=_.slice();t=lin_2020(t),t=lin_2020_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))},sRGB_linear_to_sRGB:function sRGB_linear_to_sRGB(_){let t=_.slice();t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))} +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to + * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */,sRGB_to_LCH:function sRGB_to_LCH(_){return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(_)))))},sRGB_to_luminance:sRGB_to_luminance,sRGB_to_sRGB:function sRGB_to_sRGB(_){let t=_.slice();t=lin_sRGB(t),t=lin_sRGB_to_XYZ(t);let o=t.slice();return o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),t=XYZ_to_lin_sRGB(t),t=gam_sRGB(t),inGamut(t)?clip(t):mapGamut(o,(_=>gam_sRGB(_=XYZ_to_lin_sRGB(_=OKLab_to_XYZ(_=OKLCH_to_OKLab(_))))),(_=>OKLab_to_OKLCH(_=XYZ_to_OKLab(_=lin_sRGB_to_XYZ(_=lin_sRGB(_))))))}}),a=Object.freeze({__proto__:null,clip:clip,inGamut:inGamut});const n={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]};export{_ as calculations,o as conversions,n as namedColors,a as utils}; diff --git a/packages/color-helpers/dist/named-colors/index.d.ts b/packages/color-helpers/dist/named-colors/index.d.ts new file mode 100644 index 000000000..1ff07d599 --- /dev/null +++ b/packages/color-helpers/dist/named-colors/index.d.ts @@ -0,0 +1 @@ +export declare const namedColors: Record; diff --git a/packages/color-helpers/dist/utils/clip.d.ts b/packages/color-helpers/dist/utils/clip.d.ts new file mode 100644 index 000000000..71126b1bb --- /dev/null +++ b/packages/color-helpers/dist/utils/clip.d.ts @@ -0,0 +1,6 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function clip(color: Color): Color; diff --git a/packages/color-helpers/dist/utils/in-gamut.d.ts b/packages/color-helpers/dist/utils/in-gamut.d.ts new file mode 100644 index 000000000..917d403f0 --- /dev/null +++ b/packages/color-helpers/dist/utils/in-gamut.d.ts @@ -0,0 +1,6 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export declare function inGamut(x: Color): boolean; diff --git a/packages/color-helpers/dist/utils/index.d.ts b/packages/color-helpers/dist/utils/index.d.ts new file mode 100644 index 000000000..b73e4598c --- /dev/null +++ b/packages/color-helpers/dist/utils/index.d.ts @@ -0,0 +1,2 @@ +export * from './clip'; +export * from './in-gamut'; diff --git a/packages/color-helpers/package.json b/packages/color-helpers/package.json new file mode 100644 index 000000000..a492c1678 --- /dev/null +++ b/packages/color-helpers/package.json @@ -0,0 +1,73 @@ +{ + "name": "@csstools/color-helpers", + "description": "Color helpers to ease transformation between formats, gamut, etc", + "version": "0.0.0", + "contributors": [ + { + "name": "Antonio Laguna", + "email": "antonio@laguna.es", + "url": "https://antonio.laguna.es" + }, + { + "name": "Romain Menke ", + "email": "romainmenke@gmail.com" + } + ], + "license": "CC0-1.0", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "main": "dist/index.cjs", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "files": [ + "CHANGELOG.md", + "LICENSE.md", + "README.md", + "dist" + ], + "scripts": { + "prebuild": "npm run clean", + "build": "rollup -c ../../rollup/default.mjs", + "check-sources-integrity": "node ./scripts/check-changes.mjs", + "check-sources-integrity:rewrite": "REWRITE_HASHES=true node ./scripts/check-changes.mjs", + "clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true }); fs.mkdirSync('./dist');\"", + "lint": "npm run lint:eslint && npm run lint:package-json", + "lint:eslint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern", + "lint:package-json": "node ../../.github/bin/format-package-json.mjs", + "prepublishOnly": "npm run clean && npm run build && npm run test", + "stryker": "stryker run --logLevel error", + "test": "npm run test:exports", + "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs" + }, + "homepage": "https://github.com/csstools/postcss-plugins/tree/main/packages/color-helpers#readme", + "repository": { + "type": "git", + "url": "https://github.com/csstools/postcss-plugins.git", + "directory": "packages/color-helpers" + }, + "bugs": "https://github.com/csstools/postcss-plugins/issues", + "keywords": [ + "colors", + "css" + ], + "volta": { + "extends": "../../package.json" + }, + "eslintConfig": { + "rules": { + "@typescript-eslint/no-loss-of-precision": "off" + } + } +} diff --git a/packages/color-helpers/scripts/check-changes.mjs b/packages/color-helpers/scripts/check-changes.mjs new file mode 100644 index 000000000..1de24d762 --- /dev/null +++ b/packages/color-helpers/scripts/check-changes.mjs @@ -0,0 +1,45 @@ +import crypto from 'crypto'; +import path from 'path'; +import { URL } from 'url'; +import fs from 'fs/promises'; + +const __dirname = new URL('.', import.meta.url).pathname; +const hashesPath = path.resolve(__dirname, './hashes.json'); +const hashesFile = await fs.readFile(hashesPath, 'utf8').then(JSON.parse); +const isRewriting = process.env.REWRITE_HASHES; + +const WATCHED_FILES = [ + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/utilities.js', + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/conversions.js', + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/deltaEOK.js', + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/multiply-matrices.js', + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/hslToRgb.js', + 'https://raw.githubusercontent.com/w3c/csswg-drafts/main/css-color-4/hwbToRgb.js', +]; + +const newHashes = await Promise.all(WATCHED_FILES.map(async urlPath => { + const content = await fetch(urlPath).then(response => response.text()); + const hash = crypto.createHash('md5'); + hash.update(content, 'utf8'); + return hash.digest('hex'); +})); + +const changes = newHashes + .map((hash, index) => [hash, WATCHED_FILES[index]]) + .filter(([hash], index) => hashesFile[index] !== hash) + .map(([,file]) => file); + +if (changes.length) { + console.log('Changes have been detected in the following files:'); + changes.forEach(change => console.log('└ %s', change)); + + if (isRewriting) { + await fs.writeFile(hashesPath, JSON.stringify(newHashes, null, '\t')); + console.log('Changes have been updated.'); + process.exit(0); + } else { + process.exit(1); + } +} + +console.log('No changes detected'); diff --git a/packages/color-helpers/scripts/hashes.json b/packages/color-helpers/scripts/hashes.json new file mode 100644 index 000000000..f4ac63379 --- /dev/null +++ b/packages/color-helpers/scripts/hashes.json @@ -0,0 +1,8 @@ +[ + "384d52db3fcd98381e18743e1eba590a", + "6014c79b98dfe166e3e02232d8c3beaa", + "094c9859b0960c4e394947cc4832b54f", + "c9e2f2a3b2cba543a01cb8aa5d77c04a", + "f28e9d179704b95a9cd40fbf5b5f1164", + "a0b388982712b1849c991ce0e323828e" +] \ No newline at end of file diff --git a/plugins/postcss-color-function/src/css-color-4/LICENSE.md b/packages/color-helpers/src/calculations/LICENSE.md similarity index 100% rename from plugins/postcss-color-function/src/css-color-4/LICENSE.md rename to packages/color-helpers/src/calculations/LICENSE.md diff --git a/packages/color-helpers/src/calculations/binary-search-gamut.ts b/packages/color-helpers/src/calculations/binary-search-gamut.ts new file mode 100644 index 000000000..b170fe181 --- /dev/null +++ b/packages/color-helpers/src/calculations/binary-search-gamut.ts @@ -0,0 +1,28 @@ +import { clip } from 'utils/clip'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { deltaEOK } from 'calculations/delta-EOK'; + +export function binarySearchGamut( + startOKLCH: Color, + toDestination: (x: Color) => Color, + fromDestination: (x: Color) => Color, +): Color { + let min = 0; + let max = startOKLCH[1]; + const current = startOKLCH; + + while (max - min > 0.0001) { + const clipped = clip(toDestination(current)); + const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped))); + // are we inside the gamut (or very close to the boundary, outside) + if (deltaE - 0.02 < 0.0001) { + min = current[1]; + } else { + max = current[1]; + } + // binary search + current[1] = (max + min) / 2; + } + + return clip(toDestination([...current])); +} diff --git a/packages/color-helpers/src/calculations/contrast.ts b/packages/color-helpers/src/calculations/contrast.ts new file mode 100644 index 000000000..b8c12e60d --- /dev/null +++ b/packages/color-helpers/src/calculations/contrast.ts @@ -0,0 +1,23 @@ +/** + * Return WCAG 2.1 contrast ratio for two sRGB values given as arrays + * + * of 0.0 to 1.0 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio + */ +import { sRGB_to_luminance } from 'conversions/srgb-to-luminance'; + +export function contrast(RGB1: Color, RGB2: Color): number { + const L1 = sRGB_to_luminance(RGB1); + const L2 = sRGB_to_luminance(RGB2); + + if (L1 > L2) { + return (L1 + 0.05) / (L2 + 0.05); + } + + return (L2 + 0.05) / (L1 + 0.05); +} diff --git a/plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts b/packages/color-helpers/src/calculations/delta-EOK.ts similarity index 53% rename from plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts rename to packages/color-helpers/src/calculations/delta-EOK.ts index ce023047e..c6a9c208a 100644 --- a/plugins/postcss-oklab-function/src/css-color-4/deltaEOK.ts +++ b/packages/color-helpers/src/calculations/delta-EOK.ts @@ -1,16 +1,16 @@ /** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * @description Calculate deltaE OK which is the simple root sum of squares + * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1 + * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1 + * @return {number} How different a color sample is from reference + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). * * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js */ - -// Calculate deltaE OK -// simple root sum of squares -type color = [number, number, number]; -export function deltaEOK(reference: color, sample: color): number { +export function deltaEOK(reference: Color, sample: Color): number { // Given reference and sample are both in OKLab const [L1, a1, b1] = reference; const [L2, a2, b2] = sample; diff --git a/packages/color-helpers/src/calculations/index.ts b/packages/color-helpers/src/calculations/index.ts new file mode 100644 index 000000000..3db911c00 --- /dev/null +++ b/packages/color-helpers/src/calculations/index.ts @@ -0,0 +1,6 @@ +export * from './binary-search-gamut'; +export * from './polar-premultiply'; +export * from './map-gamut'; +export * from './delta-EOK'; +export * from './contrast'; +export * from './multiply-matrices'; diff --git a/packages/color-helpers/src/calculations/map-gamut.ts b/packages/color-helpers/src/calculations/map-gamut.ts new file mode 100644 index 000000000..78de6f0e1 --- /dev/null +++ b/packages/color-helpers/src/calculations/map-gamut.ts @@ -0,0 +1,5 @@ +import { binarySearchGamut } from 'calculations/binary-search-gamut'; + +export function mapGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color { + return binarySearchGamut(startOKLCH, toDestination, fromDestination); +} diff --git a/plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts b/packages/color-helpers/src/calculations/multiply-matrices.ts similarity index 94% rename from plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts rename to packages/color-helpers/src/calculations/multiply-matrices.ts index e8a827309..4590dda6e 100644 --- a/plugins/postcss-color-function/src/css-color-4/multiply-matrices.ts +++ b/packages/color-helpers/src/calculations/multiply-matrices.ts @@ -3,8 +3,7 @@ * Warning: No error handling for incompatible dimensions! * @author Lea Verou 2020 MIT License * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). * diff --git a/packages/color-helpers/src/calculations/polar-premultiply.ts b/packages/color-helpers/src/calculations/polar-premultiply.ts new file mode 100644 index 000000000..e17d7664f --- /dev/null +++ b/packages/color-helpers/src/calculations/polar-premultiply.ts @@ -0,0 +1,17 @@ +/** + * Given a color in a cylindical polar colorspace and an alpha value + * return the premultiplied form. The index says which entry in the + * color array corresponds to hue angle for example, in OKLCH it + * would be 2 while in HSL it would be 0 + * + * @param color + * @param alpha + * @param hueIndex + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function polarPremultiply(color: Color, alpha: number, hueIndex: number): Color { + return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as Color; +} diff --git a/packages/color-helpers/src/conversions/LICENSE.md b/packages/color-helpers/src/conversions/LICENSE.md new file mode 100644 index 000000000..0913e1881 --- /dev/null +++ b/packages/color-helpers/src/conversions/LICENSE.md @@ -0,0 +1,3 @@ +Some documents in this Directory are licensed by contributors +under the +[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). diff --git a/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts b/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts new file mode 100644 index 000000000..09564e2c2 --- /dev/null +++ b/packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts @@ -0,0 +1,54 @@ +import { lin_a98rgb } from 'conversions/lin-a98rgb'; +import { lin_a98rgb_to_XYZ } from 'conversions/lin-a98rgb-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; + +export function a98_RGB_to_sRGB(a98: Color): Color { + let conversion = a98.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_a98rgb(conversion); + conversion = lin_a98rgb_to_XYZ(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts b/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts new file mode 100644 index 000000000..c713b0506 --- /dev/null +++ b/packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts @@ -0,0 +1,52 @@ +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; + +export function cie_XYZ_50_to_sRGB(xyz: Color): Color { + let conversion = xyz.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = D50_to_D65(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts b/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts new file mode 100644 index 000000000..6d444bb3e --- /dev/null +++ b/packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts @@ -0,0 +1,49 @@ +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; + +export function cie_XYZ_65_to_sRGB(xyz: Color): Color { + let conversion = xyz.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/constants.ts b/packages/color-helpers/src/conversions/constants.ts new file mode 100644 index 000000000..04b1a4cbe --- /dev/null +++ b/packages/color-helpers/src/conversions/constants.ts @@ -0,0 +1,3 @@ +// standard white points, defined by 4-figure CIE x,y chromaticities +export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585]; +export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290]; diff --git a/packages/color-helpers/src/conversions/d50-to-d65.ts b/packages/color-helpers/src/conversions/d50-to-d65.ts new file mode 100644 index 000000000..1af0962a4 --- /dev/null +++ b/packages/color-helpers/src/conversions/d50-to-d65.ts @@ -0,0 +1,18 @@ +/** + * Bradford chromatic adaptation from D50 to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +export function D50_to_D65(XYZ: Color): Color { + const M = [ + [0.9554734527042182, -0.023098536874261423, 0.0632593086610217], + [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008], + [0.012314001688319899, -0.020507696433477912, 1.3303659366080753], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/d65-to-d50.ts b/packages/color-helpers/src/conversions/d65-to-d50.ts new file mode 100644 index 000000000..fea324afd --- /dev/null +++ b/packages/color-helpers/src/conversions/d65-to-d50.ts @@ -0,0 +1,23 @@ +/** + * Bradford chromatic adaptation from D65 to D50 + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html + */ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +export function D65_to_D50(XYZ: Color): Color { + // The matrix below is the result of three operations: + // - convert from XYZ to retinal cone domain + // - scale components from one reference white to another + // - convert back to XYZ + const M = [ + [1.0479298208405488, 0.022946793341019088, -0.05019222954313557], + [0.029627815688159344, 0.990434484573249, -0.01707382502938514], + [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/gam-2020.ts b/packages/color-helpers/src/conversions/gam-2020.ts new file mode 100644 index 000000000..02d6f71a3 --- /dev/null +++ b/packages/color-helpers/src/conversions/gam-2020.ts @@ -0,0 +1,23 @@ +/** + * Convert an array of linear-light rec2020 RGB in the range 0.0-1.0 + * to gamma corrected form ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function gam_2020(RGB: Color): Color { + const α = 1.09929682680944; + const β = 0.018053968510807; + + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs > β) { + return sign * (α * Math.pow(abs, 0.45) - (α - 1)); + } + + return 4.5 * val; + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/gam-a98rgb.ts b/packages/color-helpers/src/conversions/gam-a98rgb.ts new file mode 100644 index 000000000..9981f9d53 --- /dev/null +++ b/packages/color-helpers/src/conversions/gam-a98rgb.ts @@ -0,0 +1,16 @@ +/** + * Convert an array of linear-light a98-rgb in the range 0.0-1.0 + * to gamma corrected form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function gam_a98rgb(RGB: Color): Color { + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + return sign * Math.pow(abs, 256 / 563); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/gam-p3.ts b/packages/color-helpers/src/conversions/gam-p3.ts new file mode 100644 index 000000000..8eaf70671 --- /dev/null +++ b/packages/color-helpers/src/conversions/gam-p3.ts @@ -0,0 +1,13 @@ +import { gam_sRGB } from 'conversions/gam-srgb'; + +/** + * Convert an array of linear-light display-p3 RGB in the range 0.0-1.0 + * to gamma corrected form + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function gam_P3(RGB: Color): Color { + return gam_sRGB(RGB); // same as sRGB +} diff --git a/packages/color-helpers/src/conversions/gam-pro-photo.ts b/packages/color-helpers/src/conversions/gam-pro-photo.ts new file mode 100644 index 000000000..0f00a0806 --- /dev/null +++ b/packages/color-helpers/src/conversions/gam-pro-photo.ts @@ -0,0 +1,24 @@ + +/** + * Convert an array of linear-light prophoto-rgb in the range 0.0-1.0 + * to gamma corrected form. + * Transfer curve is gamma 1.8 with a small linear portion. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function gam_ProPhoto(RGB: Color): Color { + // TODO for negative values, extend linear portion on reflection of axis, then add pow below that + const Et = 1 / 512; + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs >= Et) { + return sign * Math.pow(abs, 1 / 1.8); + } + + return 16 * val; + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/gam-srgb.ts b/packages/color-helpers/src/conversions/gam-srgb.ts new file mode 100644 index 000000000..150de0bd3 --- /dev/null +++ b/packages/color-helpers/src/conversions/gam-srgb.ts @@ -0,0 +1,24 @@ +/** + * Convert an array of linear-light sRGB values in the range 0.0-1.0 to gamma corrected form + * Extended transfer function: + * For negative values, linear portion extends on reflection + * of axis, then uses reflected pow below that + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */ +export function gam_sRGB(RGB: Color): Color { + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs > 0.0031308) { + return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055); + } + + return 12.92 * val; + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/hsl-to-srgb.ts b/packages/color-helpers/src/conversions/hsl-to-srgb.ts new file mode 100644 index 000000000..a7eadc5dd --- /dev/null +++ b/packages/color-helpers/src/conversions/hsl-to-srgb.ts @@ -0,0 +1,34 @@ +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} sat - Saturation as percentage 0..100 + * @param {number} light - Lightness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js + */ +export function HSL_to_sRGB(HSL: Color) { + let hue = HSL[0]; + let sat = HSL[1]; + let light = HSL[2]; + + hue = hue % 360; + + if (hue < 0) { + hue += 360; + } + + sat /= 100; + light /= 100; + + function f(n) { + const k = (n + hue / 30) % 12; + const a = sat * Math.min(light, 1 - light); + return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); + } + + return [f(0), f(8), f(4)]; +} diff --git a/packages/color-helpers/src/conversions/hue-to-rgb.ts b/packages/color-helpers/src/conversions/hue-to-rgb.ts new file mode 100644 index 000000000..b1cc563d3 --- /dev/null +++ b/packages/color-helpers/src/conversions/hue-to-rgb.ts @@ -0,0 +1,25 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function hueToRGB(t1: number, t2: number, hue: number): number { + if (hue < 0) { + hue += 6; + } + if (hue >= 6) { + hue -= 6; + } + + if (hue < 1) { + return (t2 - t1) * hue + t1; + } else if (hue < 3) { + return t2; + } else if (hue < 4) { + return (t2 - t1) * (4 - hue) + t1; + } else { + return t1; + } +} diff --git a/packages/color-helpers/src/conversions/hwb-to-srgb.ts b/packages/color-helpers/src/conversions/hwb-to-srgb.ts new file mode 100644 index 000000000..b1bd64e91 --- /dev/null +++ b/packages/color-helpers/src/conversions/hwb-to-srgb.ts @@ -0,0 +1,34 @@ +import { HSL_to_sRGB } from './hsl-to-srgb'; + +/** + * @param {number} hue - Hue as degrees 0..360 + * @param {number} white - Whiteness as percentage 0..100 + * @param {number} black - Blackness as percentage 0..100 + * @return {number[]} Array of RGB components 0..1 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js + */ +export function HWB_to_sRGB(HWB: Color) { + const hue = HWB[0]; + let white = HWB[1]; + let black = HWB[2]; + + white /= 100; + black /= 100; + if (white + black >= 1) { + const gray = white / (white + black); + return [gray, gray, gray]; + } + + const rgb = HSL_to_sRGB([hue, 100, 50]); + for (let i = 0; i < 3; i++) { + rgb[i] *= (1 - white - black); + rgb[i] += white; + } + + return rgb; +} diff --git a/packages/color-helpers/src/conversions/index.ts b/packages/color-helpers/src/conversions/index.ts new file mode 100644 index 000000000..539f7ab8f --- /dev/null +++ b/packages/color-helpers/src/conversions/index.ts @@ -0,0 +1,58 @@ +export * from './a98-rgb-to-srgb'; +export * from './cie-xyz-50-to-srgb'; +export * from './cie-xyz-65-to-srgb'; +export * from './constants'; +export * from './d50-to-d65'; +export * from './d65-to-d50'; +export * from './gam-2020'; +export * from './gam-a98rgb'; +export * from './gam-p3'; +export * from './gam-pro-photo'; +export * from './gam-srgb'; +export * from './hsl-to-srgb'; +export * from './hue-to-rgb'; +export * from './hwb-to-srgb'; +export * from './lab-to-lch'; +export * from './lab-to-p3'; +export * from './lab-to-srgb'; +export * from './lab-to-xyz'; +export * from './lch-to-lab'; +export * from './lch-to-p3'; +export * from './lch-to-rec2020'; +export * from './lch-to-srgb'; +export * from './lin-2020'; +export * from './lin-2020-to-xyz'; +export * from './lin-a98rgb'; +export * from './lin-a98rgb-to-xyz'; +export * from './lin-p3'; +export * from './lin-p3-to-xyz'; +export * from './lin-pro-photo'; +export * from './lin-pro-photo-to-xyz'; +export * from './lin-srgb'; +export * from './lin-srgb-to-xyz'; +export * from './naive-cmyk-to-srgb'; +export * from './oklab-to-oklch'; +export * from './oklab-to-p3'; +export * from './oklab-to-srgb'; +export * from './oklab-to-xyz'; +export * from './oklch-to-oklab'; +export * from './oklch-to-p3'; +export * from './oklch-to-srgb'; +export * from './p3-to-lch'; +export * from './p3-to-srgb'; +export * from './pro-photo-rgb-to-srgb'; +export * from './rec2020-to-lch'; +export * from './rec2020-to-srgb'; +export * from './srgb-linear-to-srgb'; +export * from './srgb-to-lch'; +export * from './srgb-to-luminance'; +export * from './srgb-to-srgb'; +export * from './xyz-to-lab'; +export * from './xyz-to-lin-2020'; +export * from './xyz-to-lin-a98rgb'; +export * from './xyz-to-lin-p3'; +export * from './xyz-to-lin-pro-photo'; +export * from './xyz-to-lin-srgb'; +export * from './xyz-to-oklab'; +export * from './xyz-to-uv'; +export * from './xyz-to-xy'; diff --git a/packages/color-helpers/src/conversions/lab-to-lch.ts b/packages/color-helpers/src/conversions/lab-to-lch.ts new file mode 100644 index 000000000..2fb0c496c --- /dev/null +++ b/packages/color-helpers/src/conversions/lab-to-lch.ts @@ -0,0 +1,14 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function Lab_to_LCH(Lab: Color): Color { + // Convert to polar form + const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI; + return [ + Lab[0], // L is still L + Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma + hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) + ]; +} diff --git a/plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts b/packages/color-helpers/src/conversions/lab-to-p3.ts similarity index 57% rename from plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts rename to packages/color-helpers/src/conversions/lab-to-p3.ts index 848c64964..bc3b5f0be 100644 --- a/plugins/postcss-lab-function/src/convert-lab-to-display-p3.ts +++ b/packages/color-helpers/src/conversions/lab-to-p3.ts @@ -1,9 +1,18 @@ -import { D50_to_D65, gam_P3, Lab_to_XYZ, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; +import { Lab_to_XYZ } from 'conversions/lab-to-xyz'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3'; +import { gam_P3 } from 'conversions/gam-p3'; +import { clip } from 'utils/clip'; +import { inGamut } from 'utils/in-gamut'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_P3 } from 'conversions/lin-p3'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; -type color = [number, number, number]; - -export function labToDisplayP3(labRaw: color): [color, boolean] { +export function Lab_to_P3(labRaw: Color): [Color, boolean] { const [labLRaw, labARaw, labBRaw] = labRaw; const labL = Math.max( @@ -29,22 +38,22 @@ export function labToDisplayP3(labRaw: color): [color, boolean] { const lab = [labL, labA, labB]; - let conversion = lab as color; + let conversion = lab as Color; // https://drafts.csswg.org/css-color-4/#oklab-lab-to-predefined // 1. Convert Lab to(D50 - adapted) XYZ conversion = Lab_to_XYZ(conversion); - let oklch = conversion.slice() as color; + let oklch = conversion.slice() as Color; oklch = D50_to_D65(oklch); oklch = XYZ_to_OKLab(oklch); oklch = OKLab_to_OKLCH(oklch); if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; + oklch = [0, 0, 0] as Color; } if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; + oklch = [1, 0, 0] as Color; } // 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step. @@ -58,12 +67,12 @@ export function labToDisplayP3(labRaw: color): [color, boolean] { return [clip(conversion), true]; } - return [mapGamut(oklch, (x: color) => { + return [mapGamut(oklch, (x: Color) => { x = OKLCH_to_OKLab(x); x = OKLab_to_XYZ(x); x = XYZ_to_lin_P3(x); return gam_P3(x); - }, (x: color) => { + }, (x: Color) => { x = lin_P3(x); x = lin_P3_to_XYZ(x); x = XYZ_to_OKLab(x); diff --git a/plugins/postcss-lab-function/src/convert-lab-to-srgb.ts b/packages/color-helpers/src/conversions/lab-to-srgb.ts similarity index 58% rename from plugins/postcss-lab-function/src/convert-lab-to-srgb.ts rename to packages/color-helpers/src/conversions/lab-to-srgb.ts index b19cefa55..739346759 100644 --- a/plugins/postcss-lab-function/src/convert-lab-to-srgb.ts +++ b/packages/color-helpers/src/conversions/lab-to-srgb.ts @@ -1,9 +1,18 @@ -import { D50_to_D65, gam_sRGB, Lab_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; +import { Lab_to_XYZ } from 'conversions/lab-to-xyz'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; -type color = [number, number, number]; - -export function labToSRgb(labRaw: color): color { +export function Lab_to_sRGB(labRaw: Color): Color { const [labLRaw, labARaw, labBRaw] = labRaw; const labL = Math.max( @@ -29,22 +38,22 @@ export function labToSRgb(labRaw: color): color { const lab = [labL, labA, labB]; - let conversion = lab as color; + let conversion = lab as Color; // https://drafts.csswg.org/css-color-4/#oklab-lab-to-predefined // 1. Convert Lab to(D50 - adapted) XYZ conversion = Lab_to_XYZ(conversion); - let oklch = conversion.slice() as color; + let oklch = conversion.slice() as Color; oklch = D50_to_D65(oklch); oklch = XYZ_to_OKLab(oklch); oklch = OKLab_to_OKLCH(oklch); if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; + oklch = [0, 0, 0] as Color; } if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; + oklch = [1, 0, 0] as Color; } // 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step. @@ -57,20 +66,20 @@ export function labToSRgb(labRaw: color): color { if (inGamut(conversion)) { return clip(conversion).map((x) => { return Math.round(x * 255); - }) as color; + }) as Color; } - return mapGamut(oklch, (x: color) => { + return mapGamut(oklch, (x: Color) => { x = OKLCH_to_OKLab(x); x = OKLab_to_XYZ(x); x = XYZ_to_lin_sRGB(x); return gam_sRGB(x); - }, (x: color) => { + }, (x: Color) => { x = lin_sRGB(x); x = lin_sRGB_to_XYZ(x); x = XYZ_to_OKLab(x); return OKLab_to_OKLCH(x); }).map((x) => { return Math.round(x * 255); - }) as color; + }) as Color; } diff --git a/packages/color-helpers/src/conversions/lab-to-xyz.ts b/packages/color-helpers/src/conversions/lab-to-xyz.ts new file mode 100644 index 000000000..f040e3bb6 --- /dev/null +++ b/packages/color-helpers/src/conversions/lab-to-xyz.ts @@ -0,0 +1,30 @@ +/** + * Convert Lab to D50-adapted XYZ + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +import { D50 } from 'conversions/constants'; + +export function Lab_to_XYZ(Lab: Color): Color { + const κ = 24389 / 27; // 29^3/3^3 + const ε = 216 / 24389; // 6^3/29^3 + const f = []; + + // compute f, starting with the luminance-related term + f[1] = (Lab[0] + 16) / 116; + f[0] = Lab[1] / 500 + f[1]; + f[2] = f[1] - Lab[2] / 200; + + // compute xyz + const xyz = [ + Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ, + Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ, + Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ, + ]; + + // Compute XYZ by scaling xyz by reference white + return xyz.map((value, i) => value * D50[i]) as Color; +} diff --git a/packages/color-helpers/src/conversions/lch-to-lab.ts b/packages/color-helpers/src/conversions/lch-to-lab.ts new file mode 100644 index 000000000..9c97e5346 --- /dev/null +++ b/packages/color-helpers/src/conversions/lch-to-lab.ts @@ -0,0 +1,13 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function LCH_to_Lab(LCH: Color): Color { + // Convert from polar form + return [ + LCH[0], // L is still L + LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a + LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b + ]; +} diff --git a/plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts b/packages/color-helpers/src/conversions/lch-to-p3.ts similarity index 52% rename from plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts rename to packages/color-helpers/src/conversions/lch-to-p3.ts index b622a195e..9c32fddeb 100644 --- a/plugins/postcss-lab-function/src/convert-lch-to-display-p3.ts +++ b/packages/color-helpers/src/conversions/lch-to-p3.ts @@ -1,9 +1,19 @@ -import { D50_to_D65, gam_P3, Lab_to_XYZ, LCH_to_Lab, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; +import { gam_P3 } from 'conversions/gam-p3'; +import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { Lab_to_XYZ } from 'conversions/lab-to-xyz'; +import { LCH_to_Lab } from 'conversions/lch-to-lab'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_P3 } from 'conversions/lin-p3'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; -type color = [number, number, number]; - -export function lchToDisplayP3(lchRaw: color): [color, boolean] { +export function LCH_to_P3(lchRaw: Color): [Color, boolean] { const [lchLRaw, lchCRaw, lchHRaw] = lchRaw; const lchL = Math.max( @@ -11,25 +21,23 @@ export function lchToDisplayP3(lchRaw: color): [color, boolean] { 0, ); - const lch = [lchL, lchCRaw, lchHRaw % 360] as color; - - let conversion = lch; + let conversion = [ lchL, lchCRaw, lchHRaw % 360 ] as Color; conversion = LCH_to_Lab(conversion); // https://www.w3.org/TR/css-color-4/#oklab-lab-to-predefined // 1. Convert Lab to(D50 - adapted) XYZ conversion = Lab_to_XYZ(conversion); - let oklch = conversion.slice() as color; + let oklch = conversion.slice() as Color; oklch = D50_to_D65(oklch); oklch = XYZ_to_OKLab(oklch); oklch = OKLab_to_OKLCH(oklch); if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; + oklch = [0, 0, 0] as Color; } if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; + oklch = [1, 0, 0] as Color; } // 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step. @@ -43,12 +51,12 @@ export function lchToDisplayP3(lchRaw: color): [color, boolean] { return [clip(conversion), true]; } - return [mapGamut(oklch, (x: color) => { + return [mapGamut(oklch, (x: Color) => { x = OKLCH_to_OKLab(x); x = OKLab_to_XYZ(x); x = XYZ_to_lin_P3(x); return gam_P3(x); - }, (x: color) => { + }, (x: Color) => { x = lin_P3(x); x = lin_P3_to_XYZ(x); x = XYZ_to_OKLab(x); diff --git a/packages/color-helpers/src/conversions/lch-to-rec2020.ts b/packages/color-helpers/src/conversions/lch-to-rec2020.ts new file mode 100644 index 000000000..4b6efe771 --- /dev/null +++ b/packages/color-helpers/src/conversions/lch-to-rec2020.ts @@ -0,0 +1,22 @@ +import { gam_2020 } from 'conversions/gam-2020'; +import { XYZ_to_lin_2020 } from 'conversions/xyz-to-lin-2020'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { Lab_to_XYZ } from 'conversions/lab-to-xyz'; +import { LCH_to_Lab } from 'conversions/lch-to-lab'; + +/** + * Convert an array of CIE LCH values to CIE Lab, and then to XYZ, adapt from + * D50 to D65, then convert XYZ to linear-light rec.2020 and finally to gamma + * corrected rec.2020 for in-gamut colors, components are in the 0.0 to 1.0 + * range out of gamut colors may have negative components or components greater + * than 1.0 so check for that :) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function LCH_to_rec2020(LCH: Color): Color { + return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); +} diff --git a/plugins/postcss-lab-function/src/convert-lch-to-srgb.ts b/packages/color-helpers/src/conversions/lch-to-srgb.ts similarity index 54% rename from plugins/postcss-lab-function/src/convert-lch-to-srgb.ts rename to packages/color-helpers/src/conversions/lch-to-srgb.ts index 0648f6506..1c391b7a2 100644 --- a/plugins/postcss-lab-function/src/convert-lch-to-srgb.ts +++ b/packages/color-helpers/src/conversions/lch-to-srgb.ts @@ -1,9 +1,19 @@ -import { D50_to_D65, gam_sRGB, Lab_to_XYZ, LCH_to_Lab, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { Lab_to_XYZ } from 'conversions/lab-to-xyz'; +import { LCH_to_Lab } from 'conversions/lch-to-lab'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; -type color = [number, number, number]; - -export function lchToSRgb(lchRaw: color): color { +export function LCH_to_sRGB(lchRaw: Color): Color { const [lchLRaw, lchCRaw, lchHRaw] = lchRaw; const lchL = Math.max( @@ -11,7 +21,7 @@ export function lchToSRgb(lchRaw: color): color { 0, ); - const lch = [lchL, lchCRaw, lchHRaw % 360] as color; + const lch = [lchL, lchCRaw, lchHRaw % 360] as Color; let conversion = lch; conversion = LCH_to_Lab(conversion); @@ -20,16 +30,16 @@ export function lchToSRgb(lchRaw: color): color { // 1. Convert Lab to(D50 - adapted) XYZ conversion = Lab_to_XYZ(conversion); - let oklch = conversion.slice() as color; + let oklch = conversion.slice() as Color; oklch = D50_to_D65(oklch); oklch = XYZ_to_OKLab(oklch); oklch = OKLab_to_OKLCH(oklch); if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; + oklch = [0, 0, 0] as Color; } if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; + oklch = [1, 0, 0] as Color; } // 2. If needed, convert from a D50 whitepoint(used by Lab) to the D65 whitepoint used in sRGB and most other RGB spaces, with the Bradford transform.prophoto - rgb' does not require this step. @@ -42,20 +52,20 @@ export function lchToSRgb(lchRaw: color): color { if (inGamut(conversion)) { return clip(conversion).map((x) => { return Math.round(x * 255); - }) as color; + }) as Color; } - return mapGamut(oklch, (x: color) => { + return mapGamut(oklch, (x: Color) => { x = OKLCH_to_OKLab(x); x = OKLab_to_XYZ(x); x = XYZ_to_lin_sRGB(x); return gam_sRGB(x); - }, (x: color) => { + }, (x: Color) => { x = lin_sRGB(x); x = lin_sRGB_to_XYZ(x); x = XYZ_to_OKLab(x); return OKLab_to_OKLCH(x); }).map((x) => { return Math.round(x * 255); - }) as color; + }) as Color; } diff --git a/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts b/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts new file mode 100644 index 000000000..4e03581fe --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-2020-to-xyz.ts @@ -0,0 +1,22 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert an array of linear-light rec2020 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export function lin_2020_to_XYZ(rgb: Color): Color { + const M = [ + [63426534 / 99577255, 20160776 / 139408157, 47086771 / 278816314], + [26158966 / 99577255, 472592308 / 697040785, 8267143 / 139408157], + [0 / 1, 19567812 / 697040785, 295819943 / 278816314], + ]; + // 0 is actually calculated as 4.994106574466076e-17 + + return multiplyMatrices(M, rgb) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-2020.ts b/packages/color-helpers/src/conversions/lin-2020.ts new file mode 100644 index 000000000..614f1e9f0 --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-2020.ts @@ -0,0 +1,24 @@ +/** + * Convert an array of rec2020 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * ITU-R BT.2020-2 p.4 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function lin_2020(RGB: Color): Color { + const α = 1.09929682680944; + const β = 0.018053968510807; + + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs < β * 4.5) { + return val / 4.5; + } + + return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts b/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts new file mode 100644 index 000000000..4954bb855 --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-a98rgb-to-xyz.ts @@ -0,0 +1,27 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert an array of linear-light a98-rgb values to CIE XYZ + * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * has greater numerical precision than section 4.3.5.3 of + * https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * but the values below were calculated from first principles + * from the chromaticity coordinates of R G B W + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + * @see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/matrixmaker.html + */ +export function lin_a98rgb_to_XYZ(rgb: Color): Color { + const M = [ + [573536 / 994567, 263643 / 1420810, 187206 / 994567], + [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835], + [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835], + ]; + + return multiplyMatrices(M, rgb) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-a98rgb.ts b/packages/color-helpers/src/conversions/lin-a98rgb.ts new file mode 100644 index 000000000..7b64e4df0 --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-a98rgb.ts @@ -0,0 +1,16 @@ +/** + * Convert an array of a98-rgb values in the range 0.0 - 1.0 + * to linear light (un-companded) form. Negative values are also now accepted + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function lin_a98rgb(RGB: Color): Color { + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + return sign * Math.pow(abs, 563 / 256); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts b/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts new file mode 100644 index 000000000..4e298155e --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-p3-to-xyz.ts @@ -0,0 +1,21 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert an array of linear-light display-p3 values to CIE XYZ + * using D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export function lin_P3_to_XYZ(rgb: Color): Color { + const M = [ + [608311 / 1250200, 189793 / 714400, 198249 / 1000160], + [35783 / 156275, 247089 / 357200, 198249 / 2500400], + [0 / 1, 32229 / 714400, 5220557 / 5000800], + ]; + + return multiplyMatrices(M, rgb) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-p3.ts b/packages/color-helpers/src/conversions/lin-p3.ts new file mode 100644 index 000000000..95193445e --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-p3.ts @@ -0,0 +1,13 @@ +import { lin_sRGB } from 'conversions/lin-srgb'; + +/** + * Convert an array of display-p3 RGB values in the range 0.0 - 1.0 + * to linear light (un-companded) form. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function lin_P3(RGB: Color): Color { + return lin_sRGB(RGB); // same as sRGB +} diff --git a/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts b/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts new file mode 100644 index 000000000..4639d6a7b --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-pro-photo-to-xyz.ts @@ -0,0 +1,21 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert an array of linear-light prophoto-rgb values to CIE XYZ + * using D50 (so no chromatic adaptation needed afterwards) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export function lin_ProPhoto_to_XYZ(rgb: Color): Color { + const M = [ + [0.7977604896723027, 0.13518583717574031, 0.0313493495815248], + [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902], + [0.0, 0.0, 0.8251046025104601], + ]; + + return multiplyMatrices(M, rgb) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-pro-photo.ts b/packages/color-helpers/src/conversions/lin-pro-photo.ts new file mode 100644 index 000000000..de338a0d3 --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-pro-photo.ts @@ -0,0 +1,22 @@ +/** + * Convert an array of prophoto-rgb values where in-gamut Colors are in the + * range [0.0 - 1.0] to linear light (un-companded) form. Transfer curve is + * gamma 1.8 with a small linear portion. Extended transfer function + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function lin_ProPhoto(RGB: Color): Color { + const Et2 = 16 / 512; + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs <= Et2) { + return val / 16; + } + + return sign * Math.pow(abs, 1.8); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts b/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts new file mode 100644 index 000000000..aa0b460bc --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-srgb-to-xyz.ts @@ -0,0 +1,18 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert an array of linear-light sRGB values to CIE XYZ + * using sRGB's own white, D65 (no chromatic adaptation) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function lin_sRGB_to_XYZ(rgb: Color): Color { + const M = [ + [506752 / 1228815, 87881 / 245763, 12673 / 70218], + [87098 / 409605, 175762 / 245763, 12673 / 175545], + [7918 / 409605, 87881 / 737289, 1001167 / 1053270], + ]; + return multiplyMatrices(M, rgb) as Color; +} diff --git a/packages/color-helpers/src/conversions/lin-srgb.ts b/packages/color-helpers/src/conversions/lin-srgb.ts new file mode 100644 index 000000000..f55a29620 --- /dev/null +++ b/packages/color-helpers/src/conversions/lin-srgb.ts @@ -0,0 +1,25 @@ +/** + * Convert an array of of sRGB values where in-gamut values are in the range + * [0 - 1] to linear light (un-companded) form. + * Extended transfer function: + * For negative values, linear portion is extended on reflection of axis, + * then reflected power function is used. + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://en.wikipedia.org/wiki/SRGB + */ +export function lin_sRGB(RGB: Color): Color { + return RGB.map(function (val) { + const sign = val < 0 ? -1 : 1; + const abs = Math.abs(val); + + if (abs < 0.04045) { + return val / 12.92; + } + + return sign * (Math.pow((abs + 0.055) / 1.055, 2.4)); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts b/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts new file mode 100644 index 000000000..712669915 --- /dev/null +++ b/packages/color-helpers/src/conversions/naive-cmyk-to-srgb.ts @@ -0,0 +1,21 @@ +/** + * CMYK is an array of four values in the range [0.0, 1.0] the output is an + * array of [RGB] also in the [0.0, 1.0] range because the naive algorithm + * does not generate out of gamut colors neither does it generate accurate + * simulations of practical CMYK colors + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): Color { + const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3]; + + const red = 1 - Math.min(1, cyan * (1 - black) + black); + const green = 1 - Math.min(1, magenta * (1 - black) + black); + const blue = 1 - Math.min(1, yellow * (1 - black) + black); + + return [red, green, blue]; +} diff --git a/packages/color-helpers/src/conversions/oklab-to-oklch.ts b/packages/color-helpers/src/conversions/oklab-to-oklch.ts new file mode 100644 index 000000000..8cc976172 --- /dev/null +++ b/packages/color-helpers/src/conversions/oklab-to-oklch.ts @@ -0,0 +1,15 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */ +export function OKLab_to_OKLCH(OKLab: Color): Color { + const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI; + return [ + OKLab[0], // L is still L + Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma + hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) + ]; +} diff --git a/packages/color-helpers/src/conversions/oklab-to-p3.ts b/packages/color-helpers/src/conversions/oklab-to-p3.ts new file mode 100644 index 000000000..db8eb42c6 --- /dev/null +++ b/packages/color-helpers/src/conversions/oklab-to-p3.ts @@ -0,0 +1,52 @@ +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3'; +import { gam_P3 } from 'conversions/gam-p3'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { lin_P3 } from 'conversions/lin-p3'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; + +export function OKLab_to_P3(oklabRaw: Color): [Color, boolean] { + const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw; + + const oklabL = Math.max( + oklabLRaw, + 0, + ); + + const oklab = [oklabL, oklabARaw, oklabBRaw] as Color; + + let conversion = oklab as Color; + let oklch = OKLab_to_OKLCH(conversion); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + conversion = OKLab_to_XYZ(conversion); + conversion = XYZ_to_lin_P3(conversion); + conversion = gam_P3(conversion); + + if (inGamut(conversion)) { + return [clip(conversion), true]; + } + + return [mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_P3(x); + return gam_P3(x); + }, (x: Color) => { + x = lin_P3(x); + x = lin_P3_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }), false]; +} diff --git a/packages/color-helpers/src/conversions/oklab-to-srgb.ts b/packages/color-helpers/src/conversions/oklab-to-srgb.ts new file mode 100644 index 000000000..ac56839ab --- /dev/null +++ b/packages/color-helpers/src/conversions/oklab-to-srgb.ts @@ -0,0 +1,56 @@ +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; + +export function OKLab_to_sRGB(oklabRaw: Color): Color { + const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw; + + const oklabL = Math.max( + oklabLRaw, + 0, + ); + + const oklab = [oklabL, oklabARaw, oklabBRaw] as Color; + + let conversion = oklab as Color; + let oklch = OKLab_to_OKLCH(conversion); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + conversion = OKLab_to_XYZ(conversion); + conversion = XYZ_to_lin_sRGB(conversion); + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion).map((x) => { + return Math.round(x * 255); + }) as Color; + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }).map((x) => { + return Math.round(x * 255); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/oklab-to-xyz.ts b/packages/color-helpers/src/conversions/oklab-to-xyz.ts new file mode 100644 index 000000000..2da348462 --- /dev/null +++ b/packages/color-helpers/src/conversions/oklab-to-xyz.ts @@ -0,0 +1,27 @@ +/** + * Given OKLab, convert to XYZ relative to D65 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +export function OKLab_to_XYZ(OKLab: Color): Color { + const LMStoXYZ = [ + [1.2268798733741557, -0.5578149965554813, 0.28139105017721583], + [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701], + [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418], + ]; + const OKLabtoLMS = [ + [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339], + [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402], + [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399], + ]; + + const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as Color; + + return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as Color; +} diff --git a/packages/color-helpers/src/conversions/oklch-to-oklab.ts b/packages/color-helpers/src/conversions/oklch-to-oklab.ts new file mode 100644 index 000000000..91b87cb4f --- /dev/null +++ b/packages/color-helpers/src/conversions/oklch-to-oklab.ts @@ -0,0 +1,15 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js + */ + +export function OKLCH_to_OKLab(OKLCH: Color): Color { + return [ + OKLCH[0], // L is still L + OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a + OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b + ]; +} diff --git a/packages/color-helpers/src/conversions/oklch-to-p3.ts b/packages/color-helpers/src/conversions/oklch-to-p3.ts new file mode 100644 index 000000000..54775db91 --- /dev/null +++ b/packages/color-helpers/src/conversions/oklch-to-p3.ts @@ -0,0 +1,52 @@ +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { XYZ_to_lin_P3 } from 'conversions/xyz-to-lin-p3'; +import { gam_P3 } from 'conversions/gam-p3'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { lin_P3 } from 'conversions/lin-p3'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; + +export function OKLCH_to_P3(oklchRaw: Color): [Color, boolean] { + const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw; + + const oklchL = Math.max( + oklchLRaw, + 0, + ); + + const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as Color; + + let conversion = oklch as Color; + if (conversion[0] < 0.000001) { + conversion = [0, 0, 0] as Color; + } + + if (conversion[0] > 0.999999) { + conversion = [1, 0, 0] as Color; + } + + conversion = OKLCH_to_OKLab(conversion); + conversion = OKLab_to_XYZ(conversion); + conversion = XYZ_to_lin_P3(conversion); + conversion = gam_P3(conversion); + + if (inGamut(conversion)) { + return [clip(conversion), true]; + } + + return [mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_P3(x); + return gam_P3(x); + }, (x: Color) => { + x = lin_P3(x); + x = lin_P3_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }), false]; +} diff --git a/packages/color-helpers/src/conversions/oklch-to-srgb.ts b/packages/color-helpers/src/conversions/oklch-to-srgb.ts new file mode 100644 index 000000000..98cd3dd01 --- /dev/null +++ b/packages/color-helpers/src/conversions/oklch-to-srgb.ts @@ -0,0 +1,56 @@ +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; + +export function OKLCH_to_sRGB(oklchRaw: Color): Color { + const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw; + + const oklchL = Math.max( + oklchLRaw, + 0, + ); + + const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as Color; + + let conversion = oklch as Color; + if (conversion[0] < 0.000001) { + conversion = [0, 0, 0] as Color; + } + + if (conversion[0] > 0.999999) { + conversion = [1, 0, 0] as Color; + } + + conversion = OKLCH_to_OKLab(conversion); + conversion = OKLab_to_XYZ(conversion); + conversion = XYZ_to_lin_sRGB(conversion); + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion).map((x) => { + return Math.round(x * 255); + }) as Color; + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }).map((x) => { + return Math.round(x * 255); + }) as Color; +} diff --git a/packages/color-helpers/src/conversions/p3-to-lch.ts b/packages/color-helpers/src/conversions/p3-to-lch.ts new file mode 100644 index 000000000..78b0ffef6 --- /dev/null +++ b/packages/color-helpers/src/conversions/p3-to-lch.ts @@ -0,0 +1,20 @@ +import { Lab_to_LCH } from 'conversions/lab-to-lch'; +import { XYZ_to_Lab } from 'conversions/xyz-to-lab'; +import { D65_to_D50 } from 'conversions/d65-to-d50'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; +import { lin_P3 } from 'conversions/lin-p3'; + +/** + * Convert an array of gamma-corrected display-p3 values in the 0.0 to 1.0 + * range to linear-light display-p3, then to CIE XYZ, then adapt from D65 + * to D50, then convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function P3_to_LCH(RGB: Color): Color { + return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB))))); +} diff --git a/packages/color-helpers/src/conversions/p3-to-srgb.ts b/packages/color-helpers/src/conversions/p3-to-srgb.ts new file mode 100644 index 000000000..967b4090f --- /dev/null +++ b/packages/color-helpers/src/conversions/p3-to-srgb.ts @@ -0,0 +1,54 @@ +import { lin_P3 } from 'conversions/lin-p3'; +import { lin_P3_to_XYZ } from 'conversions/lin-p3-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; + +export function p3_to_sRGB(displayP3: Color): Color { + let conversion = displayP3.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_P3(conversion); + conversion = lin_P3_to_XYZ(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts b/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts new file mode 100644 index 000000000..2b2cefab4 --- /dev/null +++ b/packages/color-helpers/src/conversions/pro-photo-rgb-to-srgb.ts @@ -0,0 +1,56 @@ +import { lin_ProPhoto } from 'conversions/lin-pro-photo'; +import { lin_ProPhoto_to_XYZ } from 'conversions/lin-pro-photo-to-xyz'; +import { D50_to_D65 } from 'conversions/d50-to-d65'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { mapGamut } from 'calculations/map-gamut'; + +export function proPhoto_RGB_to_sRGB(proPhoto: Color): Color { + let conversion = proPhoto.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_ProPhoto(conversion); + conversion = lin_ProPhoto_to_XYZ(conversion); + conversion = D50_to_D65(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/rec2020-to-lch.ts b/packages/color-helpers/src/conversions/rec2020-to-lch.ts new file mode 100644 index 000000000..830dd43f6 --- /dev/null +++ b/packages/color-helpers/src/conversions/rec2020-to-lch.ts @@ -0,0 +1,20 @@ +import { Lab_to_LCH } from 'conversions/lab-to-lch'; +import { XYZ_to_Lab } from 'conversions/xyz-to-lab'; +import { D65_to_D50 } from 'conversions/d65-to-d50'; +import { lin_2020_to_XYZ } from 'conversions/lin-2020-to-xyz'; +import { lin_2020 } from 'conversions/lin-2020'; + +/** + * Convert an array of gamma-corrected rec.2020 values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function rec_2020_to_LCH(RGB: Color): Color { + return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB))))); +} diff --git a/packages/color-helpers/src/conversions/rec2020-to-srgb.ts b/packages/color-helpers/src/conversions/rec2020-to-srgb.ts new file mode 100644 index 000000000..109239d23 --- /dev/null +++ b/packages/color-helpers/src/conversions/rec2020-to-srgb.ts @@ -0,0 +1,54 @@ +import { lin_2020 } from 'conversions/lin-2020'; +import { lin_2020_to_XYZ } from 'conversions/lin-2020-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; + +export function rec_2020_to_sRGB(rec: Color): Color { + let conversion = rec.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_2020(conversion); + conversion = lin_2020_to_XYZ(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts b/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts new file mode 100644 index 000000000..cb5d63b64 --- /dev/null +++ b/packages/color-helpers/src/conversions/srgb-linear-to-srgb.ts @@ -0,0 +1,51 @@ +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; + +export function sRGB_linear_to_sRGB(linearSRgb: Color): Color { + let conversion = linearSRgb.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_sRGB_to_XYZ(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/srgb-to-lch.ts b/packages/color-helpers/src/conversions/srgb-to-lch.ts new file mode 100644 index 000000000..d2fd53c4d --- /dev/null +++ b/packages/color-helpers/src/conversions/srgb-to-lch.ts @@ -0,0 +1,20 @@ +import { Lab_to_LCH } from 'conversions/lab-to-lch'; +import { XYZ_to_Lab } from 'conversions/xyz-to-lab'; +import { D65_to_D50 } from 'conversions/d65-to-d50'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; + +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range to + * linear-light sRGB, then to CIE XYZ, then adapt from D65 to D50, then + * convert XYZ to CIE Lab and finally, convert to CIE LCH + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function sRGB_to_LCH(RGB: Color): Color { + return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB))))); +} diff --git a/packages/color-helpers/src/conversions/srgb-to-luminance.ts b/packages/color-helpers/src/conversions/srgb-to-luminance.ts new file mode 100644 index 000000000..6ddb326f1 --- /dev/null +++ b/packages/color-helpers/src/conversions/srgb-to-luminance.ts @@ -0,0 +1,17 @@ +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { lin_sRGB } from 'conversions/lin-srgb'; + +/** + * Convert an array of gamma-corrected sRGB values in the 0.0 to 1.0 range + * to linear-light sRGB, then to CIE XYZ and return luminance (the Y value) + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function sRGB_to_luminance(RGB: Color): number { + const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB)); + return XYZ[1]; +} diff --git a/packages/color-helpers/src/conversions/srgb-to-srgb.ts b/packages/color-helpers/src/conversions/srgb-to-srgb.ts new file mode 100644 index 000000000..7cb479f5f --- /dev/null +++ b/packages/color-helpers/src/conversions/srgb-to-srgb.ts @@ -0,0 +1,52 @@ +import { lin_sRGB } from 'conversions/lin-srgb'; +import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz'; +import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab'; +import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch'; +import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb'; +import { gam_sRGB } from 'conversions/gam-srgb'; +import { inGamut } from 'utils/in-gamut'; +import { clip } from 'utils/clip'; +import { mapGamut } from 'calculations/map-gamut'; +import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab'; +import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz'; + +export function sRGB_to_sRGB(sRgb: Color): Color { + let conversion = sRgb.slice() as Color; + + // https://www.w3.org/TR/css-color-4/#predefined-to-predefined + // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab + conversion = lin_sRGB(conversion); + conversion = lin_sRGB_to_XYZ(conversion); + + let oklch = conversion.slice() as Color; + oklch = XYZ_to_OKLab(oklch); + oklch = OKLab_to_OKLCH(oklch); + if (oklch[0] < 0.000001) { + oklch = [0, 0, 0] as Color; + } + + if (oklch[0] > 0.999999) { + oklch = [1, 0, 0] as Color; + } + + // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB + conversion = XYZ_to_lin_sRGB(conversion); + // 4. Convert from linear - light RGB to RGB(do gamma encoding) + conversion = gam_sRGB(conversion); + + if (inGamut(conversion)) { + return clip(conversion); + } + + return mapGamut(oklch, (x: Color) => { + x = OKLCH_to_OKLab(x); + x = OKLab_to_XYZ(x); + x = XYZ_to_lin_sRGB(x); + return gam_sRGB(x); + }, (x: Color) => { + x = lin_sRGB(x); + x = lin_sRGB_to_XYZ(x); + x = XYZ_to_OKLab(x); + return OKLab_to_OKLCH(x); + }); +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lab.ts b/packages/color-helpers/src/conversions/xyz-to-lab.ts new file mode 100644 index 000000000..fdbf1f449 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lab.ts @@ -0,0 +1,27 @@ +/** + * Assuming XYZ is relative to D50, convert to CIE Lab + * from CIE standard, which now defines these as a rational fraction + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +import { D50 } from 'conversions/constants'; + +export function XYZ_to_Lab(XYZ: Color): Color { + const ε = 216 / 24389; // 6^3/29^3 + const κ = 24389 / 27; // 29^3/3^3 + + // compute xyz, which is XYZ scaled relative to reference white + const xyz = XYZ.map((value, i) => value / D50[i]); + + // now compute f + const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116); + + return [ + (116 * f[1]) - 16, // L + 500 * (f[0] - f[1]), // a + 200 * (f[1] - f[2]), // b + ]; + // L in range [0,100]. For use in CSS, add a percent +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts b/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts new file mode 100644 index 000000000..5f2f92406 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lin-2020.ts @@ -0,0 +1,18 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert XYZ to linear-light rec2020 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function XYZ_to_lin_2020(XYZ: Color): Color { + const M = [ + [30757411 / 17917100, -6372589 / 17917100, -4539589 / 17917100], + [-19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200], + [792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts b/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts new file mode 100644 index 000000000..9ec1a0b59 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lin-a98rgb.ts @@ -0,0 +1,18 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert XYZ to linear-light a98-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function XYZ_to_lin_a98rgb(XYZ: Color): Color { + const M = [ + [1829569 / 896150, -506331 / 896150, -308931 / 896150], + [-851781 / 878810, 1648619 / 878810, 36519 / 878810], + [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts b/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts new file mode 100644 index 000000000..d6cc5193d --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lin-p3.ts @@ -0,0 +1,18 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert XYZ to linear-light P3 + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function XYZ_to_lin_P3(XYZ: Color): Color { + const M = [ + [446124 / 178915, -333277 / 357830, -72051 / 178915], + [-14852 / 17905, 63121 / 35810, 423 / 17905], + [11844 / 330415, -50337 / 660830, 316169 / 330415], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts b/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts new file mode 100644 index 000000000..facafc9bb --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lin-pro-photo.ts @@ -0,0 +1,20 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * Convert XYZ to linear-light prophoto-rgb + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +export function XYZ_to_lin_ProPhoto(XYZ: Color): Color { + const M = [ + [1.3457989731028281, -0.25558010007997534, -0.05110628506753401], + [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973], + [0.0, 0.0, 1.2119675456389454], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts b/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts new file mode 100644 index 000000000..be79af764 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-lin-srgb.ts @@ -0,0 +1,16 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function XYZ_to_lin_sRGB(XYZ: Color): Color { + const M = [ + [12831 / 3959, -329 / 214, -1974 / 3959], + [-851781 / 878810, 1648619 / 878810, 36519 / 878810], + [705 / 12673, -2585 / 12673, 705 / 667], + ]; + + return multiplyMatrices(M, XYZ) as Color; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-oklab.ts b/packages/color-helpers/src/conversions/xyz-to-oklab.ts new file mode 100644 index 000000000..52df715b3 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-oklab.ts @@ -0,0 +1,27 @@ +import { multiplyMatrices } from 'calculations/multiply-matrices'; + +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * XYZ <-> LMS matrices recalculated for consistent reference white + * @see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 + */ +export function XYZ_to_OKLab(XYZ: Color): Color { + // Given XYZ relative to D65, convert to OKLab + const XYZtoLMS = [ + [0.8190224432164319, 0.3619062562801221, -0.12887378261216414], + [0.0329836671980271, 0.9292868468965546, 0.03614466816999844], + [0.048177199566046255, 0.26423952494422764, 0.6335478258136937], + ]; + const LMStoOKLab = [ + [0.2104542553, 0.7936177850, -0.0040720468], + [1.9779984951, -2.4285922050, 0.4505937099], + [0.0259040371, 0.7827717662, -0.8086757660], + ]; + + const LMS = multiplyMatrices(XYZtoLMS, XYZ) as Color; + return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as Color; + // L in range [0,1]. For use in CSS, multiply by 100 and add a percent +} diff --git a/packages/color-helpers/src/conversions/xyz-to-uv.ts b/packages/color-helpers/src/conversions/xyz-to-uv.ts new file mode 100644 index 000000000..8e0e4fe15 --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-uv.ts @@ -0,0 +1,16 @@ +/** + * Convert an array of three XYZ values to u*,v* chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function XYZ_to_uv(XYZ: Color): [number, number] { + const X = XYZ[0]; + const Y = XYZ[1]; + const Z = XYZ[2]; + const denom = X + 15 * Y + 3 * Z; + return [4 * X / denom, 9 * Y / denom]; +} diff --git a/packages/color-helpers/src/conversions/xyz-to-xy.ts b/packages/color-helpers/src/conversions/xyz-to-xy.ts new file mode 100644 index 000000000..a64dd66ca --- /dev/null +++ b/packages/color-helpers/src/conversions/xyz-to-xy.ts @@ -0,0 +1,16 @@ +/** + * Convert an array of three XYZ values to x,y chromaticity coordinates + * + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + * + * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js + */ +export function XYZ_to_xy(XYZ: Color): [number, number] { + const X = XYZ[0]; + const Y = XYZ[1]; + const Z = XYZ[2]; + const sum = X + Y + Z; + return [X / sum, Y / sum]; +} diff --git a/packages/color-helpers/src/index.ts b/packages/color-helpers/src/index.ts new file mode 100644 index 000000000..2a876cf2f --- /dev/null +++ b/packages/color-helpers/src/index.ts @@ -0,0 +1,4 @@ +export * as calculations from './calculations'; +export * as conversions from './conversions'; +export * as utils from './utils'; +export { namedColors } from './named-colors'; diff --git a/packages/color-helpers/src/named-colors/index.ts b/packages/color-helpers/src/named-colors/index.ts new file mode 100644 index 000000000..722ef6ea0 --- /dev/null +++ b/packages/color-helpers/src/named-colors/index.ts @@ -0,0 +1,151 @@ +// https://www.w3.org/TR/css-color-4/#named-colors +export const namedColors: Record = { + aliceblue: [240, 248, 255], + antiquewhite: [250, 235, 215], + aqua: [0, 255, 255], + aquamarine: [127, 255, 212], + azure: [240, 255, 255], + beige: [245, 245, 220], + bisque: [255, 228, 196], + black: [0, 0, 0], + blanchedalmond: [255, 235, 205], + blue: [0, 0, 255], + blueviolet: [138, 43, 226], + brown: [165, 42, 42], + burlywood: [222, 184, 135], + cadetblue: [95, 158, 160], + chartreuse: [127, 255, 0], + chocolate: [210, 105, 30], + coral: [255, 127, 80], + cornflowerblue: [100, 149, 237], + cornsilk: [255, 248, 220], + crimson: [220, 20, 60], + cyan: [0, 255, 255], + darkblue: [0, 0, 139], + darkcyan: [0, 139, 139], + darkgoldenrod: [184, 134, 11], + darkgray: [169, 169, 169], + darkgreen: [0, 100, 0], + darkgrey: [169, 169, 169], + darkkhaki: [189, 183, 107], + darkmagenta: [139, 0, 139], + darkolivegreen: [85, 107, 47], + darkorange: [255, 140, 0], + darkorchid: [153, 50, 204], + darkred: [139, 0, 0], + darksalmon: [233, 150, 122], + darkseagreen: [143, 188, 143], + darkslateblue: [72, 61, 139], + darkslategray: [47, 79, 79], + darkslategrey: [47, 79, 79], + darkturquoise: [0, 206, 209], + darkviolet: [148, 0, 211], + deeppink: [255, 20, 147], + deepskyblue: [0, 191, 255], + dimgray: [105, 105, 105], + dimgrey: [105, 105, 105], + dodgerblue: [30, 144, 255], + firebrick: [178, 34, 34], + floralwhite: [255, 250, 240], + forestgreen: [34, 139, 34], + fuchsia: [255, 0, 255], + gainsboro: [220, 220, 220], + ghostwhite: [248, 248, 255], + gold: [255, 215, 0], + goldenrod: [218, 165, 32], + gray: [128, 128, 128], + green: [0, 128, 0], + greenyellow: [173, 255, 47], + grey: [128, 128, 128], + honeydew: [240, 255, 240], + hotpink: [255, 105, 180], + indianred: [205, 92, 92], + indigo: [75, 0, 130], + ivory: [255, 255, 240], + khaki: [240, 230, 140], + lavender: [230, 230, 250], + lavenderblush: [255, 240, 245], + lawngreen: [124, 252, 0], + lemonchiffon: [255, 250, 205], + lightblue: [173, 216, 230], + lightcoral: [240, 128, 128], + lightcyan: [224, 255, 255], + lightgoldenrodyellow: [250, 250, 210], + lightgray: [211, 211, 211], + lightgreen: [144, 238, 144], + lightgrey: [211, 211, 211], + lightpink: [255, 182, 193], + lightsalmon: [255, 160, 122], + lightseagreen: [32, 178, 170], + lightskyblue: [135, 206, 250], + lightslategray: [119, 136, 153], + lightslategrey: [119, 136, 153], + lightsteelblue: [176, 196, 222], + lightyellow: [255, 255, 224], + lime: [0, 255, 0], + limegreen: [50, 205, 50], + linen: [250, 240, 230], + magenta: [255, 0, 255], + maroon: [128, 0, 0], + mediumaquamarine: [102, 205, 170], + mediumblue: [0, 0, 205], + mediumorchid: [186, 85, 211], + mediumpurple: [147, 112, 219], + mediumseagreen: [60, 179, 113], + mediumslateblue: [123, 104, 238], + mediumspringgreen: [0, 250, 154], + mediumturquoise: [72, 209, 204], + mediumvioletred: [199, 21, 133], + midnightblue: [25, 25, 112], + mintcream: [245, 255, 250], + mistyrose: [255, 228, 225], + moccasin: [255, 228, 181], + navajowhite: [255, 222, 173], + navy: [0, 0, 128], + oldlace: [253, 245, 230], + olive: [128, 128, 0], + olivedrab: [107, 142, 35], + orange: [255, 165, 0], + orangered: [255, 69, 0], + orchid: [218, 112, 214], + palegoldenrod: [238, 232, 170], + palegreen: [152, 251, 152], + paleturquoise: [175, 238, 238], + palevioletred: [219, 112, 147], + papayawhip: [255, 239, 213], + peachpuff: [255, 218, 185], + peru: [205, 133, 63], + pink: [255, 192, 203], + plum: [221, 160, 221], + powderblue: [176, 224, 230], + purple: [128, 0, 128], + rebeccapurple: [102, 51, 153], + red: [255, 0, 0], + rosybrown: [188, 143, 143], + royalblue: [65, 105, 225], + saddlebrown: [139, 69, 19], + salmon: [250, 128, 114], + sandybrown: [244, 164, 96], + seagreen: [46, 139, 87], + seashell: [255, 245, 238], + sienna: [160, 82, 45], + silver: [192, 192, 192], + skyblue: [135, 206, 235], + slateblue: [106, 90, 205], + slategray: [112, 128, 144], + slategrey: [112, 128, 144], + snow: [255, 250, 250], + springgreen: [0, 255, 127], + steelblue: [70, 130, 180], + tan: [210, 180, 140], + teal: [0, 128, 128], + thistle: [216, 191, 216], + tomato: [255, 99, 71], + turquoise: [64, 224, 208], + violet: [238, 130, 238], + wheat: [245, 222, 179], + white: [255, 255, 255], + whitesmoke: [245, 245, 245], + yellow: [255, 255, 0], + yellowgreen: [154, 205, 50], +}; diff --git a/plugins/postcss-lab-function/src/css-color-4/LICENSE.md b/packages/color-helpers/src/utils/LICENSE.md similarity index 66% rename from plugins/postcss-lab-function/src/css-color-4/LICENSE.md rename to packages/color-helpers/src/utils/LICENSE.md index ea4236ffc..7293506b4 100644 --- a/plugins/postcss-lab-function/src/css-color-4/LICENSE.md +++ b/packages/color-helpers/src/utils/LICENSE.md @@ -1,5 +1,3 @@ All documents in this Directory are licensed by contributors under the [W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). - -See [w3c/csswg-drafts](https://github.com/w3c/csswg-drafts) for the original work. diff --git a/packages/color-helpers/src/utils/clip.ts b/packages/color-helpers/src/utils/clip.ts new file mode 100644 index 000000000..2a79c2d72 --- /dev/null +++ b/packages/color-helpers/src/utils/clip.ts @@ -0,0 +1,16 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function clip(color: Color): Color { + return color.map(val => { + if (val < 0) { + return 0; + } else if (val > 1) { + return 1; + } else { + return val; + } + }) as Color; +} diff --git a/packages/color-helpers/src/utils/in-gamut.ts b/packages/color-helpers/src/utils/in-gamut.ts new file mode 100644 index 000000000..f8b93fd0c --- /dev/null +++ b/packages/color-helpers/src/utils/in-gamut.ts @@ -0,0 +1,9 @@ +/** + * @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). + */ +export function inGamut(x: Color): boolean { + const [xX, xY, xZ] = x; + return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001; +} diff --git a/packages/color-helpers/src/utils/index.ts b/packages/color-helpers/src/utils/index.ts new file mode 100644 index 000000000..b73e4598c --- /dev/null +++ b/packages/color-helpers/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './clip'; +export * from './in-gamut'; diff --git a/packages/color-helpers/stryker.conf.json b/packages/color-helpers/stryker.conf.json new file mode 100644 index 000000000..015ebbb73 --- /dev/null +++ b/packages/color-helpers/stryker.conf.json @@ -0,0 +1,19 @@ +{ + "$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json", + "mutate": [ + "src/**/*.ts" + ], + "buildCommand": "npm run build", + "testRunner": "command", + "coverageAnalysis": "perTest", + "tempDirName": "../../.stryker-tmp", + "commandRunner": { + "command": "npm run test" + }, + "thresholds": { + "high": 100, + "low": 100, + "break": 100 + }, + "inPlace": true +} diff --git a/packages/color-helpers/test/_import.mjs b/packages/color-helpers/test/_import.mjs new file mode 100644 index 000000000..e7d81f6e9 --- /dev/null +++ b/packages/color-helpers/test/_import.mjs @@ -0,0 +1,7 @@ +import assert from 'assert'; +import { calculations } from '@csstools/color-helpers'; + +const { deltaEOK } = calculations; + +assert.equal(typeof deltaEOK, 'function', 'should export nested libraries'); +assert.equal(typeof calculations.deltaEOK, 'function', 'should be possible to import from index'); diff --git a/packages/color-helpers/test/_require.cjs b/packages/color-helpers/test/_require.cjs new file mode 100644 index 000000000..16a9da00a --- /dev/null +++ b/packages/color-helpers/test/_require.cjs @@ -0,0 +1,6 @@ +const assert = require('assert'); +const { deltaEOK } = require('@csstools/color-helpers').calculations; +const { calculations } = require('@csstools/color-helpers'); + +assert.equal(typeof deltaEOK, 'function', 'should export nested libraries'); +assert.equal(typeof calculations.deltaEOK, 'function', 'should be possible to import from index'); diff --git a/packages/color-helpers/tsconfig.json b/packages/color-helpers/tsconfig.json new file mode 100644 index 000000000..f8ce32b15 --- /dev/null +++ b/packages/color-helpers/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "declarationDir": ".", + "baseUrl": "./src/" + }, + "include": [ + "./src/**/*", + "types/global.d.ts" + ], + "exclude": ["dist"] +} diff --git a/packages/color-helpers/types/global.d.ts b/packages/color-helpers/types/global.d.ts new file mode 100644 index 000000000..9ed8ef549 --- /dev/null +++ b/packages/color-helpers/types/global.d.ts @@ -0,0 +1,5 @@ +export {}; + +declare global { + type Color = [number, number, number]; +} diff --git a/plugins/postcss-color-function/CHANGELOG.md b/plugins/postcss-color-function/CHANGELOG.md index 0de243786..cec56c98c 100644 --- a/plugins/postcss-color-function/CHANGELOG.md +++ b/plugins/postcss-color-function/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Color Function +### Unreleased (minor) + +- Add: `@csstools/color-helpers` dependency for all color value transformations. + ### 2.0.1 (January 28, 2023) - Improve `types` declaration in `package.json` diff --git a/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts deleted file mode 100644 index 846c0a37f..000000000 --- a/plugins/postcss-color-function/dist/convert-a98-rgb-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function a98RgbToSRgb(a98: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts deleted file mode 100644 index 07b637c6a..000000000 --- a/plugins/postcss-color-function/dist/convert-cie-xyz-50-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function cieXyz50ToSRgb(xyz: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts deleted file mode 100644 index b287e1e80..000000000 --- a/plugins/postcss-color-function/dist/convert-cie-xyz-65-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function cieXyz65ToSRgb(xyz: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts deleted file mode 100644 index d0451a4e9..000000000 --- a/plugins/postcss-color-function/dist/convert-display-p3-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function displayP3ToSRgb(displayP3: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts deleted file mode 100644 index 6a230a065..000000000 --- a/plugins/postcss-color-function/dist/convert-prophoto-rgb-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function prophotoRgbToSRgb(prophoto: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts deleted file mode 100644 index adb1f02aa..000000000 --- a/plugins/postcss-color-function/dist/convert-rec2020-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function rec2020ToSRgb(rec: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts deleted file mode 100644 index 0006647e8..000000000 --- a/plugins/postcss-color-function/dist/convert-srgb-linear-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function sRgbLinearToSRgb(linearSRgb: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts b/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts deleted file mode 100644 index 09d78d917..000000000 --- a/plugins/postcss-color-function/dist/convert-srgb-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function sRgbToSRgb(sRgb: color): color; -export {}; diff --git a/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts deleted file mode 100644 index a48b1e5bc..000000000 --- a/plugins/postcss-color-function/dist/css-color-4/conversions.d.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ -type color = [number, number, number]; -export declare const D50: number[]; -export declare const D65: number[]; -export declare function lin_sRGB(RGB: color): color; -export declare function gam_sRGB(RGB: color): color; -export declare function lin_sRGB_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_sRGB(XYZ: color): color; -export declare function lin_P3(RGB: color): color; -export declare function gam_P3(RGB: color): color; -export declare function lin_P3_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_P3(XYZ: color): color; -export declare function lin_ProPhoto(RGB: color): color; -export declare function gam_ProPhoto(RGB: color): color; -export declare function lin_ProPhoto_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_ProPhoto(XYZ: color): color; -export declare function lin_a98rgb(RGB: color): color; -export declare function gam_a98rgb(RGB: color): color; -export declare function lin_a98rgb_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_a98rgb(XYZ: color): color; -export declare function lin_2020(RGB: color): color; -export declare function gam_2020(RGB: color): color; -export declare function lin_2020_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_2020(XYZ: color): color; -export declare function D65_to_D50(XYZ: color): color; -export declare function D50_to_D65(XYZ: color): color; -export declare function XYZ_to_Lab(XYZ: color): color; -export declare function Lab_to_XYZ(Lab: color): color; -export declare function Lab_to_LCH(Lab: color): color; -export declare function LCH_to_Lab(LCH: color): color; -export declare function XYZ_to_OKLab(XYZ: color): color; -export declare function OKLab_to_XYZ(OKLab: color): color; -export declare function OKLab_to_OKLCH(OKLab: color): color; -export declare function OKLCH_to_OKLab(OKLCH: color): color; -export declare function rectangular_premultiply(color: color, alpha: number): color; -export declare function rectangular_un_premultiply(color: color, alpha: number): color; -export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function hsl_premultiply(color: color, alpha: number): color; -export {}; diff --git a/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts deleted file mode 100644 index d744ffaad..000000000 --- a/plugins/postcss-color-function/dist/css-color-4/deltaEOK.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */ -type color = [number, number, number]; -export declare function deltaEOK(reference: color, sample: color): number; -export {}; diff --git a/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts deleted file mode 100644 index 1a4ee6e95..000000000 --- a/plugins/postcss-color-function/dist/css-color-4/map-gamut.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -type color = [number, number, number]; -export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color; -export declare function clip(color: color): color; -export declare function inGamut(x: color): boolean; -export {}; diff --git a/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts b/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts deleted file mode 100644 index 3055a8245..000000000 --- a/plugins/postcss-color-function/dist/css-color-4/multiply-matrices.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Simple matrix (and vector) multiplication - * Warning: No error handling for incompatible dimensions! - * @author Lea Verou 2020 MIT License - * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js - */ -export declare function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array; diff --git a/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts deleted file mode 100644 index a5bb9da80..000000000 --- a/plugins/postcss-color-function/dist/css-color-4/utilities.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ -type color = [number, number, number]; -export declare function sRGB_to_luminance(RGB: color): number; -export declare function contrast(RGB1: color, RGB2: color): number; -export declare function sRGB_to_LCH(RGB: color): color; -export declare function P3_to_LCH(RGB: color): color; -export declare function r2020_to_LCH(RGB: color): color; -export declare function LCH_to_sRGB(LCH: color): color; -export declare function LCH_to_P3(LCH: color): color; -export declare function LCH_to_r2020(LCH: color): color; -export declare function hslToRgb(hsl: color): color; -export declare function hueToRgb(t1: number, t2: number, hue: number): number; -export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color; -export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number]; -export declare function XYZ_to_xy(XYZ: color): [number, number]; -export declare function xy_to_uv(xy: [number, number]): [number, number]; -export declare function XYZ_to_uv(XYZ: color): [number, number]; -export {}; diff --git a/plugins/postcss-color-function/dist/index.cjs b/plugins/postcss-color-function/dist/index.cjs index efbb944b1..6671672e4 100644 --- a/plugins/postcss-color-function/dist/index.cjs +++ b/plugins/postcss-color-function/dist/index.cjs @@ -1,29 +1 @@ -"use strict";var t=require("@csstools/postcss-progressive-custom-properties"),e=require("postcss-value-parser");function hasFallback(t){const e=t.parent;if(!e)return!1;const r=t.prop.toLowerCase(),n=e.index(t);for(let t=0;t[t])));const o=a[0].length,s=a[0].map(((t,e)=>a.map((t=>t[e]))));let i=n.map((t=>s.map((e=>Array.isArray(t)?t.reduce(((t,r,n)=>t+r*(e[n]||0)),0):e.reduce(((e,r)=>e+r*t),0)))));return 1===r&&(i=i[0]),1===o?i.map((t=>t[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */function lin_sRGB(t){return t.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return r<.04045?t/12.92:e*Math.pow((r+.055)/1.055,2.4)}))}function gam_sRGB(t){return t.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return r>.0031308?e*(1.055*Math.pow(r,1/2.4)-.055):12.92*t}))}function lin_sRGB_to_XYZ(t){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],t)}function XYZ_to_lin_sRGB(t){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],t)}function lin_2020(t){const e=1.09929682680944;return t.map((function(t){const r=t<0?-1:1,n=Math.abs(t);return n<.08124285829863151?t/4.5:r*Math.pow((n+e-1)/e,1/.45)}))}function D50_to_D65(t){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],t)}function XYZ_to_OKLab(t){const e=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],t);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],e.map((t=>Math.cbrt(t))))}function OKLab_to_XYZ(t){const e=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],t);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],e.map((t=>t**3)))}function OKLab_to_OKLCH(t){const e=180*Math.atan2(t[2],t[1])/Math.PI;return[t[0],Math.sqrt(t[1]**2+t[2]**2),e>=0?e:e+360]}function OKLCH_to_OKLab(t){return[t[0],t[1]*Math.cos(t[2]*Math.PI/180),t[1]*Math.sin(t[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(t,e){const[r,n,a]=t,[o,s,i]=e,u=r-o,c=n-s,l=a-i;return Math.sqrt(u**2+c**2+l**2)}function mapGamut(t,e,r){return binarySearchGamut(t,e,r)}function binarySearchGamut(t,e,r){let n=0,a=t[1];const o=t;for(;a-n>1e-4;){const t=clip(e(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(r(t)))-.02<1e-4?n=o[1]:a=o[1],o[1]=(a+n)/2}return clip(e([...o]))}function clip(t){return t.map((t=>t<0?0:t>1?1:t))}function inGamut(t){const[e,r,n]=t;return e>=-1e-4&&e<=1.0001&&r>=-1e-4&&r<=1.0001&&n>=-1e-4&&n<=1.0001}function a98RgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1,r=Math.abs(t);return e*Math.pow(r,563/256)})),e=multiplyMatrices([[.5766690429101305,.1855582379065463,.1882286462349947],[.29734497525053605,.6273635662554661,.07529145849399788],[.02703136138641234,.07068885253582723,.9913375368376388]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz50ToSRgb(t){let e=t.slice();e=D50_to_D65(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz65ToSRgb(t){let e=t.slice(),r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function displayP3ToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function prophotoRgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1;return Math.abs(t)<=.03125?t/16:e*Math.pow(t,1.8)})),e=multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],e),e=D50_to_D65(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function rec2020ToSRgb(t){let e=t.slice();e=lin_2020(e),e=multiplyMatrices([[.6369580483012914,.14461690358620832,.1688809751641721],[.2627002120112671,.6779980715188708,.05930171646986196],[0,.028072693049087428,1.060985057710791]],e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbLinearToSRgb(t){let e=t.slice();e=lin_sRGB_to_XYZ(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=lin_sRGB_to_XYZ(e);let r=e.slice();return r=XYZ_to_OKLab(r),r=OKLab_to_OKLCH(r),r[0]<1e-6&&(r=[0,0,0]),r[0]>.999999&&(r=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(r,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function onCSSFunctionSRgb(t,r,n,a){const o=e.stringify(t),s=t.value,i=t.nodes.slice().filter((t=>"comment"!==t.type&&"space"!==t.type));let u,c=null;if("color"===s.toLowerCase()&&(c=colorFunctionContents(i)),!c)return;switch(t.value="rgb",transformAlpha(t,c.slash,c.alpha),c.colorSpace){case"srgb":u=sRgbToSRgb;break;case"srgb-linear":u=sRgbLinearToSRgb;break;case"a98-rgb":u=a98RgbToSRgb;break;case"prophoto-rgb":u=prophotoRgbToSRgb;break;case"display-p3":u=displayP3ToSRgb;break;case"rec2020":u=rec2020ToSRgb;break;case"xyz-d50":u=cieXyz50ToSRgb;break;case"xyz-d65":case"xyz":u=cieXyz65ToSRgb;break;default:return}const l=(_=c,_.parameters.map((t=>t.value))).map((t=>parseFloat(t.number)));var _;const p=u(l);!inGamut(l)&&a&&r.warn(n,`"${o}" is out of gamut for "${c.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),t.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[2])),type:"word"}],c.alpha&&(t.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),t.nodes.push(c.alpha))}function isColorSpaceNode(t){if(!t||"word"!==t.type)return!1;switch(t.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const r=e.unit(t.value);return!!r&&!!r.number}function isNumericNodePercentageOrNumber(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const r=e.unit(t.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(t){return t&&"function"===t.type&&"calc"===t.value.toLowerCase()}function isVarNode(t){return t&&"function"===t.type&&"var"===t.value.toLowerCase()}function colorFunctionContents(t){if(!isColorSpaceNode(t[0]))return null;const r={colorSpace:t[0].value.toLowerCase(),colorSpaceNode:t[0],parameters:[]};for(let a=1;a3&&(r.parameters=r.parameters.slice(0,3))),r}function transformAlpha(t,r,n){if(!r||!n)return;if(t.value="rgba",r.value=",",r.before="",!isNumericNode(n))return;const a=e.unit(n.value);a&&"%"===a.unit&&(a.number=String(parseFloat(a.number)/100),n.value=String(a.number))}function canParseAsUnit(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch(t){return!1}}function modifiedValues(t,r,n,a){let o;try{o=e(t)}catch(e){r.warn(n,`Failed to parse value '${t}' as a color function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((t=>{t.type&&"function"===t.type&&"color"===t.value.toLowerCase()&&onCSSFunctionSRgb(t,r,n,a)}));const s=String(o);return s!==t?s:void 0}const basePlugin=t=>{const e="preserve"in Object(t)&&Boolean(t.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(t,{result:r})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const n=t.value;if(!n.toLowerCase().includes("color("))return;const a=modifiedValues(n,t,r,e);void 0!==a&&(t.cloneBefore({value:a}),e||t.remove())}}};basePlugin.postcss=!0;const postcssPlugin=e=>{const r=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},e);return r.enableProgressiveCustomProperties&&r.preserve?{postcssPlugin:"postcss-color-function",plugins:[t(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; +"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),r=require("postcss-value-parser"),o=require("@csstools/color-helpers");function hasFallback(e){const r=e.parent;if(!r)return!1;const o=e.prop.toLowerCase(),n=r.index(e);for(let e=0;e"comment"!==e.type&&"space"!==e.type));let i,l=null;if("color"===u.toLowerCase()&&(l=colorFunctionContents(c)),!l)return;switch(e.value="rgb",transformAlpha(e,l.slash,l.alpha),l.colorSpace){case"srgb":i=o.conversions.sRGB_to_sRGB;break;case"srgb-linear":i=o.conversions.sRGB_linear_to_sRGB;break;case"a98-rgb":i=o.conversions.a98_RGB_to_sRGB;break;case"prophoto-rgb":i=o.conversions.proPhoto_RGB_to_sRGB;break;case"display-p3":i=o.conversions.p3_to_sRGB;break;case"rec2020":i=o.conversions.rec_2020_to_sRGB;break;case"xyz-d50":i=o.conversions.cie_XYZ_50_to_sRGB;break;case"xyz-d65":case"xyz":i=o.conversions.cie_XYZ_65_to_sRGB;break;default:return}const p=(d=l,d.parameters.map((e=>e.value))).map((e=>parseFloat(e.number)));var d;const v=i(p);!o.utils.inGamut(p)&&s&&n.warn(t,`"${a}" is out of gamut for "${l.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[2])),type:"word"}],l.alpha&&(e.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.push(l.alpha))}function isColorSpaceNode(e){if(!e||"word"!==e.type)return!1;switch(e.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const o=r.unit(e.value);return!!o&&!!o.number}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const o=r.unit(e.value);return!!o&&("%"===o.unit||""===o.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function colorFunctionContents(e){if(!isColorSpaceNode(e[0]))return null;const o={colorSpace:e[0].value.toLowerCase(),colorSpaceNode:e[0],parameters:[]};for(let t=1;t3&&(o.parameters=o.parameters.slice(0,3))),o}function transformAlpha(e,o,n){if(!o||!n)return;if(e.value="rgba",o.value=",",o.before="",!isNumericNode(n))return;const t=r.unit(n.value);t&&"%"===t.unit&&(t.number=String(parseFloat(t.number)/100),n.value=String(t.number))}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==r.unit(e.value)}catch(e){return!1}}function modifiedValues(e,o,n,t){let s;try{s=r(e)}catch(r){o.warn(n,`Failed to parse value '${e}' as a color function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&"color"===e.value.toLowerCase()&&onCSSFunctionSRgb(e,o,n,t)}));const a=String(s);return a!==e?a:void 0}const basePlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(e,{result:o})=>{if(hasFallback(e))return;if(hasSupportsAtRuleAncestor(e))return;const n=e.value;if(!n.toLowerCase().includes("color("))return;const t=modifiedValues(n,e,o,r);void 0!==t&&(e.cloneBefore({value:t}),r||e.remove())}}};basePlugin.postcss=!0;const postcssPlugin=r=>{const o=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},r);return o.enableProgressiveCustomProperties&&o.preserve?{postcssPlugin:"postcss-color-function",plugins:[e(),basePlugin(o)]}:basePlugin(o)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; diff --git a/plugins/postcss-color-function/dist/index.mjs b/plugins/postcss-color-function/dist/index.mjs index 3087f58d4..1449c4584 100644 --- a/plugins/postcss-color-function/dist/index.mjs +++ b/plugins/postcss-color-function/dist/index.mjs @@ -1,29 +1 @@ -import t from"@csstools/postcss-progressive-custom-properties";import e from"postcss-value-parser";function hasFallback(t){const e=t.parent;if(!e)return!1;const n=t.prop.toLowerCase(),r=e.index(t);for(let t=0;t[t])));const a=o[0].length,s=o[0].map(((t,e)=>o.map((t=>t[e]))));let i=r.map((t=>s.map((e=>Array.isArray(t)?t.reduce(((t,n,r)=>t+n*(e[r]||0)),0):e.reduce(((e,n)=>e+n*t),0)))));return 1===n&&(i=i[0]),1===a?i.map((t=>t[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */function lin_sRGB(t){return t.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return n<.04045?t/12.92:e*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(t){return t.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return n>.0031308?e*(1.055*Math.pow(n,1/2.4)-.055):12.92*t}))}function lin_sRGB_to_XYZ(t){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],t)}function XYZ_to_lin_sRGB(t){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],t)}function lin_2020(t){const e=1.09929682680944;return t.map((function(t){const n=t<0?-1:1,r=Math.abs(t);return r<.08124285829863151?t/4.5:n*Math.pow((r+e-1)/e,1/.45)}))}function D50_to_D65(t){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],t)}function XYZ_to_OKLab(t){const e=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],t);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],e.map((t=>Math.cbrt(t))))}function OKLab_to_XYZ(t){const e=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],t);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],e.map((t=>t**3)))}function OKLab_to_OKLCH(t){const e=180*Math.atan2(t[2],t[1])/Math.PI;return[t[0],Math.sqrt(t[1]**2+t[2]**2),e>=0?e:e+360]}function OKLCH_to_OKLab(t){return[t[0],t[1]*Math.cos(t[2]*Math.PI/180),t[1]*Math.sin(t[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(t,e){const[n,r,o]=t,[a,s,i]=e,u=n-a,c=r-s,l=o-i;return Math.sqrt(u**2+c**2+l**2)}function mapGamut(t,e,n){return binarySearchGamut(t,e,n)}function binarySearchGamut(t,e,n){let r=0,o=t[1];const a=t;for(;o-r>1e-4;){const t=clip(e(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(t)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(e([...a]))}function clip(t){return t.map((t=>t<0?0:t>1?1:t))}function inGamut(t){const[e,n,r]=t;return e>=-1e-4&&e<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function a98RgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1,n=Math.abs(t);return e*Math.pow(n,563/256)})),e=multiplyMatrices([[.5766690429101305,.1855582379065463,.1882286462349947],[.29734497525053605,.6273635662554661,.07529145849399788],[.02703136138641234,.07068885253582723,.9913375368376388]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz50ToSRgb(t){let e=t.slice();e=D50_to_D65(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function cieXyz65ToSRgb(t){let e=t.slice(),n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function displayP3ToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function prophotoRgbToSRgb(t){let e=t.slice();e=e.map((function(t){const e=t<0?-1:1;return Math.abs(t)<=.03125?t/16:e*Math.pow(t,1.8)})),e=multiplyMatrices([[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],e),e=D50_to_D65(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function rec2020ToSRgb(t){let e=t.slice();e=lin_2020(e),e=multiplyMatrices([[.6369580483012914,.14461690358620832,.1688809751641721],[.2627002120112671,.6779980715188708,.05930171646986196],[0,.028072693049087428,1.060985057710791]],e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbLinearToSRgb(t){let e=t.slice();e=lin_sRGB_to_XYZ(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function sRgbToSRgb(t){let e=t.slice();e=lin_sRGB(e),e=lin_sRGB_to_XYZ(e);let n=e.slice();return n=XYZ_to_OKLab(n),n=OKLab_to_OKLCH(n),n[0]<1e-6&&(n=[0,0,0]),n[0]>.999999&&(n=[1,0,0]),e=XYZ_to_lin_sRGB(e),e=gam_sRGB(e),inGamut(e)?clip(e):mapGamut(n,(t=>gam_sRGB(t=XYZ_to_lin_sRGB(t=OKLab_to_XYZ(t=OKLCH_to_OKLab(t))))),(t=>OKLab_to_OKLCH(t=XYZ_to_OKLab(t=lin_sRGB_to_XYZ(t=lin_sRGB(t))))))}function onCSSFunctionSRgb(t,n,r,o){const a=e.stringify(t),s=t.value,i=t.nodes.slice().filter((t=>"comment"!==t.type&&"space"!==t.type));let u,c=null;if("color"===s.toLowerCase()&&(c=colorFunctionContents(i)),!c)return;switch(t.value="rgb",transformAlpha(t,c.slash,c.alpha),c.colorSpace){case"srgb":u=sRgbToSRgb;break;case"srgb-linear":u=sRgbLinearToSRgb;break;case"a98-rgb":u=a98RgbToSRgb;break;case"prophoto-rgb":u=prophotoRgbToSRgb;break;case"display-p3":u=displayP3ToSRgb;break;case"rec2020":u=rec2020ToSRgb;break;case"xyz-d50":u=cieXyz50ToSRgb;break;case"xyz-d65":case"xyz":u=cieXyz65ToSRgb;break;default:return}const l=(_=c,_.parameters.map((t=>t.value))).map((t=>parseFloat(t.number)));var _;const p=u(l);!inGamut(l)&&o&&n.warn(r,`"${a}" is out of gamut for "${c.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),t.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*p[2])),type:"word"}],c.alpha&&(t.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),t.nodes.push(c.alpha))}function isColorSpaceNode(t){if(!t||"word"!==t.type)return!1;switch(t.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const n=e.unit(t.value);return!!n&&!!n.number}function isNumericNodePercentageOrNumber(t){if(!t||"word"!==t.type)return!1;if(!canParseAsUnit(t))return!1;const n=e.unit(t.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(t){return t&&"function"===t.type&&"calc"===t.value.toLowerCase()}function isVarNode(t){return t&&"function"===t.type&&"var"===t.value.toLowerCase()}function colorFunctionContents(t){if(!isColorSpaceNode(t[0]))return null;const n={colorSpace:t[0].value.toLowerCase(),colorSpaceNode:t[0],parameters:[]};for(let o=1;o3&&(n.parameters=n.parameters.slice(0,3))),n}function transformAlpha(t,n,r){if(!n||!r)return;if(t.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=e.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function canParseAsUnit(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch(t){return!1}}function modifiedValues(t,n,r,o){let a;try{a=e(t)}catch(e){n.warn(r,`Failed to parse value '${t}' as a color function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((t=>{t.type&&"function"===t.type&&"color"===t.value.toLowerCase()&&onCSSFunctionSRgb(t,n,r,o)}));const s=String(a);return s!==t?s:void 0}const basePlugin=t=>{const e="preserve"in Object(t)&&Boolean(t.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!r.toLowerCase().includes("color("))return;const o=modifiedValues(r,t,n,e);void 0!==o&&(t.cloneBefore({value:o}),e||t.remove())}}};basePlugin.postcss=!0;const postcssPlugin=e=>{const n=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},e);return n.enableProgressiveCustomProperties&&n.preserve?{postcssPlugin:"postcss-color-function",plugins:[t(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; +import e from"@csstools/postcss-progressive-custom-properties";import r from"postcss-value-parser";import{conversions as t,utils as o}from"@csstools/color-helpers";function hasFallback(e){const r=e.parent;if(!r)return!1;const t=e.prop.toLowerCase(),o=r.index(e);for(let e=0;e"comment"!==e.type&&"space"!==e.type));let l,p=null;if("color"===c.toLowerCase()&&(p=colorFunctionContents(i)),!p)return;switch(e.value="rgb",transformAlpha(e,p.slash,p.alpha),p.colorSpace){case"srgb":l=t.sRGB_to_sRGB;break;case"srgb-linear":l=t.sRGB_linear_to_sRGB;break;case"a98-rgb":l=t.a98_RGB_to_sRGB;break;case"prophoto-rgb":l=t.proPhoto_RGB_to_sRGB;break;case"display-p3":l=t.p3_to_sRGB;break;case"rec2020":l=t.rec_2020_to_sRGB;break;case"xyz-d50":l=t.cie_XYZ_50_to_sRGB;break;case"xyz-d65":case"xyz":l=t.cie_XYZ_65_to_sRGB;break;default:return}const d=(f=p,f.parameters.map((e=>e.value))).map((e=>parseFloat(e.number)));var f;const v=l(d);!o.inGamut(d)&&a&&n.warn(s,`"${u}" is out of gamut for "${p.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes=[{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[0])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[1])),type:"word"},{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""},{sourceIndex:0,sourceEndIndex:1,value:String(Math.round(255*v[2])),type:"word"}],p.alpha&&(e.nodes.push({sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.push(p.alpha))}function isColorSpaceNode(e){if(!e||"word"!==e.type)return!1;switch(e.value.toLowerCase()){case"srgb":case"srgb-linear":case"display-p3":case"a98-rgb":case"prophoto-rgb":case"rec2020":case"xyz-d50":case"xyz-d65":case"xyz":return!0;default:return!1}}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=r.unit(e.value);return!!t&&!!t.number}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=r.unit(e.value);return!!t&&("%"===t.unit||""===t.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function colorFunctionContents(e){if(!isColorSpaceNode(e[0]))return null;const t={colorSpace:e[0].value.toLowerCase(),colorSpaceNode:e[0],parameters:[]};for(let n=1;n3&&(t.parameters=t.parameters.slice(0,3))),t}function transformAlpha(e,t,o){if(!t||!o)return;if(e.value="rgba",t.value=",",t.before="",!isNumericNode(o))return;const n=r.unit(o.value);n&&"%"===n.unit&&(n.number=String(parseFloat(n.number)/100),o.value=String(n.number))}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==r.unit(e.value)}catch(e){return!1}}function modifiedValues(e,t,o,n){let s;try{s=r(e)}catch(r){t.warn(o,`Failed to parse value '${e}' as a color function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&"color"===e.value.toLowerCase()&&onCSSFunctionSRgb(e,t,o,n)}));const a=String(s);return a!==e?a:void 0}const basePlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-color-function",Declaration:(e,{result:t})=>{if(hasFallback(e))return;if(hasSupportsAtRuleAncestor(e))return;const o=e.value;if(!o.toLowerCase().includes("color("))return;const n=modifiedValues(o,e,t,r);void 0!==n&&(e.cloneBefore({value:n}),r||e.remove())}}};basePlugin.postcss=!0;const postcssPlugin=r=>{const t=Object.assign({preserve:!1,enableProgressiveCustomProperties:!0},r);return t.enableProgressiveCustomProperties&&t.preserve?{postcssPlugin:"postcss-color-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; diff --git a/plugins/postcss-color-function/package.json b/plugins/postcss-color-function/package.json index b7be2767b..7b9cf910c 100644 --- a/plugins/postcss-color-function/package.json +++ b/plugins/postcss-color-function/package.json @@ -29,6 +29,7 @@ "dist" ], "dependencies": { + "@csstools/color-helpers": "^0.0.0", "@csstools/postcss-progressive-custom-properties": "^2.0.0", "postcss-value-parser": "^4.2.0" }, diff --git a/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts deleted file mode 100644 index 939e35a46..000000000 --- a/plugins/postcss-color-function/src/convert-a98-rgb-to-srgb.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_sRGB, lin_a98rgb, lin_a98rgb_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function a98RgbToSRgb(a98: color): color { - let conversion = a98.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_a98rgb(conversion); - conversion = lin_a98rgb_to_XYZ(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts b/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts deleted file mode 100644 index 598ffe16d..000000000 --- a/plugins/postcss-color-function/src/convert-cie-xyz-50-to-srgb.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { D50_to_D65, gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function cieXyz50ToSRgb(xyz: color): color { - let conversion = xyz.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = D50_to_D65(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts b/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts deleted file mode 100644 index fc3f58ed2..000000000 --- a/plugins/postcss-color-function/src/convert-cie-xyz-65-to-srgb.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function cieXyz65ToSRgb(xyz: color): color { - let conversion = xyz.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts b/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts deleted file mode 100644 index 8ea108b5b..000000000 --- a/plugins/postcss-color-function/src/convert-display-p3-to-srgb.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_sRGB, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function displayP3ToSRgb(displayP3: color): color { - let conversion = displayP3.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_P3(conversion); - conversion = lin_P3_to_XYZ(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts deleted file mode 100644 index 327205d19..000000000 --- a/plugins/postcss-color-function/src/convert-prophoto-rgb-to-srgb.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { D50_to_D65, gam_sRGB, lin_ProPhoto, lin_ProPhoto_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function prophotoRgbToSRgb(prophoto: color): color { - let conversion = prophoto.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_ProPhoto(conversion); - conversion = lin_ProPhoto_to_XYZ(conversion); - conversion = D50_to_D65(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts b/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts deleted file mode 100644 index e6629f79b..000000000 --- a/plugins/postcss-color-function/src/convert-rec2020-to-srgb.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_sRGB, lin_2020, lin_2020_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function rec2020ToSRgb(rec: color): color { - let conversion = rec.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_2020(conversion); - conversion = lin_2020_to_XYZ(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts b/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts deleted file mode 100644 index 94e8edb98..000000000 --- a/plugins/postcss-color-function/src/convert-srgb-linear-to-srgb.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function sRgbLinearToSRgb(linearSRgb: color): color { - let conversion = linearSRgb.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_sRGB_to_XYZ(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts b/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts deleted file mode 100644 index 3bf206768..000000000 --- a/plugins/postcss-color-function/src/convert-srgb-to-srgb.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function sRgbToSRgb(sRgb: color): color { - let conversion = sRgb.slice() as color; - - // https://www.w3.org/TR/css-color-4/#predefined-to-predefined - // https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab - conversion = lin_sRGB(conversion); - conversion = lin_sRGB_to_XYZ(conversion); - - let oklch = conversion.slice() as color; - oklch = XYZ_to_OKLab(oklch); - oklch = OKLab_to_OKLCH(oklch); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - // 3. Convert from(D65 - adapted) CIE XYZ to linear RGB - conversion = XYZ_to_lin_sRGB(conversion); - // 4. Convert from linear - light RGB to RGB(do gamma encoding) - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion); - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }); -} diff --git a/plugins/postcss-color-function/src/css-color-4/conversions.ts b/plugins/postcss-color-function/src/css-color-4/conversions.ts deleted file mode 100644 index 636f08f90..000000000 --- a/plugins/postcss-color-function/src/css-color-4/conversions.ts +++ /dev/null @@ -1,512 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ - -/* eslint-disable @typescript-eslint/no-loss-of-precision */ - -import { multiplyMatrices } from './multiply-matrices'; - -type color = [number, number, number]; - -// Sample code for color conversions -// Conversion can also be done using ICC profiles and a Color Management System -// For clarity, a library is used for matrix multiplication (multiply-matrices.js) - -// standard white points, defined by 4-figure CIE x,y chromaticities -export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585]; -export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290]; - -// sRGB-related functions - -export function lin_sRGB(RGB: color): color { - // convert an array of sRGB values - // where in-gamut values are in the range [0 - 1] - // to linear light (un-companded) form. - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // for negative values, linear portion is extended on reflection of axis, - // then reflected power function is used. - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < 0.04045) { - return val / 12.92; - } - - return sign * (Math.pow((abs + 0.055) / 1.055, 2.4)); - }) as color; -} - -export function gam_sRGB(RGB: color): color { - // convert an array of linear-light sRGB values in the range 0.0-1.0 - // to gamma corrected form - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // For negative values, linear portion extends on reflection - // of axis, then uses reflected pow below that - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > 0.0031308) { - return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055); - } - - return 12.92 * val; - }) as color; -} - -export function lin_sRGB_to_XYZ(rgb: color): color { - // convert an array of linear-light sRGB values to CIE XYZ - // using sRGB's own white, D65 (no chromatic adaptation) - - const M = [ - [0.41239079926595934, 0.357584339383878, 0.1804807884018343], - [0.21263900587151027, 0.715168678767756, 0.07219231536073371], - [0.01933081871559182, 0.11919477979462598, 0.9505321522496607], - ]; - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_sRGB(XYZ: color): color { - // convert XYZ to linear-light sRGB - - const M = [ - [3.2409699419045226, -1.537383177570094, -0.4986107602930034], - [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559], - [0.05563007969699366, -0.20397695888897652, 1.0569715142428786], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// display-p3-related functions - - -export function lin_P3(RGB: color): color { - // convert an array of display-p3 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - - return lin_sRGB(RGB); // same as sRGB -} - -export function gam_P3(RGB: color): color { - // convert an array of linear-light display-p3 RGB in the range 0.0-1.0 - // to gamma corrected form - - return gam_sRGB(RGB); // same as sRGB -} - -export function lin_P3_to_XYZ(rgb: color): color { - // convert an array of linear-light display-p3 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.4865709486482162, 0.26566769316909306, 0.1982172852343625], - [0.2289745640697488, 0.6917385218365064, 0.079286914093745], - [0.0000000000000000, 0.04511338185890264, 1.043944368900976], - ]; - // 0 was computed as -3.972075516933488e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_P3(XYZ: color): color { - // convert XYZ to linear-light P3 - const M = [ - [2.493496911941425, -0.9313836179191239, -0.40271078445071684], - [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577], - [0.03584583024378447, -0.07617238926804182, 0.9568845240076872], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// prophoto-rgb functions - -export function lin_ProPhoto(RGB: color): color { - // convert an array of prophoto-rgb values - // where in-gamut colors are in the range [0.0 - 1.0] - // to linear light (un-companded) form. - // Transfer curve is gamma 1.8 with a small linear portion - // Extended transfer function - const Et2 = 16 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs <= Et2) { - return val / 16; - } - - return sign * Math.pow(val, 1.8); - }) as color; -} - -export function gam_ProPhoto(RGB: color): color { - // convert an array of linear-light prophoto-rgb in the range 0.0-1.0 - // to gamma corrected form - // Transfer curve is gamma 1.8 with a small linear portion - // TODO for negative values, extend linear portion on reflection of axis, then add pow below that - const Et = 1 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs >= Et) { - return sign * Math.pow(abs, 1 / 1.8); - } - - return 16 * val; - }) as color; -} - -export function lin_ProPhoto_to_XYZ(rgb: color): color { - // convert an array of linear-light prophoto-rgb values to CIE XYZ - // using D50 (so no chromatic adaptation needed afterwards) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.7977604896723027, 0.13518583717574031, 0.0313493495815248], - [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902], - [0.0, 0.0, 0.8251046025104601], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_ProPhoto(XYZ: color): color { - // convert XYZ to linear-light prophoto-rgb - const M = [ - [1.3457989731028281, -0.25558010007997534, -0.05110628506753401], - [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973], - [0.0, 0.0, 1.2119675456389454], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// a98-rgb functions - -export function lin_a98rgb(RGB: color): color { - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 563 / 256); - }) as color; -} - -export function gam_a98rgb(RGB: color): color { - // convert an array of linear-light a98-rgb in the range 0.0-1.0 - // to gamma corrected form - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 256 / 563); - }) as color; -} - -export function lin_a98rgb_to_XYZ(rgb: color): color { - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - const M = [ - [0.5766690429101305, 0.1855582379065463, 0.1882286462349947], - [0.29734497525053605, 0.6273635662554661, 0.07529145849399788], - [0.02703136138641234, 0.07068885253582723, 0.9913375368376388], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_a98rgb(XYZ: color): color { - // convert XYZ to linear-light a98-rgb - const M = [ - [2.0415879038107465, -0.5650069742788596, -0.34473135077832956], - [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557], - [0.013444280632031142, -0.11836239223101838, 1.0151749943912054], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -//Rec. 2020-related functions - -export function lin_2020(RGB: color): color { - // convert an array of rec2020 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < β * 4.5) { - return val / 4.5; - } - - return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }) as color; -} - -export function gam_2020(RGB: color): color { - // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 - // to gamma corrected form - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > β) { - return sign * (α * Math.pow(abs, 0.45) - (α - 1)); - } - - return 4.5 * val; - }) as color; -} - -export function lin_2020_to_XYZ(rgb: color): color { - // convert an array of linear-light rec2020 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.6369580483012914, 0.14461690358620832, 0.1688809751641721], - [0.2627002120112671, 0.6779980715188708, 0.05930171646986196], - [0.000000000000000, 0.028072693049087428, 1.060985057710791], - ]; - // 0 is actually calculated as 4.994106574466076e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_2020(XYZ: color): color { - // convert XYZ to linear-light rec2020 - const M = [ - [1.7166511879712674, -0.35567078377639233, -0.25336628137365974], - [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113], - [0.017639857445310783, -0.042770613257808524, 0.9421031212354738], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// Chromatic adaptation - -export function D65_to_D50(XYZ: color): color { - // Bradford chromatic adaptation from D65 to D50 - // The matrix below is the result of three operations: - // - convert from XYZ to retinal cone domain - // - scale components from one reference white to another - // - convert back to XYZ - // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html - const M = [ - [1.0479298208405488, 0.022946793341019088, -0.05019222954313557], - [0.029627815688159344, 0.990434484573249, -0.01707382502938514], - [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -export function D50_to_D65(XYZ: color): color { - // Bradford chromatic adaptation from D50 to D65 - const M = [ - [0.9554734527042182, -0.023098536874261423, 0.0632593086610217], - [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008], - [0.012314001688319899, -0.020507696433477912, 1.3303659366080753], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// CIE Lab and LCH - -export function XYZ_to_Lab(XYZ: color): color { - // Assuming XYZ is relative to D50, convert to CIE Lab - // from CIE standard, which now defines these as a rational fraction - const ε = 216 / 24389; // 6^3/29^3 - const κ = 24389 / 27; // 29^3/3^3 - - // compute xyz, which is XYZ scaled relative to reference white - const xyz = XYZ.map((value, i) => value / D50[i]); - - // now compute f - const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116); - - return [ - (116 * f[1]) - 16, // L - 500 * (f[0] - f[1]), // a - 200 * (f[1] - f[2]), // b - ]; - // L in range [0,100]. For use in CSS, add a percent -} - -export function Lab_to_XYZ(Lab: color): color { - // Convert Lab to D50-adapted XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const κ = 24389 / 27; // 29^3/3^3 - const ε = 216 / 24389; // 6^3/29^3 - const f = []; - - // compute f, starting with the luminance-related term - f[1] = (Lab[0] + 16) / 116; - f[0] = Lab[1] / 500 + f[1]; - f[2] = f[1] - Lab[2] / 200; - - // compute xyz - const xyz = [ - Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ, - Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ, - Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ, - ]; - - // Compute XYZ by scaling xyz by reference white - return xyz.map((value, i) => value * D50[i]) as color; -} - -export function Lab_to_LCH(Lab: color): color { - // Convert to polar form - const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI; - return [ - Lab[0], // L is still L - Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function LCH_to_Lab(LCH: color): color { - // Convert from polar form - return [ - LCH[0], // L is still L - LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a - LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b - ]; -} - -// OKLab and OKLCH -// https://bottosson.github.io/posts/oklab/ - -// XYZ <-> LMS matrices recalculated for consistent reference white -// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 - -export function XYZ_to_OKLab(XYZ: color): color { - // Given XYZ relative to D65, convert to OKLab - const XYZtoLMS = [ - [0.8190224432164319, 0.3619062562801221, -0.12887378261216414], - [0.0329836671980271, 0.9292868468965546, 0.03614466816999844], - [0.048177199566046255, 0.26423952494422764, 0.6335478258136937], - ]; - const LMStoOKLab = [ - [0.2104542553, 0.7936177850, -0.0040720468], - [1.9779984951, -2.4285922050, 0.4505937099], - [0.0259040371, 0.7827717662, -0.8086757660], - ]; - - const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color; - return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color; - // L in range [0,1]. For use in CSS, multiply by 100 and add a percent -} - -export function OKLab_to_XYZ(OKLab: color): color { - // Given OKLab, convert to XYZ relative to D65 - const LMStoXYZ = [ - [1.2268798733741557, -0.5578149965554813, 0.28139105017721583], - [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701], - [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418], - ]; - const OKLabtoLMS = [ - [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339], - [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402], - [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399], - ]; - - const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color; - return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color; -} - -export function OKLab_to_OKLCH(OKLab: color): color { - const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI; - return [ - OKLab[0], // L is still L - Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function OKLCH_to_OKLab(OKLCH: color): color { - return [ - OKLCH[0], // L is still L - OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a - OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b - ]; -} - -// Premultiplied alpha conversions - -export function rectangular_premultiply(color: color, alpha: number): color { - // given a color in a rectangular orthogonal colorspace - // and an alpha value - // return the premultiplied form - return color.map((c) => c * alpha) as color; -} - -export function rectangular_un_premultiply(color: color, alpha: number): color { - // given a premultiplied color in a rectangular orthogonal colorspace - // and an alpha value - // return the actual color - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c) => c / alpha) as color; -} - -export function polar_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the premultiplied form. - // the index says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color; -} - -export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the actual color. - // the hueIndex says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color; -} - -// Convenience functions can easily be defined, such as -export function hsl_premultiply(color: color, alpha: number): color { - return polar_premultiply(color, alpha, 0); -} diff --git a/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts b/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts deleted file mode 100644 index ce023047e..000000000 --- a/plugins/postcss-color-function/src/css-color-4/deltaEOK.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */ - -// Calculate deltaE OK -// simple root sum of squares -type color = [number, number, number]; -export function deltaEOK(reference: color, sample: color): number { - // Given reference and sample are both in OKLab - const [L1, a1, b1] = reference; - const [L2, a2, b2] = sample; - const ΔL = L1 - L2; - const Δa = a1 - a2; - const Δb = b1 - b2; - return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2); -} diff --git a/plugins/postcss-color-function/src/css-color-4/map-gamut.ts b/plugins/postcss-color-function/src/css-color-4/map-gamut.ts deleted file mode 100644 index 168068986..000000000 --- a/plugins/postcss-color-function/src/css-color-4/map-gamut.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { OKLCH_to_OKLab } from './conversions'; -import { deltaEOK } from './deltaEOK'; - -type color = [number, number, number]; - -export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - return binarySearchGamut(startOKLCH, toDestination, fromDestination); -} - -function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - let min = 0; - let max = startOKLCH[1]; - const current = startOKLCH; - - while (max - min > 0.0001) { - const clipped = clip(toDestination(current)); - const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped))); - // are we inside the gamut (or very close to the boundary, outside) - if (deltaE - 0.02 < 0.0001) { - min = current[1]; - } else { - max = current[1]; - } - // binary search - current[1] = (max + min) / 2; - } - - return clip(toDestination([...current])); -} - -export function clip(color: color): color { - return color.map(val => { - if (val < 0) { - return 0; - } else if (val > 1) { - return 1; - } else { - return val; - } - }) as color; -} - -export function inGamut(x: color): boolean { - const [xX, xY, xZ] = x; - return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001; -} - diff --git a/plugins/postcss-color-function/src/css-color-4/utilities.ts b/plugins/postcss-color-function/src/css-color-4/utilities.ts deleted file mode 100644 index b3c4368cd..000000000 --- a/plugins/postcss-color-function/src/css-color-4/utilities.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ - -import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions'; - -type color = [number, number, number]; - -// utility functions for color conversions -// needs conversions.js - -export function sRGB_to_luminance(RGB: color): number { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ - // and return luminance (the Y value) - - const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB)); - return XYZ[1]; -} - -export function contrast(RGB1: color, RGB2: color): number { - // return WCAG 2.1 contrast ratio - // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio - // for two sRGB values - // given as arrays of 0.0 to 1.0 - - const L1 = sRGB_to_luminance(RGB1); - const L2 = sRGB_to_luminance(RGB2); - - if (L1 > L2) { - return (L1 + 0.05) / (L2 + 0.05); - } - - return (L2 + 0.05) / (L1 + 0.05); -} - -export function sRGB_to_LCH(RGB: color): color { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB))))); -} - -export function P3_to_LCH(RGB: color): color { - // convert an array of gamma-corrected display-p3 values - // in the 0.0 to 1.0 range - // to linear-light display-p3, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB))))); -} - -export function r2020_to_LCH(RGB: color): color { - // convert an array of gamma-corrected rec.2020 values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB))))); -} - -export function LCH_to_sRGB(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light sRGB - // and finally to gamma corrected sRGB - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_P3(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light display-p3 - // and finally to gamma corrected display-p3 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_r2020(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light rec.2020 - // and finally to gamma corrected rec.2020 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -// this is straight from the CSS Color 4 spec - -export function hslToRgb(hsl: color): color { - // For simplicity, this algorithm assumes that the hue has been normalized - // to a number in the half-open range [0, 6), and the saturation and lightness - // have been normalized to the range [0, 1]. It returns an array of three numbers - // representing the red, green, and blue channels of the colors, - // normalized to the range [0, 1] - const [hue, sat, light] = hsl; - - let t2: number; - if (light <= .5) { - t2 = light * (sat + 1); - } else { - t2 = light + sat - (light * sat); - } - const t1 = light * 2 - t2; - const r = hueToRgb(t1, t2, hue + 2); - const g = hueToRgb(t1, t2, hue); - const b = hueToRgb(t1, t2, hue - 2); - return [r, g, b]; -} - -export function hueToRgb(t1: number, t2: number, hue: number): number { - if (hue < 0) { - hue += 6; - } - if (hue >= 6) { - hue -= 6; - } - - if (hue < 1) { - return (t2 - t1) * hue + t1; - } else if (hue < 3) { - return t2; - } else if (hue < 4) { - return (t2 - t1) * (4 - hue) + t1; - } else { - return t1; - } -} - -// These are the naive algorithms from CS Color 4 - -export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color { - // CMYK is an array of four values - // in the range [0.0, 1.0] - // the optput is an array of [RGB] - // also in the [0.0, 1.0] range - // because the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3]; - - const red = 1 - Math.min(1, cyan * (1 - black) + black); - const green = 1 - Math.min(1, magenta * (1 - black) + black); - const blue = 1 - Math.min(1, yellow * (1 - black) + black); - - return [red, green, blue]; - -} - -export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] { - // RGB is an arravy of three values - // in the range [0.0, 1.0] - // the output is an array of [CMYK] - // also in the [0.0, 1.0] range - // with maximum GCR and (I think) 200% TAC - // the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const red = RGB[0], green = RGB[1], blue = RGB[2]; - - const black = 1 - Math.max(red, green, blue); - const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black); - const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black); - const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black); - - return [cyan, magenta, yellow, black]; -} - -// Chromaticity utilities - -export function XYZ_to_xy(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to x,y chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const sum = X + Y + Z; - return [X / sum, Y / sum]; -} - -export function xy_to_uv(xy: [number, number]): [number, number] { - // convert an x,y chromaticity pair - // to u*,v* chromaticities - - const x = xy[0]; - const y = xy[1]; - const denom = -2 * x + 12 * y + 3; - return [4 * x / denom, 9 * y / denom]; -} - -export function XYZ_to_uv(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to u*,v* chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const denom = X + 15 * Y + 3 * Z; - return [4 * X / denom, 9 * Y / denom]; -} diff --git a/plugins/postcss-color-function/src/on-css-function.ts b/plugins/postcss-color-function/src/on-css-function.ts index f02f1a768..05a3ecfdf 100644 --- a/plugins/postcss-color-function/src/on-css-function.ts +++ b/plugins/postcss-color-function/src/on-css-function.ts @@ -1,15 +1,7 @@ import type { Declaration, Result } from 'postcss'; import type { FunctionNode, Dimension, Node, DivNode, WordNode } from 'postcss-value-parser'; import valueParser from 'postcss-value-parser'; -import { a98RgbToSRgb } from './convert-a98-rgb-to-srgb'; -import { cieXyz50ToSRgb } from './convert-cie-xyz-50-to-srgb'; -import { cieXyz65ToSRgb } from './convert-cie-xyz-65-to-srgb'; -import { displayP3ToSRgb } from './convert-display-p3-to-srgb'; -import { prophotoRgbToSRgb } from './convert-prophoto-rgb-to-srgb'; -import { rec2020ToSRgb } from './convert-rec2020-to-srgb'; -import { sRgbLinearToSRgb } from './convert-srgb-linear-to-srgb'; -import { sRgbToSRgb } from './convert-srgb-to-srgb'; -import { inGamut } from './css-color-4/map-gamut'; +import { conversions, utils } from '@csstools/color-helpers'; export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result: Result, preserve: boolean) { const originalForWarnings = valueParser.stringify(node); @@ -38,31 +30,31 @@ export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result: let toRGB: (x: [number, number, number]) => [number, number, number]; switch (nodes.colorSpace) { case 'srgb': - toRGB = sRgbToSRgb; + toRGB = conversions.sRGB_to_sRGB; break; case 'srgb-linear': - toRGB = sRgbLinearToSRgb; + toRGB = conversions.sRGB_linear_to_sRGB; break; case 'a98-rgb': - toRGB = a98RgbToSRgb; + toRGB = conversions.a98_RGB_to_sRGB; break; case 'prophoto-rgb': - toRGB = prophotoRgbToSRgb; + toRGB = conversions.proPhoto_RGB_to_sRGB; break; case 'display-p3': - toRGB = displayP3ToSRgb; + toRGB = conversions.p3_to_sRGB; break; case 'rec2020': - toRGB = rec2020ToSRgb; + toRGB = conversions.rec_2020_to_sRGB; break; case 'xyz-d50': - toRGB = cieXyz50ToSRgb; + toRGB = conversions.cie_XYZ_50_to_sRGB; break; case 'xyz-d65': - toRGB = cieXyz65ToSRgb; + toRGB = conversions.cie_XYZ_65_to_sRGB; break; case 'xyz': - toRGB = cieXyz65ToSRgb; + toRGB = conversions.cie_XYZ_65_to_sRGB; break; default: return; @@ -77,7 +69,7 @@ export function onCSSFunctionSRgb(node: FunctionNode, decl: Declaration, result: channelNumbers, ); - if (!inGamut(channelNumbers) && preserve) { + if (!utils.inGamut(channelNumbers) && preserve) { decl.warn( result, `"${originalForWarnings}" is out of gamut for "${nodes.colorSpace}". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`, diff --git a/plugins/postcss-color-function/test/basic.expect.css b/plugins/postcss-color-function/test/basic.expect.css index f38be16f0..c4dc2cb9a 100644 --- a/plugins/postcss-color-function/test/basic.expect.css +++ b/plugins/postcss-color-function/test/basic.expect.css @@ -163,7 +163,7 @@ .test-out-of-range-values-srgb { color-1: rgb(128,0,255); color-2: rgb(125,0,245); - color-3: rgb(25,255,26); + color-3: rgb(25,255,25); color-4: rgb(159,255,151); } diff --git a/plugins/postcss-color-function/test/basic.preserve-true.expect.css b/plugins/postcss-color-function/test/basic.preserve-true.expect.css index 1eb0f0573..b0322787b 100644 --- a/plugins/postcss-color-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-function/test/basic.preserve-true.expect.css @@ -223,7 +223,7 @@ color-1: color(srgb 0.5 0 1); color-2: rgb(125,0,245); color-2: color(srgb 0.5 -0.2 1); - color-3: rgb(25,255,26); + color-3: rgb(25,255,25); color-3: color(srgb 0.1 1 0.1); color-4: rgb(159,255,151); color-4: color(srgb 0.1 1.1 0.1); diff --git a/plugins/postcss-hwb-function/CHANGELOG.md b/plugins/postcss-hwb-function/CHANGELOG.md index 8fa1b67d9..d077b2312 100644 --- a/plugins/postcss-hwb-function/CHANGELOG.md +++ b/plugins/postcss-hwb-function/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS HWB Function +### Unreleased (minor) + +- Add: `@csstools/color-helpers` dependency for all color value transformations. + ### 2.0.1 (January 28, 2023) - Improve `types` declaration in `package.json` diff --git a/plugins/postcss-hwb-function/dist/hwb.d.ts b/plugins/postcss-hwb-function/dist/hwb.d.ts deleted file mode 100644 index 0429dd937..000000000 --- a/plugins/postcss-hwb-function/dist/hwb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function hwbToRgb(hwb: color): color; -export {}; diff --git a/plugins/postcss-hwb-function/dist/index.cjs b/plugins/postcss-hwb-function/dist/index.cjs index 1d410ba17..f3d085e04 100644 --- a/plugins/postcss-hwb-function/dist/index.cjs +++ b/plugins/postcss-hwb-function/dist/index.cjs @@ -1 +1 @@ -"use strict";var e=require("postcss-value-parser");function hasSupportsAtRuleAncestor(e){let n=e.parent;for(;n;)if("atrule"===n.type){if("supports"===n.name.toLowerCase()&&-1!==n.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;n=n.parent}else n=n.parent;return!1}function hwbToRgb(e){const n=e[0];let r=e[1],t=e[2];if(r/=100,t/=100,r+t>=1){const e=r/(r+t);return[e,e,e].map((e=>Math.round(255*e)))}const o=hslToRgb([n,100,50]);for(let e=0;e<3;e++)o[e]*=1-r-t,o[e]+=r;return o.map((e=>Math.round(255*e)))}function hslToRgb(e){let n=e[0],r=e[1],t=e[2];function f(e){const o=(e+n/30)%12,u=r*Math.min(t,1-t);return t-u*Math.max(-1,Math.min(o-3,9-o,1))}return n%=360,n<0&&(n+=360),r/=100,t/=100,[f(0),f(8),f(4)]}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),r=hwbFunctionContents(n);if(!r)return;if(n.length>3&&(!r.slash||!r.alpha))return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[t,o,u]=[(i=r).hNode,i.wNode,i.bNode];var i;const[a,s,c]=channelDimensions(r),l=hwbToRgb([a.number,s.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(t)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,t,{...t,value:String(l[0])}),replaceWith(e.nodes,o,{...o,value:String(l[1])}),replaceWith(e.nodes,u,{...u,value:String(l[2])})}function isNumericNode(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&!!r.number}function isNumericNodeHueLike(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(n){if(!isNumericNodeHueLike(n[0]))return null;if(!isNumericNodePercentageOrNumber(n[1]))return null;if(!isNumericNodePercentageOrNumber(n[2]))return null;const r={h:e.unit(n[0].value),hNode:n[0],w:e.unit(n[1].value),wNode:n[1],b:e.unit(n[2].value),bNode:n[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(normalizeBlackOrWhiteNode(r.w),normalizeBlackOrWhiteNode(r.b),(t=n[3])&&"div"===t.type&&"/"===t.value&&(r.slash=n[3]),(isNumericNodePercentageOrNumber(n[4])||isCalcNode(n[4])||isVarNode(n[4]))&&(r.alpha=n[4]),r);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(n,r,t){if(!r||!t)return;if(n.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(n){if(!n||!n.value)return!1;try{return!1!==e.unit(n.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(n,r,t){let o;try{o=e(n)}catch(e){r.warn(t,`Failed to parse value '${n}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==n?u:void 0}function insertAtSupportsAfterCorrectRule(e,n,r){let t=n,o=n.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===r;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0,module.exports=postcssPlugin; +"use strict";var e=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasSupportsAtRuleAncestor(e){let r=e.parent;for(;r;)if("atrule"===r.type){if("supports"===r.name.toLowerCase()&&-1!==r.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;r=r.parent}else r=r.parent;return!1}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),t=hwbFunctionContents(n);if(!t)return;if(n.length>3&&(!t.slash||!t.alpha))return;e.value="rgb",transformAlpha(e,t.slash,t.alpha);const[o,u,i]=[(a=t).hNode,a.wNode,a.bNode];var a;const[s,c,l]=channelDimensions(t),p=[s.number,c.number,l.number].map((e=>parseFloat(e))),d=r.conversions.HWB_to_sRGB(p).map((e=>Math.round(255*e)));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,i,{...i,value:String(d[2])})}function isNumericNode(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&!!n.number}function isNumericNodeHueLike(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);if(!n)return!1;const t=n.unit.toLowerCase();return!!n.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(r){if(!isNumericNodeHueLike(r[0]))return null;if(!isNumericNodePercentageOrNumber(r[1]))return null;if(!isNumericNodePercentageOrNumber(r[2]))return null;const n={h:e.unit(r[0].value),hNode:r[0],w:e.unit(r[1].value),wNode:r[1],b:e.unit(r[2].value),bNode:r[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(normalizeBlackOrWhiteNode(n.w),normalizeBlackOrWhiteNode(n.b),(t=r[3])&&"div"===t.type&&"/"===t.value&&(n.slash=r[3]),(isNumericNodePercentageOrNumber(r[4])||isCalcNode(r[4])||isVarNode(r[4]))&&(n.alpha=r[4]),n);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(r,n,t){if(!n||!t)return;if(r.value="rgba",n.value=",",n.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,r,n){const t=e.indexOf(r);e[t]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(r){if(!r||!r.value)return!1;try{return!1!==e.unit(r.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(r,n,t){let o;try{o=e(r)}catch(e){n.warn(t,`Failed to parse value '${r}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==r?u:void 0}function insertAtSupportsAfterCorrectRule(e,r,n){let t=r,o=r.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===n;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0,module.exports=postcssPlugin; diff --git a/plugins/postcss-hwb-function/dist/index.mjs b/plugins/postcss-hwb-function/dist/index.mjs index a2ed994a3..77527c1f7 100644 --- a/plugins/postcss-hwb-function/dist/index.mjs +++ b/plugins/postcss-hwb-function/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";function hasSupportsAtRuleAncestor(e){let n=e.parent;for(;n;)if("atrule"===n.type){if("supports"===n.name.toLowerCase()&&-1!==n.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;n=n.parent}else n=n.parent;return!1}function hwbToRgb(e){const n=e[0];let r=e[1],t=e[2];if(r/=100,t/=100,r+t>=1){const e=r/(r+t);return[e,e,e].map((e=>Math.round(255*e)))}const o=hslToRgb([n,100,50]);for(let e=0;e<3;e++)o[e]*=1-r-t,o[e]+=r;return o.map((e=>Math.round(255*e)))}function hslToRgb(e){let n=e[0],r=e[1],t=e[2];function f(e){const o=(e+n/30)%12,u=r*Math.min(t,1-t);return t-u*Math.max(-1,Math.min(o-3,9-o,1))}return n%=360,n<0&&(n+=360),r/=100,t/=100,[f(0),f(8),f(4)]}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),r=hwbFunctionContents(n);if(!r)return;if(n.length>3&&(!r.slash||!r.alpha))return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[t,o,u]=[(i=r).hNode,i.wNode,i.bNode];var i;const[a,s,c]=channelDimensions(r),l=hwbToRgb([a.number,s.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(t)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,t,{...t,value:String(l[0])}),replaceWith(e.nodes,o,{...o,value:String(l[1])}),replaceWith(e.nodes,u,{...u,value:String(l[2])})}function isNumericNode(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&!!r.number}function isNumericNodeHueLike(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(n){if(!n||"word"!==n.type)return!1;if(!canParseAsUnit(n))return!1;const r=e.unit(n.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(n){if(!isNumericNodeHueLike(n[0]))return null;if(!isNumericNodePercentageOrNumber(n[1]))return null;if(!isNumericNodePercentageOrNumber(n[2]))return null;const r={h:e.unit(n[0].value),hNode:n[0],w:e.unit(n[1].value),wNode:n[1],b:e.unit(n[2].value),bNode:n[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(normalizeBlackOrWhiteNode(r.w),normalizeBlackOrWhiteNode(r.b),(t=n[3])&&"div"===t.type&&"/"===t.value&&(r.slash=n[3]),(isNumericNodePercentageOrNumber(n[4])||isCalcNode(n[4])||isVarNode(n[4]))&&(r.alpha=n[4]),r);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(n,r,t){if(!r||!t)return;if(n.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(n){if(!n||!n.value)return!1;try{return!1!==e.unit(n.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(n,r,t){let o;try{o=e(n)}catch(e){r.warn(t,`Failed to parse value '${n}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==n?u:void 0}function insertAtSupportsAfterCorrectRule(e,n,r){let t=n,o=n.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===r;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0;export{postcssPlugin as default}; +import e from"postcss-value-parser";import{conversions as r}from"@csstools/color-helpers";function hasSupportsAtRuleAncestor(e){let r=e.parent;for(;r;)if("atrule"===r.type){if("supports"===r.name.toLowerCase()&&-1!==r.params.toLowerCase().indexOf("(color: hwb(0% 0 0))"))return!0;r=r.parent}else r=r.parent;return!1}function onCSSFunctionSRgb(e){const n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type)),t=hwbFunctionContents(n);if(!t)return;if(n.length>3&&(!t.slash||!t.alpha))return;e.value="rgb",transformAlpha(e,t.slash,t.alpha);const[o,u,i]=[(a=t).hNode,a.wNode,a.bNode];var a;const[s,c,l]=channelDimensions(t),p=[s.number,c.number,l.number].map((e=>parseFloat(e))),d=r.HWB_to_sRGB(p).map((e=>Math.round(255*e)));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,i,{...i,value:String(d[2])})}function isNumericNode(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&!!n.number}function isNumericNodeHueLike(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);if(!n)return!1;const t=n.unit.toLowerCase();return!!n.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(r){if(!r||"word"!==r.type)return!1;if(!canParseAsUnit(r))return!1;const n=e.unit(r.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function hwbFunctionContents(r){if(!isNumericNodeHueLike(r[0]))return null;if(!isNumericNodePercentageOrNumber(r[1]))return null;if(!isNumericNodePercentageOrNumber(r[2]))return null;const n={h:e.unit(r[0].value),hNode:r[0],w:e.unit(r[1].value),wNode:r[1],b:e.unit(r[2].value),bNode:r[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(normalizeBlackOrWhiteNode(n.w),normalizeBlackOrWhiteNode(n.b),(t=r[3])&&"div"===t.type&&"/"===t.value&&(n.slash=r[3]),(isNumericNodePercentageOrNumber(r[4])||isCalcNode(r[4])||isVarNode(r[4]))&&(n.alpha=r[4]),n);var t}function channelDimensions(e){return[e.h,e.w,e.b]}function transformAlpha(r,n,t){if(!n||!t)return;if(r.value="rgba",n.value=",",n.before="",!isNumericNode(t))return;const o=e.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,r,n){const t=e.indexOf(r);e[t]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function normalizeBlackOrWhiteNode(e){if("%"!==e.unit)return e.unit="%",void(e.number=(100*parseFloat(e.number)).toString())}function canParseAsUnit(r){if(!r||!r.value)return!1;try{return!1!==e.unit(r.value)}catch(e){return!1}}const n="(color: hwb(0% 0 0))",postcssPlugin=e=>{const r="preserve"in Object(e)&&Boolean(e.preserve);return{postcssPlugin:"postcss-hwb-function",Declaration:(e,{result:t,postcss:o})=>{if(r&&hasSupportsAtRuleAncestor(e))return;const u=e.value;if(!u.toLowerCase().includes("hwb"))return;const i=modifiedValues(u,e,t);if(void 0!==i)if(e.variable&&r){const r=e.parent,t=o.atRule({name:"supports",params:n,source:e.source}),u=r.clone();u.removeAll(),u.append(e.clone()),t.append(u),insertAtSupportsAfterCorrectRule(t,r,n),e.replaceWith(e.clone({value:i}))}else r?e.cloneBefore({value:i}):e.replaceWith(e.clone({value:i}))}}};function modifiedValues(r,n,t){let o;try{o=e(r)}catch(e){n.warn(t,`Failed to parse value '${r}' as a hwb function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&"hwb"===e.value.toLowerCase()&&onCSSFunctionSRgb(e)}));const u=String(o);return u!==r?u:void 0}function insertAtSupportsAfterCorrectRule(e,r,n){let t=r,o=r.next();for(;t&&o&&"atrule"===o.type&&"supports"===o.name.toLowerCase()&&o.params===n;)t=o,o=o.next();t.after(e)}postcssPlugin.postcss=!0;export{postcssPlugin as default}; diff --git a/plugins/postcss-hwb-function/package.json b/plugins/postcss-hwb-function/package.json index 0defd2ef7..86e624699 100644 --- a/plugins/postcss-hwb-function/package.json +++ b/plugins/postcss-hwb-function/package.json @@ -30,6 +30,7 @@ "dist" ], "dependencies": { + "@csstools/color-helpers": "^0.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { diff --git a/plugins/postcss-hwb-function/src/hwb.ts b/plugins/postcss-hwb-function/src/hwb.ts deleted file mode 100644 index cd892e084..000000000 --- a/plugins/postcss-hwb-function/src/hwb.ts +++ /dev/null @@ -1,45 +0,0 @@ -type color = [number, number, number]; - -// source: https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hwbToRgb.js -export function hwbToRgb(hwb: color): color { - const hue = hwb[0]; - let white = hwb[1]; - let black = hwb[2]; - - white /= 100; - black /= 100; - if (white + black >= 1) { - const gray = white / (white + black); - return [gray, gray, gray].map((x) => Math.round(x * 255)) as color; - } - const rgb = hslToRgb([hue, 100, 50]); - for (let i = 0; i < 3; i++) { - rgb[i] *= (1 - white - black); - rgb[i] += white; - } - return rgb.map((x) => Math.round(x * 255)) as color; -} - -// source: https://github.com/w3c/csswg-drafts/blob/main/css-color-4/hslToRgb.js -function hslToRgb(hwb: color): color { - let hue = hwb[0]; - let sat = hwb[1]; - let light = hwb[2]; - - hue = hue % 360; - - if (hue < 0) { - hue += 360; - } - - sat /= 100; - light /= 100; - - function f(n) { - const k = (n + hue / 30) % 12; - const a = sat * Math.min(light, 1 - light); - return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); - } - - return [f(0), f(8), f(4)]; -} diff --git a/plugins/postcss-hwb-function/src/on-css-function.ts b/plugins/postcss-hwb-function/src/on-css-function.ts index 342281969..030a1c01a 100644 --- a/plugins/postcss-hwb-function/src/on-css-function.ts +++ b/plugins/postcss-hwb-function/src/on-css-function.ts @@ -1,6 +1,6 @@ import valueParser from 'postcss-value-parser'; import type { FunctionNode, Dimension, Node, DivNode, WordNode } from 'postcss-value-parser'; -import { hwbToRgb } from './hwb'; +import { conversions } from '@csstools/color-helpers'; export function onCSSFunctionSRgb(node: FunctionNode) { const rawNodes = node.nodes; @@ -35,9 +35,9 @@ export function onCSSFunctionSRgb(node: FunctionNode) { channelNumber => parseFloat(channelNumber), ) as [number, number, number]; - const rgbValues = hwbToRgb( + const rgbValues = conversions.HWB_to_sRGB( channelNumbers, - ); + ).map((x) => Math.round(x * 255)); node.nodes.splice(node.nodes.indexOf(channelNode1) + 1, 0, commaNode()); node.nodes.splice(node.nodes.indexOf(channelNode2) + 1, 0, commaNode()); diff --git a/plugins/postcss-lab-function/CHANGELOG.md b/plugins/postcss-lab-function/CHANGELOG.md index 7bd77c710..42b99c974 100644 --- a/plugins/postcss-lab-function/CHANGELOG.md +++ b/plugins/postcss-lab-function/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Lab Function +### Unreleased (minor) + +- Add: `@csstools/color-helpers` dependency for all color value transformations. + ### 5.0.1 (January 28, 2023) - Improve `types` declaration in `package.json` diff --git a/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts b/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts deleted file mode 100644 index 8ab3896e2..000000000 --- a/plugins/postcss-lab-function/dist/convert-lab-to-display-p3.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function labToDisplayP3(labRaw: color): [color, boolean]; -export {}; diff --git a/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts b/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts deleted file mode 100644 index a2cc12cce..000000000 --- a/plugins/postcss-lab-function/dist/convert-lab-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function labToSRgb(labRaw: color): color; -export {}; diff --git a/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts b/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts deleted file mode 100644 index 5d2040b60..000000000 --- a/plugins/postcss-lab-function/dist/convert-lch-to-display-p3.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function lchToDisplayP3(lchRaw: color): [color, boolean]; -export {}; diff --git a/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts b/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts deleted file mode 100644 index 2ebf9f7fd..000000000 --- a/plugins/postcss-lab-function/dist/convert-lch-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function lchToSRgb(lchRaw: color): color; -export {}; diff --git a/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts deleted file mode 100644 index a48b1e5bc..000000000 --- a/plugins/postcss-lab-function/dist/css-color-4/conversions.d.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ -type color = [number, number, number]; -export declare const D50: number[]; -export declare const D65: number[]; -export declare function lin_sRGB(RGB: color): color; -export declare function gam_sRGB(RGB: color): color; -export declare function lin_sRGB_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_sRGB(XYZ: color): color; -export declare function lin_P3(RGB: color): color; -export declare function gam_P3(RGB: color): color; -export declare function lin_P3_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_P3(XYZ: color): color; -export declare function lin_ProPhoto(RGB: color): color; -export declare function gam_ProPhoto(RGB: color): color; -export declare function lin_ProPhoto_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_ProPhoto(XYZ: color): color; -export declare function lin_a98rgb(RGB: color): color; -export declare function gam_a98rgb(RGB: color): color; -export declare function lin_a98rgb_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_a98rgb(XYZ: color): color; -export declare function lin_2020(RGB: color): color; -export declare function gam_2020(RGB: color): color; -export declare function lin_2020_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_2020(XYZ: color): color; -export declare function D65_to_D50(XYZ: color): color; -export declare function D50_to_D65(XYZ: color): color; -export declare function XYZ_to_Lab(XYZ: color): color; -export declare function Lab_to_XYZ(Lab: color): color; -export declare function Lab_to_LCH(Lab: color): color; -export declare function LCH_to_Lab(LCH: color): color; -export declare function XYZ_to_OKLab(XYZ: color): color; -export declare function OKLab_to_XYZ(OKLab: color): color; -export declare function OKLab_to_OKLCH(OKLab: color): color; -export declare function OKLCH_to_OKLab(OKLCH: color): color; -export declare function rectangular_premultiply(color: color, alpha: number): color; -export declare function rectangular_un_premultiply(color: color, alpha: number): color; -export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function hsl_premultiply(color: color, alpha: number): color; -export {}; diff --git a/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts deleted file mode 100644 index d744ffaad..000000000 --- a/plugins/postcss-lab-function/dist/css-color-4/deltaEOK.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */ -type color = [number, number, number]; -export declare function deltaEOK(reference: color, sample: color): number; -export {}; diff --git a/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts deleted file mode 100644 index 1a4ee6e95..000000000 --- a/plugins/postcss-lab-function/dist/css-color-4/map-gamut.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -type color = [number, number, number]; -export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color; -export declare function clip(color: color): color; -export declare function inGamut(x: color): boolean; -export {}; diff --git a/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts b/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts deleted file mode 100644 index 3055a8245..000000000 --- a/plugins/postcss-lab-function/dist/css-color-4/multiply-matrices.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Simple matrix (and vector) multiplication - * Warning: No error handling for incompatible dimensions! - * @author Lea Verou 2020 MIT License - * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js - */ -export declare function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array; diff --git a/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts deleted file mode 100644 index a5bb9da80..000000000 --- a/plugins/postcss-lab-function/dist/css-color-4/utilities.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ -type color = [number, number, number]; -export declare function sRGB_to_luminance(RGB: color): number; -export declare function contrast(RGB1: color, RGB2: color): number; -export declare function sRGB_to_LCH(RGB: color): color; -export declare function P3_to_LCH(RGB: color): color; -export declare function r2020_to_LCH(RGB: color): color; -export declare function LCH_to_sRGB(LCH: color): color; -export declare function LCH_to_P3(LCH: color): color; -export declare function LCH_to_r2020(LCH: color): color; -export declare function hslToRgb(hsl: color): color; -export declare function hueToRgb(t1: number, t2: number, hue: number): number; -export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color; -export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number]; -export declare function XYZ_to_xy(XYZ: color): [number, number]; -export declare function xy_to_uv(xy: [number, number]): [number, number]; -export declare function XYZ_to_uv(XYZ: color): [number, number]; -export {}; diff --git a/plugins/postcss-lab-function/dist/index.cjs b/plugins/postcss-lab-function/dist/index.cjs index f510d4f3b..fc21337f0 100644 --- a/plugins/postcss-lab-function/dist/index.cjs +++ b/plugins/postcss-lab-function/dist/index.cjs @@ -1,29 +1 @@ -"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),t=require("postcss-value-parser");function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let a=0;a[e])));const o=r[0].length,u=r[0].map(((e,t)=>r.map((e=>e[t]))));let i=a.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,a)=>e+n*(t[a]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===o?i.map((e=>e[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */const n=[.3457/.3585,1,.2958/.3585];function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function D50_to_D65(e){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],e)}function Lab_to_XYZ(e){const t=24389/27,a=216/24389,r=[];r[1]=(e[0]+16)/116,r[0]=e[1]/500+r[1],r[2]=r[1]-e[2]/200;return[Math.pow(r[0],3)>a?Math.pow(r[0],3):(116*r[0]-16)/t,e[0]>8?Math.pow((e[0]+16)/116,3):e[0]/t,Math.pow(r[2],3)>a?Math.pow(r[2],3):(116*r[2]-16)/t].map(((e,t)=>e*n[t]))}function LCH_to_Lab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(e,t){const[n,a,r]=e,[o,u,i]=t,s=n-o,l=a-u,c=r-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let a=0,r=e[1];const o=e;for(;r-a>1e-4;){const e=clip(t(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(n(e)))-.02<1e-4?a=o[1]:r=o[1],o[1]=(r+a)/2}return clip(t([...o]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,a]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&a>=-1e-4&&a<=1.0001}function labToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function labToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function lchToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function lchToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let a=null;if("lab"===t?a=labFunctionContents(n):"lch"===t&&(a=lchFunctionContents(n)),!a)return;e.value="rgb",transformAlpha(e,a.slash,a.alpha);const[r,o,u]=channelNodes(a),[i,s,l]=channelDimensions(a),c=("lab"===t?labToSRgb:lchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(r)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,r,{...r,value:String(c[0])}),replaceWith(e.nodes,o,{...o,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,a,r){const o=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("lab"===u?s=labFunctionContents(i):"lch"===u&&(s=lchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,_]=channelNodes(s),[p,m,b]=channelDimensions(s),d="lab"===u?labToDisplayP3:lchToDisplayP3,f=[p.number,m.number,b.number].map((e=>parseFloat(e))),[h,L]=d(f);!L&&r&&n.warn(a,`"${o}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,_,{..._,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const a=n.unit.toLowerCase();return!!n.number&&("deg"===a||"grad"===a||"rad"===a||"turn"===a||""===a)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*150).toFixed(10)),n):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*125).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*125).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,a){if(!n||!a)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(a))return;const r=t.unit(a.value);r&&"%"===r.unit&&(r.number=String(parseFloat(r.number)/100),a.value=String(r.number))}function replaceWith(e,t,n){const a=e.indexOf(t);e[a]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,a,r){let o;try{o=t(e)}catch(t){n.warn(a,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(o);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,a,r))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const a=t.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(a.toLowerCase()))return;const r=modifiedValues(a,t,n,e.preserve);void 0!==r&&(e.preserve?(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3})):(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; +"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),n=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("lab"===n?o=labFunctionContents(t):"lch"===n&&(o=lchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[s,u,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("lab"===n?r.conversions.Lab_to_sRGB:r.conversions.LCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,s,{...s,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,s){const u=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("lab"===a?l=labFunctionContents(i):"lch"===a&&(l=lchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,v]=channelDimensions(l),m="lab"===a?r.conversions.Lab_to_P3:r.conversions.LCH_to_P3,h=[f.number,b.number,v.number].map((e=>parseFloat(e))),[N,g]=m(h);!g&&s&&t.warn(o,`"${u}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit=""),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*150).toFixed(10)),r):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit=""),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*125).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*125).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let s;try{s=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(s);if(u===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:u,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; diff --git a/plugins/postcss-lab-function/dist/index.mjs b/plugins/postcss-lab-function/dist/index.mjs index 9657cd879..de1161a86 100644 --- a/plugins/postcss-lab-function/dist/index.mjs +++ b/plugins/postcss-lab-function/dist/index.mjs @@ -1,29 +1 @@ -import e from"@csstools/postcss-progressive-custom-properties";import t from"postcss-value-parser";function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let a=0;a[e])));const o=r[0].length,u=r[0].map(((e,t)=>r.map((e=>e[t]))));let i=a.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,a)=>e+n*(t[a]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===o?i.map((e=>e[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */const n=[.3457/.3585,1,.2958/.3585];function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function D50_to_D65(e){return multiplyMatrices([[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]],e)}function Lab_to_XYZ(e){const t=24389/27,a=216/24389,r=[];r[1]=(e[0]+16)/116,r[0]=e[1]/500+r[1],r[2]=r[1]-e[2]/200;return[Math.pow(r[0],3)>a?Math.pow(r[0],3):(116*r[0]-16)/t,e[0]>8?Math.pow((e[0]+16)/116,3):e[0]/t,Math.pow(r[2],3)>a?Math.pow(r[2],3):(116*r[2]-16)/t].map(((e,t)=>e*n[t]))}function LCH_to_Lab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(e,t){const[n,a,r]=e,[o,u,i]=t,s=n-o,l=a-u,c=r-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let a=0,r=e[1];const o=e;for(;r-a>1e-4;){const e=clip(t(o));deltaEOK(OKLCH_to_OKLab(o),OKLCH_to_OKLab(n(e)))-.02<1e-4?a=o[1]:r=o[1],o[1]=(r+a)/2}return clip(t([...o]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,a]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&a>=-1e-4&&a<=1.0001}function labToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function labToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),Math.min(Math.max(n,-160),160),Math.min(Math.max(a,-160),160)];r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function lchToDisplayP3(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_P3(r),r=gam_P3(r),inGamut(r)?[clip(r),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function lchToSRgb(e){const[t,n,a]=e;let r=[Math.max(t,0),n,a%360];r=LCH_to_Lab(r),r=Lab_to_XYZ(r);let o=r.slice();return o=D50_to_D65(o),o=XYZ_to_OKLab(o),o=OKLab_to_OKLCH(o),o[0]<1e-6&&(o=[0,0,0]),o[0]>.999999&&(o=[1,0,0]),r=D50_to_D65(r),r=XYZ_to_lin_sRGB(r),r=gam_sRGB(r),inGamut(r)?clip(r).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let a=null;if("lab"===t?a=labFunctionContents(n):"lch"===t&&(a=lchFunctionContents(n)),!a)return;e.value="rgb",transformAlpha(e,a.slash,a.alpha);const[r,o,u]=channelNodes(a),[i,s,l]=channelDimensions(a),c=("lab"===t?labToSRgb:lchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(r)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,r,{...r,value:String(c[0])}),replaceWith(e.nodes,o,{...o,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,a,r){const o=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("lab"===u?s=labFunctionContents(i):"lch"===u&&(s=lchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,_]=channelNodes(s),[p,m,b]=channelDimensions(s),d="lab"===u?labToDisplayP3:lchToDisplayP3,f=[p.number,m.number,b.number].map((e=>parseFloat(e))),[h,L]=d(f);!L&&r&&n.warn(a,`"${o}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,_,{..._,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const a=n.unit.toLowerCase();return!!n.number&&("deg"===a||"grad"===a||"rad"===a||"turn"===a||""===a)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*150).toFixed(10)),n):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit=""),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*125).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*125).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,a){if(!n||!a)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(a))return;const r=t.unit(a.value);r&&"%"===r.unit&&(r.number=String(parseFloat(r.number)/100),a.value=String(r.number))}function replaceWith(e,t,n){const a=e.indexOf(t);e[a]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,a,r){let o;try{o=t(e)}catch(t){n.warn(a,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===o)return;o.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(o);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,a,r))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const a=t.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(a.toLowerCase()))return;const r=modifiedValues(a,t,n,e.preserve);void 0!==r&&(e.preserve?(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3})):(t.cloneBefore({value:r.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:r.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; +import e from"@csstools/postcss-progressive-custom-properties";import n from"postcss-value-parser";import{conversions as t}from"@csstools/color-helpers";function hasFallback(e){const n=e.parent;if(!n)return!1;const t=n.index(e);for(let r=0;r"comment"!==e.type&&"space"!==e.type));let o=null;if("lab"===n?o=labFunctionContents(r):"lch"===n&&(o=lchFunctionContents(r)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[u,s,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("lab"===n?t.Lab_to_sRGB:t.LCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,u,{...u,value:String(d[0])}),replaceWith(e.nodes,s,{...s,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,r,o,u){const s=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("lab"===a?l=labFunctionContents(i):"lch"===a&&(l=lchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,m]=channelDimensions(l),v="lab"===a?t.Lab_to_P3:t.LCH_to_P3,h=[f.number,b.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&u&&r.warn(o,`"${s}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);return!!t&&!!t.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);if(!t)return!1;const r=t.unit.toLowerCase();return!!t.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const t=n.unit(e.value);return!!t&&("%"===t.unit||""===t.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function lchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const t={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(t.h),""!==t.h.unit?null:(isSlashNode(e[3])&&(t.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(t.alpha=e[4]),!(e.length>3)||t.slash&&t.alpha?("%"===t.l.unit&&(t.l.unit=""),"%"===t.c.unit&&(t.c.unit="",t.c.number=(parseFloat(t.c.number)/100*150).toFixed(10)),t):null)}function labFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const t={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(t.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(t.alpha=e[4]),!(e.length>3)||t.slash&&t.alpha?("%"===t.l.unit&&(t.l.unit=""),"%"===t.a.unit&&(t.a.unit="",t.a.number=(parseFloat(t.a.number)/100*125).toFixed(10)),"%"===t.b.unit&&(t.b.unit="",t.b.number=(parseFloat(t.b.number)/100*125).toFixed(10)),t):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,t,r){if(!t||!r)return;if(e.value="rgba",t.value=",",t.before="",!isNumericNode(r))return;const o=n.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,n,t){const r=e.indexOf(n);e[r]=t}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,t,r,o){let u;try{u=n(e)}catch(n){t.warn(r,`Failed to parse value '${e}' as a lab or lch function. Leaving the original value intact.`)}if(void 0===u)return;u.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const s=String(u);if(s===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("lab"!==e.value.toLowerCase()&&"lch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,t,r,o))}));return{rgb:s,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-lab-function",Declaration:(n,{result:t})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const r=n.value;if(!/(^|[^\w-])(lab|lch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,n,t,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const t=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return t.subFeatures=Object.assign({displayP3:!0},t.subFeatures),t.enableProgressiveCustomProperties&&(t.preserve||t.subFeatures.displayP3)?{postcssPlugin:"postcss-lab-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; diff --git a/plugins/postcss-lab-function/package.json b/plugins/postcss-lab-function/package.json index ca2e15cdd..213d64493 100644 --- a/plugins/postcss-lab-function/package.json +++ b/plugins/postcss-lab-function/package.json @@ -29,6 +29,7 @@ "dist" ], "dependencies": { + "@csstools/color-helpers": "^0.0.0", "@csstools/postcss-progressive-custom-properties": "^2.0.0", "postcss-value-parser": "^4.2.0" }, diff --git a/plugins/postcss-lab-function/src/css-color-4/conversions.ts b/plugins/postcss-lab-function/src/css-color-4/conversions.ts deleted file mode 100644 index 636f08f90..000000000 --- a/plugins/postcss-lab-function/src/css-color-4/conversions.ts +++ /dev/null @@ -1,512 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ - -/* eslint-disable @typescript-eslint/no-loss-of-precision */ - -import { multiplyMatrices } from './multiply-matrices'; - -type color = [number, number, number]; - -// Sample code for color conversions -// Conversion can also be done using ICC profiles and a Color Management System -// For clarity, a library is used for matrix multiplication (multiply-matrices.js) - -// standard white points, defined by 4-figure CIE x,y chromaticities -export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585]; -export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290]; - -// sRGB-related functions - -export function lin_sRGB(RGB: color): color { - // convert an array of sRGB values - // where in-gamut values are in the range [0 - 1] - // to linear light (un-companded) form. - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // for negative values, linear portion is extended on reflection of axis, - // then reflected power function is used. - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < 0.04045) { - return val / 12.92; - } - - return sign * (Math.pow((abs + 0.055) / 1.055, 2.4)); - }) as color; -} - -export function gam_sRGB(RGB: color): color { - // convert an array of linear-light sRGB values in the range 0.0-1.0 - // to gamma corrected form - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // For negative values, linear portion extends on reflection - // of axis, then uses reflected pow below that - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > 0.0031308) { - return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055); - } - - return 12.92 * val; - }) as color; -} - -export function lin_sRGB_to_XYZ(rgb: color): color { - // convert an array of linear-light sRGB values to CIE XYZ - // using sRGB's own white, D65 (no chromatic adaptation) - - const M = [ - [0.41239079926595934, 0.357584339383878, 0.1804807884018343], - [0.21263900587151027, 0.715168678767756, 0.07219231536073371], - [0.01933081871559182, 0.11919477979462598, 0.9505321522496607], - ]; - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_sRGB(XYZ: color): color { - // convert XYZ to linear-light sRGB - - const M = [ - [3.2409699419045226, -1.537383177570094, -0.4986107602930034], - [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559], - [0.05563007969699366, -0.20397695888897652, 1.0569715142428786], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// display-p3-related functions - - -export function lin_P3(RGB: color): color { - // convert an array of display-p3 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - - return lin_sRGB(RGB); // same as sRGB -} - -export function gam_P3(RGB: color): color { - // convert an array of linear-light display-p3 RGB in the range 0.0-1.0 - // to gamma corrected form - - return gam_sRGB(RGB); // same as sRGB -} - -export function lin_P3_to_XYZ(rgb: color): color { - // convert an array of linear-light display-p3 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.4865709486482162, 0.26566769316909306, 0.1982172852343625], - [0.2289745640697488, 0.6917385218365064, 0.079286914093745], - [0.0000000000000000, 0.04511338185890264, 1.043944368900976], - ]; - // 0 was computed as -3.972075516933488e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_P3(XYZ: color): color { - // convert XYZ to linear-light P3 - const M = [ - [2.493496911941425, -0.9313836179191239, -0.40271078445071684], - [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577], - [0.03584583024378447, -0.07617238926804182, 0.9568845240076872], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// prophoto-rgb functions - -export function lin_ProPhoto(RGB: color): color { - // convert an array of prophoto-rgb values - // where in-gamut colors are in the range [0.0 - 1.0] - // to linear light (un-companded) form. - // Transfer curve is gamma 1.8 with a small linear portion - // Extended transfer function - const Et2 = 16 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs <= Et2) { - return val / 16; - } - - return sign * Math.pow(val, 1.8); - }) as color; -} - -export function gam_ProPhoto(RGB: color): color { - // convert an array of linear-light prophoto-rgb in the range 0.0-1.0 - // to gamma corrected form - // Transfer curve is gamma 1.8 with a small linear portion - // TODO for negative values, extend linear portion on reflection of axis, then add pow below that - const Et = 1 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs >= Et) { - return sign * Math.pow(abs, 1 / 1.8); - } - - return 16 * val; - }) as color; -} - -export function lin_ProPhoto_to_XYZ(rgb: color): color { - // convert an array of linear-light prophoto-rgb values to CIE XYZ - // using D50 (so no chromatic adaptation needed afterwards) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.7977604896723027, 0.13518583717574031, 0.0313493495815248], - [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902], - [0.0, 0.0, 0.8251046025104601], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_ProPhoto(XYZ: color): color { - // convert XYZ to linear-light prophoto-rgb - const M = [ - [1.3457989731028281, -0.25558010007997534, -0.05110628506753401], - [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973], - [0.0, 0.0, 1.2119675456389454], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// a98-rgb functions - -export function lin_a98rgb(RGB: color): color { - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 563 / 256); - }) as color; -} - -export function gam_a98rgb(RGB: color): color { - // convert an array of linear-light a98-rgb in the range 0.0-1.0 - // to gamma corrected form - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 256 / 563); - }) as color; -} - -export function lin_a98rgb_to_XYZ(rgb: color): color { - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - const M = [ - [0.5766690429101305, 0.1855582379065463, 0.1882286462349947], - [0.29734497525053605, 0.6273635662554661, 0.07529145849399788], - [0.02703136138641234, 0.07068885253582723, 0.9913375368376388], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_a98rgb(XYZ: color): color { - // convert XYZ to linear-light a98-rgb - const M = [ - [2.0415879038107465, -0.5650069742788596, -0.34473135077832956], - [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557], - [0.013444280632031142, -0.11836239223101838, 1.0151749943912054], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -//Rec. 2020-related functions - -export function lin_2020(RGB: color): color { - // convert an array of rec2020 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < β * 4.5) { - return val / 4.5; - } - - return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }) as color; -} - -export function gam_2020(RGB: color): color { - // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 - // to gamma corrected form - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > β) { - return sign * (α * Math.pow(abs, 0.45) - (α - 1)); - } - - return 4.5 * val; - }) as color; -} - -export function lin_2020_to_XYZ(rgb: color): color { - // convert an array of linear-light rec2020 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.6369580483012914, 0.14461690358620832, 0.1688809751641721], - [0.2627002120112671, 0.6779980715188708, 0.05930171646986196], - [0.000000000000000, 0.028072693049087428, 1.060985057710791], - ]; - // 0 is actually calculated as 4.994106574466076e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_2020(XYZ: color): color { - // convert XYZ to linear-light rec2020 - const M = [ - [1.7166511879712674, -0.35567078377639233, -0.25336628137365974], - [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113], - [0.017639857445310783, -0.042770613257808524, 0.9421031212354738], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// Chromatic adaptation - -export function D65_to_D50(XYZ: color): color { - // Bradford chromatic adaptation from D65 to D50 - // The matrix below is the result of three operations: - // - convert from XYZ to retinal cone domain - // - scale components from one reference white to another - // - convert back to XYZ - // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html - const M = [ - [1.0479298208405488, 0.022946793341019088, -0.05019222954313557], - [0.029627815688159344, 0.990434484573249, -0.01707382502938514], - [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -export function D50_to_D65(XYZ: color): color { - // Bradford chromatic adaptation from D50 to D65 - const M = [ - [0.9554734527042182, -0.023098536874261423, 0.0632593086610217], - [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008], - [0.012314001688319899, -0.020507696433477912, 1.3303659366080753], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// CIE Lab and LCH - -export function XYZ_to_Lab(XYZ: color): color { - // Assuming XYZ is relative to D50, convert to CIE Lab - // from CIE standard, which now defines these as a rational fraction - const ε = 216 / 24389; // 6^3/29^3 - const κ = 24389 / 27; // 29^3/3^3 - - // compute xyz, which is XYZ scaled relative to reference white - const xyz = XYZ.map((value, i) => value / D50[i]); - - // now compute f - const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116); - - return [ - (116 * f[1]) - 16, // L - 500 * (f[0] - f[1]), // a - 200 * (f[1] - f[2]), // b - ]; - // L in range [0,100]. For use in CSS, add a percent -} - -export function Lab_to_XYZ(Lab: color): color { - // Convert Lab to D50-adapted XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const κ = 24389 / 27; // 29^3/3^3 - const ε = 216 / 24389; // 6^3/29^3 - const f = []; - - // compute f, starting with the luminance-related term - f[1] = (Lab[0] + 16) / 116; - f[0] = Lab[1] / 500 + f[1]; - f[2] = f[1] - Lab[2] / 200; - - // compute xyz - const xyz = [ - Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ, - Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ, - Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ, - ]; - - // Compute XYZ by scaling xyz by reference white - return xyz.map((value, i) => value * D50[i]) as color; -} - -export function Lab_to_LCH(Lab: color): color { - // Convert to polar form - const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI; - return [ - Lab[0], // L is still L - Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function LCH_to_Lab(LCH: color): color { - // Convert from polar form - return [ - LCH[0], // L is still L - LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a - LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b - ]; -} - -// OKLab and OKLCH -// https://bottosson.github.io/posts/oklab/ - -// XYZ <-> LMS matrices recalculated for consistent reference white -// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 - -export function XYZ_to_OKLab(XYZ: color): color { - // Given XYZ relative to D65, convert to OKLab - const XYZtoLMS = [ - [0.8190224432164319, 0.3619062562801221, -0.12887378261216414], - [0.0329836671980271, 0.9292868468965546, 0.03614466816999844], - [0.048177199566046255, 0.26423952494422764, 0.6335478258136937], - ]; - const LMStoOKLab = [ - [0.2104542553, 0.7936177850, -0.0040720468], - [1.9779984951, -2.4285922050, 0.4505937099], - [0.0259040371, 0.7827717662, -0.8086757660], - ]; - - const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color; - return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color; - // L in range [0,1]. For use in CSS, multiply by 100 and add a percent -} - -export function OKLab_to_XYZ(OKLab: color): color { - // Given OKLab, convert to XYZ relative to D65 - const LMStoXYZ = [ - [1.2268798733741557, -0.5578149965554813, 0.28139105017721583], - [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701], - [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418], - ]; - const OKLabtoLMS = [ - [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339], - [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402], - [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399], - ]; - - const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color; - return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color; -} - -export function OKLab_to_OKLCH(OKLab: color): color { - const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI; - return [ - OKLab[0], // L is still L - Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function OKLCH_to_OKLab(OKLCH: color): color { - return [ - OKLCH[0], // L is still L - OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a - OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b - ]; -} - -// Premultiplied alpha conversions - -export function rectangular_premultiply(color: color, alpha: number): color { - // given a color in a rectangular orthogonal colorspace - // and an alpha value - // return the premultiplied form - return color.map((c) => c * alpha) as color; -} - -export function rectangular_un_premultiply(color: color, alpha: number): color { - // given a premultiplied color in a rectangular orthogonal colorspace - // and an alpha value - // return the actual color - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c) => c / alpha) as color; -} - -export function polar_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the premultiplied form. - // the index says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color; -} - -export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the actual color. - // the hueIndex says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color; -} - -// Convenience functions can easily be defined, such as -export function hsl_premultiply(color: color, alpha: number): color { - return polar_premultiply(color, alpha, 0); -} diff --git a/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts b/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts deleted file mode 100644 index ce023047e..000000000 --- a/plugins/postcss-lab-function/src/css-color-4/deltaEOK.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */ - -// Calculate deltaE OK -// simple root sum of squares -type color = [number, number, number]; -export function deltaEOK(reference: color, sample: color): number { - // Given reference and sample are both in OKLab - const [L1, a1, b1] = reference; - const [L2, a2, b2] = sample; - const ΔL = L1 - L2; - const Δa = a1 - a2; - const Δb = b1 - b2; - return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2); -} diff --git a/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts b/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts deleted file mode 100644 index 168068986..000000000 --- a/plugins/postcss-lab-function/src/css-color-4/map-gamut.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { OKLCH_to_OKLab } from './conversions'; -import { deltaEOK } from './deltaEOK'; - -type color = [number, number, number]; - -export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - return binarySearchGamut(startOKLCH, toDestination, fromDestination); -} - -function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - let min = 0; - let max = startOKLCH[1]; - const current = startOKLCH; - - while (max - min > 0.0001) { - const clipped = clip(toDestination(current)); - const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped))); - // are we inside the gamut (or very close to the boundary, outside) - if (deltaE - 0.02 < 0.0001) { - min = current[1]; - } else { - max = current[1]; - } - // binary search - current[1] = (max + min) / 2; - } - - return clip(toDestination([...current])); -} - -export function clip(color: color): color { - return color.map(val => { - if (val < 0) { - return 0; - } else if (val > 1) { - return 1; - } else { - return val; - } - }) as color; -} - -export function inGamut(x: color): boolean { - const [xX, xY, xZ] = x; - return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001; -} - diff --git a/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts b/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts deleted file mode 100644 index 776f8c597..000000000 --- a/plugins/postcss-lab-function/src/css-color-4/multiply-matrices.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Simple matrix (and vector) multiplication - * Warning: No error handling for incompatible dimensions! - * @author Lea Verou 2020 MIT License - * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js - */ - -// A is m x n. B is n x p. product is m x p. -export function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array { - const m = a.length; - - let A: Array>; - if (!Array.isArray(a[0])) { - // A is vector, convert to [[a, b, c, ...]] - A = [a as Array]; - } else { - A = a as Array>; - } - - let B: Array>; - if (!Array.isArray(b[0])) { - // B is vector, convert to [[a], [b], [c], ...]] - B = (b as Array).map(x => [x]); - } - - const p = B[0].length; - const B_cols = B[0].map((_, i) => B.map(x => x[i])); // transpose B - let product: Array> | Array = A.map(row => B_cols.map(col => { - if (!Array.isArray(row)) { - return col.reduce((d, f) => d + f * row, 0); - } - - return row.reduce((d, f, i) => d + f * (col[i] || 0), 0); - })); - - if (m === 1) { - product = product[0]; // Avoid [[a, b, c, ...]] - } - - if (p === 1) { - return product.map(x => x[0]); // Avoid [[a], [b], [c], ...]] - } - - return product; -} diff --git a/plugins/postcss-lab-function/src/css-color-4/utilities.ts b/plugins/postcss-lab-function/src/css-color-4/utilities.ts deleted file mode 100644 index b3c4368cd..000000000 --- a/plugins/postcss-lab-function/src/css-color-4/utilities.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ - -import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions'; - -type color = [number, number, number]; - -// utility functions for color conversions -// needs conversions.js - -export function sRGB_to_luminance(RGB: color): number { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ - // and return luminance (the Y value) - - const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB)); - return XYZ[1]; -} - -export function contrast(RGB1: color, RGB2: color): number { - // return WCAG 2.1 contrast ratio - // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio - // for two sRGB values - // given as arrays of 0.0 to 1.0 - - const L1 = sRGB_to_luminance(RGB1); - const L2 = sRGB_to_luminance(RGB2); - - if (L1 > L2) { - return (L1 + 0.05) / (L2 + 0.05); - } - - return (L2 + 0.05) / (L1 + 0.05); -} - -export function sRGB_to_LCH(RGB: color): color { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB))))); -} - -export function P3_to_LCH(RGB: color): color { - // convert an array of gamma-corrected display-p3 values - // in the 0.0 to 1.0 range - // to linear-light display-p3, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB))))); -} - -export function r2020_to_LCH(RGB: color): color { - // convert an array of gamma-corrected rec.2020 values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB))))); -} - -export function LCH_to_sRGB(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light sRGB - // and finally to gamma corrected sRGB - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_P3(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light display-p3 - // and finally to gamma corrected display-p3 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_r2020(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light rec.2020 - // and finally to gamma corrected rec.2020 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -// this is straight from the CSS Color 4 spec - -export function hslToRgb(hsl: color): color { - // For simplicity, this algorithm assumes that the hue has been normalized - // to a number in the half-open range [0, 6), and the saturation and lightness - // have been normalized to the range [0, 1]. It returns an array of three numbers - // representing the red, green, and blue channels of the colors, - // normalized to the range [0, 1] - const [hue, sat, light] = hsl; - - let t2: number; - if (light <= .5) { - t2 = light * (sat + 1); - } else { - t2 = light + sat - (light * sat); - } - const t1 = light * 2 - t2; - const r = hueToRgb(t1, t2, hue + 2); - const g = hueToRgb(t1, t2, hue); - const b = hueToRgb(t1, t2, hue - 2); - return [r, g, b]; -} - -export function hueToRgb(t1: number, t2: number, hue: number): number { - if (hue < 0) { - hue += 6; - } - if (hue >= 6) { - hue -= 6; - } - - if (hue < 1) { - return (t2 - t1) * hue + t1; - } else if (hue < 3) { - return t2; - } else if (hue < 4) { - return (t2 - t1) * (4 - hue) + t1; - } else { - return t1; - } -} - -// These are the naive algorithms from CS Color 4 - -export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color { - // CMYK is an array of four values - // in the range [0.0, 1.0] - // the optput is an array of [RGB] - // also in the [0.0, 1.0] range - // because the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3]; - - const red = 1 - Math.min(1, cyan * (1 - black) + black); - const green = 1 - Math.min(1, magenta * (1 - black) + black); - const blue = 1 - Math.min(1, yellow * (1 - black) + black); - - return [red, green, blue]; - -} - -export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] { - // RGB is an arravy of three values - // in the range [0.0, 1.0] - // the output is an array of [CMYK] - // also in the [0.0, 1.0] range - // with maximum GCR and (I think) 200% TAC - // the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const red = RGB[0], green = RGB[1], blue = RGB[2]; - - const black = 1 - Math.max(red, green, blue); - const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black); - const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black); - const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black); - - return [cyan, magenta, yellow, black]; -} - -// Chromaticity utilities - -export function XYZ_to_xy(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to x,y chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const sum = X + Y + Z; - return [X / sum, Y / sum]; -} - -export function xy_to_uv(xy: [number, number]): [number, number] { - // convert an x,y chromaticity pair - // to u*,v* chromaticities - - const x = xy[0]; - const y = xy[1]; - const denom = -2 * x + 12 * y + 3; - return [4 * x / denom, 9 * y / denom]; -} - -export function XYZ_to_uv(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to u*,v* chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const denom = X + 15 * Y + 3 * Z; - return [4 * X / denom, 9 * Y / denom]; -} diff --git a/plugins/postcss-lab-function/src/on-css-function.ts b/plugins/postcss-lab-function/src/on-css-function.ts index 925553172..a93f0914a 100644 --- a/plugins/postcss-lab-function/src/on-css-function.ts +++ b/plugins/postcss-lab-function/src/on-css-function.ts @@ -1,10 +1,7 @@ import type { FunctionNode, Dimension, Node, DivNode, WordNode, SpaceNode } from 'postcss-value-parser'; import valueParser from 'postcss-value-parser'; import { Declaration, Result } from 'postcss'; -import { labToDisplayP3 } from './convert-lab-to-display-p3'; -import { labToSRgb } from './convert-lab-to-srgb'; -import { lchToDisplayP3 } from './convert-lch-to-display-p3'; -import { lchToSRgb } from './convert-lch-to-srgb'; +import { conversions } from '@csstools/color-helpers'; export function onCSSFunctionSRgb(node: FunctionNode) { const value = node.value.toLowerCase(); @@ -34,7 +31,7 @@ export function onCSSFunctionSRgb(node: FunctionNode) { const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes); /** Corresponding Color transformer. */ - const toRGB = value === 'lab' ? labToSRgb : lchToSRgb; + const toRGB = value === 'lab' ? conversions.Lab_to_sRGB : conversions.LCH_to_sRGB; /** RGB channels from the source color. */ const channelNumbers: [number, number, number] = [ @@ -100,7 +97,7 @@ export function onCSSFunctionDisplayP3(node: FunctionNode, decl: Declaration, re const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes); /** Corresponding Color transformer. */ - const toDisplayP3 = value === 'lab' ? labToDisplayP3 : lchToDisplayP3; + const toDisplayP3 = value === 'lab' ? conversions.Lab_to_P3 : conversions.LCH_to_P3; /** RGB channels from the source color. */ const channelNumbers: [number, number, number] = [ diff --git a/plugins/postcss-oklab-function/CHANGELOG.md b/plugins/postcss-oklab-function/CHANGELOG.md index b377a4aa2..3b62a9962 100644 --- a/plugins/postcss-oklab-function/CHANGELOG.md +++ b/plugins/postcss-oklab-function/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS OKLab Function +### Unreleased (minor) + +- Add: `@csstools/color-helpers` dependency for all color value transformations. + ### 2.0.1 (January 28, 2023) - Improve `types` declaration in `package.json` diff --git a/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts b/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts deleted file mode 100644 index 0afadfa1e..000000000 --- a/plugins/postcss-oklab-function/dist/convert-oklab-to-display-p3.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function oklabToDisplayP3(oklabRaw: color): [color, boolean]; -export {}; diff --git a/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts b/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts deleted file mode 100644 index 01b638750..000000000 --- a/plugins/postcss-oklab-function/dist/convert-oklab-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function oklabToSRgb(oklabRaw: color): color; -export {}; diff --git a/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts b/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts deleted file mode 100644 index 123a19ef6..000000000 --- a/plugins/postcss-oklab-function/dist/convert-oklch-to-display-p3.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function oklchToDisplayP3(oklchRaw: color): [color, boolean]; -export {}; diff --git a/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts b/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts deleted file mode 100644 index ad4c40134..000000000 --- a/plugins/postcss-oklab-function/dist/convert-oklch-to-srgb.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -type color = [number, number, number]; -export declare function oklchToSRgb(oklchRaw: color): color; -export {}; diff --git a/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts deleted file mode 100644 index a48b1e5bc..000000000 --- a/plugins/postcss-oklab-function/dist/css-color-4/conversions.d.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ -type color = [number, number, number]; -export declare const D50: number[]; -export declare const D65: number[]; -export declare function lin_sRGB(RGB: color): color; -export declare function gam_sRGB(RGB: color): color; -export declare function lin_sRGB_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_sRGB(XYZ: color): color; -export declare function lin_P3(RGB: color): color; -export declare function gam_P3(RGB: color): color; -export declare function lin_P3_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_P3(XYZ: color): color; -export declare function lin_ProPhoto(RGB: color): color; -export declare function gam_ProPhoto(RGB: color): color; -export declare function lin_ProPhoto_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_ProPhoto(XYZ: color): color; -export declare function lin_a98rgb(RGB: color): color; -export declare function gam_a98rgb(RGB: color): color; -export declare function lin_a98rgb_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_a98rgb(XYZ: color): color; -export declare function lin_2020(RGB: color): color; -export declare function gam_2020(RGB: color): color; -export declare function lin_2020_to_XYZ(rgb: color): color; -export declare function XYZ_to_lin_2020(XYZ: color): color; -export declare function D65_to_D50(XYZ: color): color; -export declare function D50_to_D65(XYZ: color): color; -export declare function XYZ_to_Lab(XYZ: color): color; -export declare function Lab_to_XYZ(Lab: color): color; -export declare function Lab_to_LCH(Lab: color): color; -export declare function LCH_to_Lab(LCH: color): color; -export declare function XYZ_to_OKLab(XYZ: color): color; -export declare function OKLab_to_XYZ(OKLab: color): color; -export declare function OKLab_to_OKLCH(OKLab: color): color; -export declare function OKLCH_to_OKLab(OKLCH: color): color; -export declare function rectangular_premultiply(color: color, alpha: number): color; -export declare function rectangular_un_premultiply(color: color, alpha: number): color; -export declare function polar_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color; -export declare function hsl_premultiply(color: color, alpha: number): color; -export {}; diff --git a/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts deleted file mode 100644 index d744ffaad..000000000 --- a/plugins/postcss-oklab-function/dist/css-color-4/deltaEOK.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */ -type color = [number, number, number]; -export declare function deltaEOK(reference: color, sample: color): number; -export {}; diff --git a/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts deleted file mode 100644 index 1a4ee6e95..000000000 --- a/plugins/postcss-oklab-function/dist/css-color-4/map-gamut.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -type color = [number, number, number]; -export declare function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color; -export declare function clip(color: color): color; -export declare function inGamut(x: color): boolean; -export {}; diff --git a/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts b/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts deleted file mode 100644 index a5bb9da80..000000000 --- a/plugins/postcss-oklab-function/dist/css-color-4/utilities.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ -type color = [number, number, number]; -export declare function sRGB_to_luminance(RGB: color): number; -export declare function contrast(RGB1: color, RGB2: color): number; -export declare function sRGB_to_LCH(RGB: color): color; -export declare function P3_to_LCH(RGB: color): color; -export declare function r2020_to_LCH(RGB: color): color; -export declare function LCH_to_sRGB(LCH: color): color; -export declare function LCH_to_P3(LCH: color): color; -export declare function LCH_to_r2020(LCH: color): color; -export declare function hslToRgb(hsl: color): color; -export declare function hueToRgb(t1: number, t2: number, hue: number): number; -export declare function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color; -export declare function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number]; -export declare function XYZ_to_xy(XYZ: color): [number, number]; -export declare function xy_to_uv(xy: [number, number]): [number, number]; -export declare function XYZ_to_uv(XYZ: color): [number, number]; -export {}; diff --git a/plugins/postcss-oklab-function/dist/index.cjs b/plugins/postcss-oklab-function/dist/index.cjs index 6680f2cd9..10795571c 100644 --- a/plugins/postcss-oklab-function/dist/index.cjs +++ b/plugins/postcss-oklab-function/dist/index.cjs @@ -1,29 +1 @@ -"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),t=require("postcss-value-parser");function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let r=0;r[e])));const a=o[0].length,u=o[0].map(((e,t)=>o.map((e=>e[t]))));let i=r.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,r)=>e+n*(t[r]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===a?i.map((e=>e[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(e,t){const[n,r,o]=e,[a,u,i]=t,s=n-a,l=r-u,c=o-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let r=0,o=e[1];const a=e;for(;o-r>1e-4;){const e=clip(t(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(e)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(t([...a]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,r]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function oklabToDisplayP3(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_P3(o),o=gam_P3(o),inGamut(o)?[clip(o),!0]:[mapGamut(a,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklchToDisplayP3(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_P3(a),a=gam_P3(a),inGamut(a)?[clip(a),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklabToSRgb(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_sRGB(o),o=gam_sRGB(o),inGamut(o)?clip(o).map((e=>Math.round(255*e))):mapGamut(a,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function oklchToSRgb(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_sRGB(a),a=gam_sRGB(a),inGamut(a)?clip(a).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let r=null;if("oklab"===t?r=oklabFunctionContents(n):"oklch"===t&&(r=oklchFunctionContents(n)),!r)return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[o,a,u]=channelNodes(r),[i,s,l]=channelDimensions(r),c=("oklab"===t?oklabToSRgb:oklchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(a)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(c[0])}),replaceWith(e.nodes,a,{...a,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,r,o){const a=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("oklab"===u?s=oklabFunctionContents(i):"oklch"===u&&(s=oklchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,p]=channelNodes(s),[m,b,d]=channelDimensions(s),_="oklab"===u?oklabToDisplayP3:oklchToDisplayP3,f=[m.number,b.number,d.number].map((e=>parseFloat(e))),[h,L]=_(f);!L&&o&&n.warn(r,`"${a}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const r=n.unit.toLowerCase();return!!n.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*.4).toFixed(10)),n):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*.4).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*.4).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,r){if(!n||!r)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=t.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,t,n){const r=e.indexOf(t);e[r]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,r,o){let a;try{a=t(e)}catch(t){n.warn(r,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(a);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,r,o))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,t,n,e.preserve);void 0!==o&&(e.preserve?(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3})):(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; +"use strict";var e=require("@csstools/postcss-progressive-custom-properties"),n=require("postcss-value-parser"),r=require("@csstools/color-helpers");function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("oklab"===n?o=oklabFunctionContents(t):"oklch"===n&&(o=oklchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[s,u,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("oklab"===n?r.conversions.OKLab_to_sRGB:r.conversions.OKLCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,s,{...s,value:String(d[0])}),replaceWith(e.nodes,u,{...u,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,s){const u=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("oklab"===a?l=oklabFunctionContents(i):"oklch"===a&&(l=oklchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[b,f,m]=channelDimensions(l),v="oklab"===a?r.conversions.OKLab_to_P3:r.conversions.OKLCH_to_P3,h=[b.number,f.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&s&&t.warn(o,`"${u}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*.4).toFixed(10)),r):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*.4).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*.4).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let s;try{s=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===s)return;s.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(s);if(u===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:u,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0,module.exports=postcssPlugin; diff --git a/plugins/postcss-oklab-function/dist/index.mjs b/plugins/postcss-oklab-function/dist/index.mjs index 3dae4ab67..4337b86a4 100644 --- a/plugins/postcss-oklab-function/dist/index.mjs +++ b/plugins/postcss-oklab-function/dist/index.mjs @@ -1,29 +1 @@ -import e from"@csstools/postcss-progressive-custom-properties";import t from"postcss-value-parser";function hasFallback(e){const t=e.parent;if(!t)return!1;const n=t.index(e);for(let r=0;r[e])));const a=o[0].length,u=o[0].map(((e,t)=>o.map((e=>e[t]))));let i=r.map((e=>u.map((t=>Array.isArray(e)?e.reduce(((e,n,r)=>e+n*(t[r]||0)),0):t.reduce(((t,n)=>t+n*e),0)))));return 1===n&&(i=i[0]),1===a?i.map((e=>e[0])):i} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */function lin_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n<.04045?e/12.92:t*Math.pow((n+.055)/1.055,2.4)}))}function gam_sRGB(e){return e.map((function(e){const t=e<0?-1:1,n=Math.abs(e);return n>.0031308?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))}function lin_sRGB_to_XYZ(e){return multiplyMatrices([[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],e)}function XYZ_to_lin_sRGB(e){return multiplyMatrices([[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],e)}function lin_P3(e){return lin_sRGB(e)}function gam_P3(e){return gam_sRGB(e)}function lin_P3_to_XYZ(e){return multiplyMatrices([[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],e)}function XYZ_to_lin_P3(e){return multiplyMatrices([[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]],e)}function XYZ_to_OKLab(e){const t=multiplyMatrices([[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],e);return multiplyMatrices([[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],t.map((e=>Math.cbrt(e))))}function OKLab_to_XYZ(e){const t=multiplyMatrices([[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],e);return multiplyMatrices([[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],t.map((e=>e**3)))}function OKLab_to_OKLCH(e){const t=180*Math.atan2(e[2],e[1])/Math.PI;return[e[0],Math.sqrt(e[1]**2+e[2]**2),t>=0?t:t+360]}function OKLCH_to_OKLab(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]} -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js - */function deltaEOK(e,t){const[n,r,o]=e,[a,u,i]=t,s=n-a,l=r-u,c=o-i;return Math.sqrt(s**2+l**2+c**2)}function mapGamut(e,t,n){return binarySearchGamut(e,t,n)}function binarySearchGamut(e,t,n){let r=0,o=e[1];const a=e;for(;o-r>1e-4;){const e=clip(t(a));deltaEOK(OKLCH_to_OKLab(a),OKLCH_to_OKLab(n(e)))-.02<1e-4?r=a[1]:o=a[1],a[1]=(o+r)/2}return clip(t([...a]))}function clip(e){return e.map((e=>e<0?0:e>1?1:e))}function inGamut(e){const[t,n,r]=e;return t>=-1e-4&&t<=1.0001&&n>=-1e-4&&n<=1.0001&&r>=-1e-4&&r<=1.0001}function oklabToDisplayP3(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_P3(o),o=gam_P3(o),inGamut(o)?[clip(o),!0]:[mapGamut(a,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklchToDisplayP3(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_P3(a),a=gam_P3(a),inGamut(a)?[clip(a),!0]:[mapGamut(o,(e=>gam_P3(e=XYZ_to_lin_P3(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_P3_to_XYZ(e=lin_P3(e)))))),!1]}function oklabToSRgb(e){const[t,n,r]=e;let o=[Math.max(t,0),n,r],a=OKLab_to_OKLCH(o);return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),o=OKLab_to_XYZ(o),o=XYZ_to_lin_sRGB(o),o=gam_sRGB(o),inGamut(o)?clip(o).map((e=>Math.round(255*e))):mapGamut(a,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function oklchToSRgb(e){const[t,n,r]=e,o=[Math.max(t,0),n,r%360];let a=o;return a[0]<1e-6&&(a=[0,0,0]),a[0]>.999999&&(a=[1,0,0]),a=OKLCH_to_OKLab(a),a=OKLab_to_XYZ(a),a=XYZ_to_lin_sRGB(a),a=gam_sRGB(a),inGamut(a)?clip(a).map((e=>Math.round(255*e))):mapGamut(o,(e=>gam_sRGB(e=XYZ_to_lin_sRGB(e=OKLab_to_XYZ(e=OKLCH_to_OKLab(e))))),(e=>OKLab_to_OKLCH(e=XYZ_to_OKLab(e=lin_sRGB_to_XYZ(e=lin_sRGB(e)))))).map((e=>Math.round(255*e)))}function onCSSFunctionSRgb(e){const t=e.value.toLowerCase(),n=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let r=null;if("oklab"===t?r=oklabFunctionContents(n):"oklch"===t&&(r=oklchFunctionContents(n)),!r)return;e.value="rgb",transformAlpha(e,r.slash,r.alpha);const[o,a,u]=channelNodes(r),[i,s,l]=channelDimensions(r),c=("oklab"===t?oklabToSRgb:oklchToSRgb)([i.number,s.number,l.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(o)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(a)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,o,{...o,value:String(c[0])}),replaceWith(e.nodes,a,{...a,value:String(c[1])}),replaceWith(e.nodes,u,{...u,value:String(c[2])})}function onCSSFunctionDisplayP3(e,n,r,o){const a=t.stringify(e),u=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let s=null;if("oklab"===u?s=oklabFunctionContents(i):"oklch"===u&&(s=oklchFunctionContents(i)),!s)return;if(i.length>3&&(!s.slash||!s.alpha))return;e.value="color";const[l,c,p]=channelNodes(s),[m,b,d]=channelDimensions(s),_="oklab"===u?oklabToDisplayP3:oklchToDisplayP3,f=[m.number,b.number,d.number].map((e=>parseFloat(e))),[h,L]=_(f);!L&&o&&n.warn(r,`"${a}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,l,{...l,value:h[0].toFixed(5)}),replaceWith(e.nodes,c,{...c,value:h[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:h[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&!!n.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);if(!n)return!1;const r=n.unit.toLowerCase();return!!n.number&&("deg"===r||"grad"===r||"rad"===r||"turn"===r||""===r)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const n=t.unit(e.value);return!!n&&("%"===n.unit||""===n.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],c:t.unit(e[1].value),cNode:e[1],h:t.unit(e[2].value),hNode:e[2]};return normalizeHueNode(n.h),""!==n.h.unit?null:(isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.c.unit&&(n.c.unit="",n.c.number=(parseFloat(n.c.number)/100*.4).toFixed(10)),n):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const n={l:t.unit(e[0].value),lNode:e[0],a:t.unit(e[1].value),aNode:e[1],b:t.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(n.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(n.alpha=e[4]),!(e.length>3)||n.slash&&n.alpha?("%"===n.l.unit&&(n.l.unit="",n.l.number=(parseFloat(n.l.number)/100).toFixed(10)),"%"===n.a.unit&&(n.a.unit="",n.a.number=(parseFloat(n.a.number)/100*.4).toFixed(10)),"%"===n.b.unit&&(n.b.unit="",n.b.number=(parseFloat(n.b.number)/100*.4).toFixed(10)),n):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,n,r){if(!n||!r)return;if(e.value="rgba",n.value=",",n.before="",!isNumericNode(r))return;const o=t.unit(r.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),r.value=String(o.number))}function replaceWith(e,t,n){const r=e.indexOf(t);e[r]=n}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==t.unit(e.value)}catch(e){return!1}}function modifiedValues(e,n,r,o){let a;try{a=t(e)}catch(t){n.warn(r,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===a)return;a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const u=String(a);if(u===e)return;const i=t(e);i.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,n,r,o))}));return{rgb:u,displayP3:String(i)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(t,{result:n})=>{if(hasFallback(t))return;if(hasSupportsAtRuleAncestor(t))return;const r=t.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(r.toLowerCase()))return;const o=modifiedValues(r,t,n,e.preserve);void 0!==o&&(e.preserve?(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3})):(t.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&t.cloneBefore({value:o.displayP3}),t.remove()))}});basePlugin.postcss=!0;const postcssPlugin=t=>{const n=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},t);return n.subFeatures=Object.assign({displayP3:!0},n.subFeatures),n.enableProgressiveCustomProperties&&(n.preserve||n.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(n)]}:basePlugin(n)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; +import e from"@csstools/postcss-progressive-custom-properties";import n from"postcss-value-parser";import{conversions as r}from"@csstools/color-helpers";function hasFallback(e){const n=e.parent;if(!n)return!1;const r=n.index(e);for(let t=0;t"comment"!==e.type&&"space"!==e.type));let o=null;if("oklab"===n?o=oklabFunctionContents(t):"oklch"===n&&(o=oklchFunctionContents(t)),!o)return;e.value="rgb",transformAlpha(e,o.slash,o.alpha);const[u,s,a]=channelNodes(o),[i,l,c]=channelDimensions(o),d=("oklab"===n?r.OKLab_to_sRGB:r.OKLCH_to_sRGB)([i.number,l.number,c.number].map((e=>parseFloat(e))));e.nodes.splice(e.nodes.indexOf(u)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),e.nodes.splice(e.nodes.indexOf(s)+1,0,{sourceIndex:0,sourceEndIndex:1,value:",",type:"div",before:"",after:""}),replaceWith(e.nodes,u,{...u,value:String(d[0])}),replaceWith(e.nodes,s,{...s,value:String(d[1])}),replaceWith(e.nodes,a,{...a,value:String(d[2])})}function onCSSFunctionDisplayP3(e,t,o,u){const s=n.stringify(e),a=e.value.toLowerCase(),i=e.nodes.slice().filter((e=>"comment"!==e.type&&"space"!==e.type));let l=null;if("oklab"===a?l=oklabFunctionContents(i):"oklch"===a&&(l=oklchFunctionContents(i)),!l)return;if(i.length>3&&(!l.slash||!l.alpha))return;e.value="color";const[c,d,p]=channelNodes(l),[f,b,m]=channelDimensions(l),v="oklab"===a?r.OKLab_to_P3:r.OKLCH_to_P3,h=[f.number,b.number,m.number].map((e=>parseFloat(e))),[N,g]=v(h);!g&&u&&t.warn(o,`"${s}" is out of gamut for "display-p3". Given "preserve: true" is set, this will lead to unexpected results in some browsers.`),e.nodes.splice(0,0,{sourceIndex:0,sourceEndIndex:10,value:"display-p3",type:"word"}),e.nodes.splice(1,0,{sourceIndex:0,sourceEndIndex:1,value:" ",type:"space"}),replaceWith(e.nodes,c,{...c,value:N[0].toFixed(5)}),replaceWith(e.nodes,d,{...d,value:N[1].toFixed(5)}),replaceWith(e.nodes,p,{...p,value:N[2].toFixed(5)})}function isNumericNode(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&!!r.number}function isNumericNodeHueLike(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);if(!r)return!1;const t=r.unit.toLowerCase();return!!r.number&&("deg"===t||"grad"===t||"rad"===t||"turn"===t||""===t)}function isNumericNodePercentageOrNumber(e){if(!e||"word"!==e.type)return!1;if(!canParseAsUnit(e))return!1;const r=n.unit(e.value);return!!r&&("%"===r.unit||""===r.unit)}function isCalcNode(e){return e&&"function"===e.type&&"calc"===e.value.toLowerCase()}function isVarNode(e){return e&&"function"===e.type&&"var"===e.value.toLowerCase()}function isSlashNode(e){return e&&"div"===e.type&&"/"===e.value}function oklchFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodeHueLike(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],c:n.unit(e[1].value),cNode:e[1],h:n.unit(e[2].value),hNode:e[2]};return normalizeHueNode(r.h),""!==r.h.unit?null:(isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.c.unit&&(r.c.unit="",r.c.number=(parseFloat(r.c.number)/100*.4).toFixed(10)),r):null)}function oklabFunctionContents(e){if(!isNumericNodePercentageOrNumber(e[0]))return null;if(!isNumericNodePercentageOrNumber(e[1]))return null;if(!isNumericNodePercentageOrNumber(e[2]))return null;const r={l:n.unit(e[0].value),lNode:e[0],a:n.unit(e[1].value),aNode:e[1],b:n.unit(e[2].value),bNode:e[2]};return isSlashNode(e[3])&&(r.slash=e[3]),(isNumericNodePercentageOrNumber(e[4])||isCalcNode(e[4])||isVarNode(e[4]))&&(r.alpha=e[4]),!(e.length>3)||r.slash&&r.alpha?("%"===r.l.unit&&(r.l.unit="",r.l.number=(parseFloat(r.l.number)/100).toFixed(10)),"%"===r.a.unit&&(r.a.unit="",r.a.number=(parseFloat(r.a.number)/100*.4).toFixed(10)),"%"===r.b.unit&&(r.b.unit="",r.b.number=(parseFloat(r.b.number)/100*.4).toFixed(10)),r):null}function isLab(e){return void 0!==e.a}function channelNodes(e){return isLab(e)?[e.lNode,e.aNode,e.bNode]:[e.lNode,e.cNode,e.hNode]}function channelDimensions(e){return isLab(e)?[e.l,e.a,e.b]:[e.l,e.c,e.h]}function transformAlpha(e,r,t){if(!r||!t)return;if(e.value="rgba",r.value=",",r.before="",!isNumericNode(t))return;const o=n.unit(t.value);o&&"%"===o.unit&&(o.number=String(parseFloat(o.number)/100),t.value=String(o.number))}function replaceWith(e,n,r){const t=e.indexOf(n);e[t]=r}function normalizeHueNode(e){switch(e.unit.toLowerCase()){case"deg":return void(e.unit="");case"rad":return e.unit="",void(e.number=(180*parseFloat(e.number)/Math.PI).toString());case"grad":return e.unit="",void(e.number=(.9*parseFloat(e.number)).toString());case"turn":return e.unit="",void(e.number=(360*parseFloat(e.number)).toString())}}function canParseAsUnit(e){if(!e||!e.value)return!1;try{return!1!==n.unit(e.value)}catch(e){return!1}}function modifiedValues(e,r,t,o){let u;try{u=n(e)}catch(n){r.warn(t,`Failed to parse value '${e}' as an oklab or oklch function. Leaving the original value intact.`)}if(void 0===u)return;u.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionSRgb(e))}));const s=String(u);if(s===e)return;const a=n(e);a.walk((e=>{e.type&&"function"===e.type&&("oklab"!==e.value.toLowerCase()&&"oklch"!==e.value.toLowerCase()||onCSSFunctionDisplayP3(e,r,t,o))}));return{rgb:s,displayP3:String(a)}}const basePlugin=e=>({postcssPlugin:"postcss-oklab-function",Declaration:(n,{result:r})=>{if(hasFallback(n))return;if(hasSupportsAtRuleAncestor(n))return;const t=n.value;if(!/(^|[^\w-])(oklab|oklch)\(/i.test(t.toLowerCase()))return;const o=modifiedValues(t,n,r,e.preserve);void 0!==o&&(e.preserve?(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3})):(n.cloneBefore({value:o.rgb}),e.subFeatures.displayP3&&n.cloneBefore({value:o.displayP3}),n.remove()))}});basePlugin.postcss=!0;const postcssPlugin=n=>{const r=Object.assign({enableProgressiveCustomProperties:!0,preserve:!1,subFeatures:{displayP3:!0}},n);return r.subFeatures=Object.assign({displayP3:!0},r.subFeatures),r.enableProgressiveCustomProperties&&(r.preserve||r.subFeatures.displayP3)?{postcssPlugin:"postcss-oklab-function",plugins:[e(),basePlugin(r)]}:basePlugin(r)};postcssPlugin.postcss=!0;export{postcssPlugin as default}; diff --git a/plugins/postcss-oklab-function/package.json b/plugins/postcss-oklab-function/package.json index ee1d9c15a..2327f6ed1 100644 --- a/plugins/postcss-oklab-function/package.json +++ b/plugins/postcss-oklab-function/package.json @@ -29,6 +29,7 @@ "dist" ], "dependencies": { + "@csstools/color-helpers": "^0.0.0", "@csstools/postcss-progressive-custom-properties": "^2.0.0", "postcss-value-parser": "^4.2.0" }, diff --git a/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts b/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts deleted file mode 100644 index b363d3590..000000000 --- a/plugins/postcss-oklab-function/src/convert-oklab-to-display-p3.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_P3, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function oklabToDisplayP3(oklabRaw: color): [color, boolean] { - const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw; - - const oklabL = Math.max( - oklabLRaw, - 0, - ); - - const oklab = [oklabL, oklabARaw, oklabBRaw] as color; - - let conversion = oklab as color; - let oklch = OKLab_to_OKLCH(conversion); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - conversion = OKLab_to_XYZ(conversion); - conversion = XYZ_to_lin_P3(conversion); - conversion = gam_P3(conversion); - - if (inGamut(conversion)) { - return [clip(conversion), true]; - } - - return [mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_P3(x); - return gam_P3(x); - }, (x: color) => { - x = lin_P3(x); - x = lin_P3_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }), false]; -} diff --git a/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts b/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts deleted file mode 100644 index 2c554dbd5..000000000 --- a/plugins/postcss-oklab-function/src/convert-oklab-to-srgb.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function oklabToSRgb(oklabRaw: color): color { - const [oklabLRaw, oklabARaw, oklabBRaw] = oklabRaw; - - const oklabL = Math.max( - oklabLRaw, - 0, - ); - - const oklab = [oklabL, oklabARaw, oklabBRaw] as color; - - let conversion = oklab as color; - let oklch = OKLab_to_OKLCH(conversion); - if (oklch[0] < 0.000001) { - oklch = [0, 0, 0] as color; - } - - if (oklch[0] > 0.999999) { - oklch = [1, 0, 0] as color; - } - - conversion = OKLab_to_XYZ(conversion); - conversion = XYZ_to_lin_sRGB(conversion); - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion).map((x) => { - return Math.round(x * 255); - }) as color; - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }).map((x) => { - return Math.round(x * 255); - }) as color; -} diff --git a/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts b/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts deleted file mode 100644 index c561d5f87..000000000 --- a/plugins/postcss-oklab-function/src/convert-oklch-to-display-p3.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { gam_P3, lin_P3, lin_P3_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_P3, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function oklchToDisplayP3(oklchRaw: color): [color, boolean] { - const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw; - - const oklchL = Math.max( - oklchLRaw, - 0, - ); - - const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as color; - - let conversion = oklch as color; - if (conversion[0] < 0.000001) { - conversion = [0, 0, 0] as color; - } - - if (conversion[0] > 0.999999) { - conversion = [1, 0, 0] as color; - } - - conversion = OKLCH_to_OKLab(conversion); - conversion = OKLab_to_XYZ(conversion); - conversion = XYZ_to_lin_P3(conversion); - conversion = gam_P3(conversion); - - if (inGamut(conversion)) { - return [clip(conversion), true]; - } - - return [mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_P3(x); - return gam_P3(x); - }, (x: color) => { - x = lin_P3(x); - x = lin_P3_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }), false]; -} diff --git a/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts b/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts deleted file mode 100644 index 83db7e474..000000000 --- a/plugins/postcss-oklab-function/src/convert-oklch-to-srgb.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { gam_sRGB, lin_sRGB, lin_sRGB_to_XYZ, OKLab_to_OKLCH, OKLab_to_XYZ, OKLCH_to_OKLab, XYZ_to_lin_sRGB, XYZ_to_OKLab } from './css-color-4/conversions.js'; -import { clip, inGamut, mapGamut } from './css-color-4/map-gamut'; - -type color = [number, number, number]; - -export function oklchToSRgb(oklchRaw: color): color { - const [oklchLRaw, oklchCRaw, oklchHRaw] = oklchRaw; - - const oklchL = Math.max( - oklchLRaw, - 0, - ); - - const oklch = [oklchL, oklchCRaw, oklchHRaw % 360] as color; - - let conversion = oklch as color; - if (conversion[0] < 0.000001) { - conversion = [0, 0, 0] as color; - } - - if (conversion[0] > 0.999999) { - conversion = [1, 0, 0] as color; - } - - conversion = OKLCH_to_OKLab(conversion); - conversion = OKLab_to_XYZ(conversion); - conversion = XYZ_to_lin_sRGB(conversion); - conversion = gam_sRGB(conversion); - - if (inGamut(conversion)) { - return clip(conversion).map((x) => { - return Math.round(x * 255); - }) as color; - } - - return mapGamut(oklch, (x: color) => { - x = OKLCH_to_OKLab(x); - x = OKLab_to_XYZ(x); - x = XYZ_to_lin_sRGB(x); - return gam_sRGB(x); - }, (x: color) => { - x = lin_sRGB(x); - x = lin_sRGB_to_XYZ(x); - x = XYZ_to_OKLab(x); - return OKLab_to_OKLCH(x); - }).map((x) => { - return Math.round(x * 255); - }) as color; -} diff --git a/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md b/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md deleted file mode 100644 index ea4236ffc..000000000 --- a/plugins/postcss-oklab-function/src/css-color-4/LICENSE.md +++ /dev/null @@ -1,5 +0,0 @@ -All documents in this Directory are licensed by contributors -under the -[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). - -See [w3c/csswg-drafts](https://github.com/w3c/csswg-drafts) for the original work. diff --git a/plugins/postcss-oklab-function/src/css-color-4/conversions.ts b/plugins/postcss-oklab-function/src/css-color-4/conversions.ts deleted file mode 100644 index 636f08f90..000000000 --- a/plugins/postcss-oklab-function/src/css-color-4/conversions.ts +++ /dev/null @@ -1,512 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js - */ - -/* eslint-disable @typescript-eslint/no-loss-of-precision */ - -import { multiplyMatrices } from './multiply-matrices'; - -type color = [number, number, number]; - -// Sample code for color conversions -// Conversion can also be done using ICC profiles and a Color Management System -// For clarity, a library is used for matrix multiplication (multiply-matrices.js) - -// standard white points, defined by 4-figure CIE x,y chromaticities -export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585]; -export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290]; - -// sRGB-related functions - -export function lin_sRGB(RGB: color): color { - // convert an array of sRGB values - // where in-gamut values are in the range [0 - 1] - // to linear light (un-companded) form. - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // for negative values, linear portion is extended on reflection of axis, - // then reflected power function is used. - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < 0.04045) { - return val / 12.92; - } - - return sign * (Math.pow((abs + 0.055) / 1.055, 2.4)); - }) as color; -} - -export function gam_sRGB(RGB: color): color { - // convert an array of linear-light sRGB values in the range 0.0-1.0 - // to gamma corrected form - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // For negative values, linear portion extends on reflection - // of axis, then uses reflected pow below that - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > 0.0031308) { - return sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055); - } - - return 12.92 * val; - }) as color; -} - -export function lin_sRGB_to_XYZ(rgb: color): color { - // convert an array of linear-light sRGB values to CIE XYZ - // using sRGB's own white, D65 (no chromatic adaptation) - - const M = [ - [0.41239079926595934, 0.357584339383878, 0.1804807884018343], - [0.21263900587151027, 0.715168678767756, 0.07219231536073371], - [0.01933081871559182, 0.11919477979462598, 0.9505321522496607], - ]; - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_sRGB(XYZ: color): color { - // convert XYZ to linear-light sRGB - - const M = [ - [3.2409699419045226, -1.537383177570094, -0.4986107602930034], - [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559], - [0.05563007969699366, -0.20397695888897652, 1.0569715142428786], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// display-p3-related functions - - -export function lin_P3(RGB: color): color { - // convert an array of display-p3 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - - return lin_sRGB(RGB); // same as sRGB -} - -export function gam_P3(RGB: color): color { - // convert an array of linear-light display-p3 RGB in the range 0.0-1.0 - // to gamma corrected form - - return gam_sRGB(RGB); // same as sRGB -} - -export function lin_P3_to_XYZ(rgb: color): color { - // convert an array of linear-light display-p3 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.4865709486482162, 0.26566769316909306, 0.1982172852343625], - [0.2289745640697488, 0.6917385218365064, 0.079286914093745], - [0.0000000000000000, 0.04511338185890264, 1.043944368900976], - ]; - // 0 was computed as -3.972075516933488e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_P3(XYZ: color): color { - // convert XYZ to linear-light P3 - const M = [ - [2.493496911941425, -0.9313836179191239, -0.40271078445071684], - [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577], - [0.03584583024378447, -0.07617238926804182, 0.9568845240076872], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// prophoto-rgb functions - -export function lin_ProPhoto(RGB: color): color { - // convert an array of prophoto-rgb values - // where in-gamut colors are in the range [0.0 - 1.0] - // to linear light (un-companded) form. - // Transfer curve is gamma 1.8 with a small linear portion - // Extended transfer function - const Et2 = 16 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs <= Et2) { - return val / 16; - } - - return sign * Math.pow(val, 1.8); - }) as color; -} - -export function gam_ProPhoto(RGB: color): color { - // convert an array of linear-light prophoto-rgb in the range 0.0-1.0 - // to gamma corrected form - // Transfer curve is gamma 1.8 with a small linear portion - // TODO for negative values, extend linear portion on reflection of axis, then add pow below that - const Et = 1 / 512; - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs >= Et) { - return sign * Math.pow(abs, 1 / 1.8); - } - - return 16 * val; - }) as color; -} - -export function lin_ProPhoto_to_XYZ(rgb: color): color { - // convert an array of linear-light prophoto-rgb values to CIE XYZ - // using D50 (so no chromatic adaptation needed afterwards) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.7977604896723027, 0.13518583717574031, 0.0313493495815248], - [0.2880711282292934, 0.7118432178101014, 0.00008565396060525902], - [0.0, 0.0, 0.8251046025104601], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_ProPhoto(XYZ: color): color { - // convert XYZ to linear-light prophoto-rgb - const M = [ - [1.3457989731028281, -0.25558010007997534, -0.05110628506753401], - [-0.5446224939028347, 1.5082327413132781, 0.02053603239147973], - [0.0, 0.0, 1.2119675456389454], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// a98-rgb functions - -export function lin_a98rgb(RGB: color): color { - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 563 / 256); - }) as color; -} - -export function gam_a98rgb(RGB: color): color { - // convert an array of linear-light a98-rgb in the range 0.0-1.0 - // to gamma corrected form - // negative values are also now accepted - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - return sign * Math.pow(abs, 256 / 563); - }) as color; -} - -export function lin_a98rgb_to_XYZ(rgb: color): color { - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - const M = [ - [0.5766690429101305, 0.1855582379065463, 0.1882286462349947], - [0.29734497525053605, 0.6273635662554661, 0.07529145849399788], - [0.02703136138641234, 0.07068885253582723, 0.9913375368376388], - ]; - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_a98rgb(XYZ: color): color { - // convert XYZ to linear-light a98-rgb - const M = [ - [2.0415879038107465, -0.5650069742788596, -0.34473135077832956], - [-0.9692436362808795, 1.8759675015077202, 0.04155505740717557], - [0.013444280632031142, -0.11836239223101838, 1.0151749943912054], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -//Rec. 2020-related functions - -export function lin_2020(RGB: color): color { - // convert an array of rec2020 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs < β * 4.5) { - return val / 4.5; - } - - return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }) as color; -} - -export function gam_2020(RGB: color): color { - // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 - // to gamma corrected form - // ITU-R BT.2020-2 p.4 - - const α = 1.09929682680944; - const β = 0.018053968510807; - - - return RGB.map(function (val) { - const sign = val < 0 ? -1 : 1; - const abs = Math.abs(val); - - if (abs > β) { - return sign * (α * Math.pow(abs, 0.45) - (α - 1)); - } - - return 4.5 * val; - }) as color; -} - -export function lin_2020_to_XYZ(rgb: color): color { - // convert an array of linear-light rec2020 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const M = [ - [0.6369580483012914, 0.14461690358620832, 0.1688809751641721], - [0.2627002120112671, 0.6779980715188708, 0.05930171646986196], - [0.000000000000000, 0.028072693049087428, 1.060985057710791], - ]; - // 0 is actually calculated as 4.994106574466076e-17 - - return multiplyMatrices(M, rgb) as color; -} - -export function XYZ_to_lin_2020(XYZ: color): color { - // convert XYZ to linear-light rec2020 - const M = [ - [1.7166511879712674, -0.35567078377639233, -0.25336628137365974], - [-0.6666843518324892, 1.6164812366349395, 0.01576854581391113], - [0.017639857445310783, -0.042770613257808524, 0.9421031212354738], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// Chromatic adaptation - -export function D65_to_D50(XYZ: color): color { - // Bradford chromatic adaptation from D65 to D50 - // The matrix below is the result of three operations: - // - convert from XYZ to retinal cone domain - // - scale components from one reference white to another - // - convert back to XYZ - // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html - const M = [ - [1.0479298208405488, 0.022946793341019088, -0.05019222954313557], - [0.029627815688159344, 0.990434484573249, -0.01707382502938514], - [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -export function D50_to_D65(XYZ: color): color { - // Bradford chromatic adaptation from D50 to D65 - const M = [ - [0.9554734527042182, -0.023098536874261423, 0.0632593086610217], - [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008], - [0.012314001688319899, -0.020507696433477912, 1.3303659366080753], - ]; - - return multiplyMatrices(M, XYZ) as color; -} - -// CIE Lab and LCH - -export function XYZ_to_Lab(XYZ: color): color { - // Assuming XYZ is relative to D50, convert to CIE Lab - // from CIE standard, which now defines these as a rational fraction - const ε = 216 / 24389; // 6^3/29^3 - const κ = 24389 / 27; // 29^3/3^3 - - // compute xyz, which is XYZ scaled relative to reference white - const xyz = XYZ.map((value, i) => value / D50[i]); - - // now compute f - const f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16) / 116); - - return [ - (116 * f[1]) - 16, // L - 500 * (f[0] - f[1]), // a - 200 * (f[1] - f[2]), // b - ]; - // L in range [0,100]. For use in CSS, add a percent -} - -export function Lab_to_XYZ(Lab: color): color { - // Convert Lab to D50-adapted XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const κ = 24389 / 27; // 29^3/3^3 - const ε = 216 / 24389; // 6^3/29^3 - const f = []; - - // compute f, starting with the luminance-related term - f[1] = (Lab[0] + 16) / 116; - f[0] = Lab[1] / 500 + f[1]; - f[2] = f[1] - Lab[2] / 200; - - // compute xyz - const xyz = [ - Math.pow(f[0], 3) > ε ? Math.pow(f[0], 3) : (116 * f[0] - 16) / κ, - Lab[0] > κ * ε ? Math.pow((Lab[0] + 16) / 116, 3) : Lab[0] / κ, - Math.pow(f[2], 3) > ε ? Math.pow(f[2], 3) : (116 * f[2] - 16) / κ, - ]; - - // Compute XYZ by scaling xyz by reference white - return xyz.map((value, i) => value * D50[i]) as color; -} - -export function Lab_to_LCH(Lab: color): color { - // Convert to polar form - const hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI; - return [ - Lab[0], // L is still L - Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function LCH_to_Lab(LCH: color): color { - // Convert from polar form - return [ - LCH[0], // L is still L - LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a - LCH[1] * Math.sin(LCH[2] * Math.PI / 180), // b - ]; -} - -// OKLab and OKLCH -// https://bottosson.github.io/posts/oklab/ - -// XYZ <-> LMS matrices recalculated for consistent reference white -// see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 - -export function XYZ_to_OKLab(XYZ: color): color { - // Given XYZ relative to D65, convert to OKLab - const XYZtoLMS = [ - [0.8190224432164319, 0.3619062562801221, -0.12887378261216414], - [0.0329836671980271, 0.9292868468965546, 0.03614466816999844], - [0.048177199566046255, 0.26423952494422764, 0.6335478258136937], - ]; - const LMStoOKLab = [ - [0.2104542553, 0.7936177850, -0.0040720468], - [1.9779984951, -2.4285922050, 0.4505937099], - [0.0259040371, 0.7827717662, -0.8086757660], - ]; - - const LMS = multiplyMatrices(XYZtoLMS, XYZ) as color; - return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c))) as color; - // L in range [0,1]. For use in CSS, multiply by 100 and add a percent -} - -export function OKLab_to_XYZ(OKLab: color): color { - // Given OKLab, convert to XYZ relative to D65 - const LMStoXYZ = [ - [1.2268798733741557, -0.5578149965554813, 0.28139105017721583], - [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701], - [-0.07637294974672142, -0.4214933239627914, 1.5869240244272418], - ]; - const OKLabtoLMS = [ - [0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339], - [1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402], - [1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399], - ]; - - const LMSnl = multiplyMatrices(OKLabtoLMS, OKLab) as color; - return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3)) as color; -} - -export function OKLab_to_OKLCH(OKLab: color): color { - const hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI; - return [ - OKLab[0], // L is still L - Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma - hue >= 0 ? hue : hue + 360, // Hue, in degrees [0 to 360) - ]; -} - -export function OKLCH_to_OKLab(OKLCH: color): color { - return [ - OKLCH[0], // L is still L - OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a - OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180), // b - ]; -} - -// Premultiplied alpha conversions - -export function rectangular_premultiply(color: color, alpha: number): color { - // given a color in a rectangular orthogonal colorspace - // and an alpha value - // return the premultiplied form - return color.map((c) => c * alpha) as color; -} - -export function rectangular_un_premultiply(color: color, alpha: number): color { - // given a premultiplied color in a rectangular orthogonal colorspace - // and an alpha value - // return the actual color - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c) => c / alpha) as color; -} - -export function polar_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the premultiplied form. - // the index says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as color; -} - -export function polar_un_premultiply(color: color, alpha: number, hueIndex: number): color { - // given a color in a cylindicalpolar colorspace - // and an alpha value - // return the actual color. - // the hueIndex says which entry in the color array corresponds to hue angle - // for example, in OKLCH it would be 2 - // while in HSL it would be 0 - if (alpha === 0) { - return color; // avoid divide by zero - } - return color.map((c, i) => c / (hueIndex === i ? 1 : alpha)) as color; -} - -// Convenience functions can easily be defined, such as -export function hsl_premultiply(color: color, alpha: number): color { - return polar_premultiply(color, alpha, 0); -} diff --git a/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts b/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts deleted file mode 100644 index 168068986..000000000 --- a/plugins/postcss-oklab-function/src/css-color-4/map-gamut.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { OKLCH_to_OKLab } from './conversions'; -import { deltaEOK } from './deltaEOK'; - -type color = [number, number, number]; - -export function mapGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - return binarySearchGamut(startOKLCH, toDestination, fromDestination); -} - -function binarySearchGamut(startOKLCH: color, toDestination: (x: color) => color, fromDestination: (x: color) => color): color { - let min = 0; - let max = startOKLCH[1]; - const current = startOKLCH; - - while (max - min > 0.0001) { - const clipped = clip(toDestination(current)); - const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped))); - // are we inside the gamut (or very close to the boundary, outside) - if (deltaE - 0.02 < 0.0001) { - min = current[1]; - } else { - max = current[1]; - } - // binary search - current[1] = (max + min) / 2; - } - - return clip(toDestination([...current])); -} - -export function clip(color: color): color { - return color.map(val => { - if (val < 0) { - return 0; - } else if (val > 1) { - return 1; - } else { - return val; - } - }) as color; -} - -export function inGamut(x: color): boolean { - const [xX, xY, xZ] = x; - return xX >= -0.0001 && xX <= 1.0001 && xY >= -0.0001 && xY <= 1.0001 && xZ >= -0.0001 && xZ <= 1.0001; -} - diff --git a/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts b/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts deleted file mode 100644 index 776f8c597..000000000 --- a/plugins/postcss-oklab-function/src/css-color-4/multiply-matrices.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Simple matrix (and vector) multiplication - * Warning: No error handling for incompatible dimensions! - * @author Lea Verou 2020 MIT License - * - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js - */ - -// A is m x n. B is n x p. product is m x p. -export function multiplyMatrices(a: Array> | Array, b: Array> | Array): Array> | Array { - const m = a.length; - - let A: Array>; - if (!Array.isArray(a[0])) { - // A is vector, convert to [[a, b, c, ...]] - A = [a as Array]; - } else { - A = a as Array>; - } - - let B: Array>; - if (!Array.isArray(b[0])) { - // B is vector, convert to [[a], [b], [c], ...]] - B = (b as Array).map(x => [x]); - } - - const p = B[0].length; - const B_cols = B[0].map((_, i) => B.map(x => x[i])); // transpose B - let product: Array> | Array = A.map(row => B_cols.map(col => { - if (!Array.isArray(row)) { - return col.reduce((d, f) => d + f * row, 0); - } - - return row.reduce((d, f, i) => d + f * (col[i] || 0), 0); - })); - - if (m === 1) { - product = product[0]; // Avoid [[a, b, c, ...]] - } - - if (p === 1) { - return product.map(x => x[0]); // Avoid [[a], [b], [c], ...]] - } - - return product; -} diff --git a/plugins/postcss-oklab-function/src/css-color-4/utilities.ts b/plugins/postcss-oklab-function/src/css-color-4/utilities.ts deleted file mode 100644 index b3c4368cd..000000000 --- a/plugins/postcss-oklab-function/src/css-color-4/utilities.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @license W3C - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - * @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). - * - * @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js - */ - -import { D50_to_D65, D65_to_D50, gam_2020, gam_P3, gam_sRGB, Lab_to_LCH, Lab_to_XYZ, LCH_to_Lab, lin_2020, lin_2020_to_XYZ, lin_P3, lin_P3_to_XYZ, lin_sRGB, lin_sRGB_to_XYZ, XYZ_to_Lab, XYZ_to_lin_2020, XYZ_to_lin_P3, XYZ_to_lin_sRGB } from './conversions'; - -type color = [number, number, number]; - -// utility functions for color conversions -// needs conversions.js - -export function sRGB_to_luminance(RGB: color): number { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ - // and return luminance (the Y value) - - const XYZ = lin_sRGB_to_XYZ(lin_sRGB(RGB)); - return XYZ[1]; -} - -export function contrast(RGB1: color, RGB2: color): number { - // return WCAG 2.1 contrast ratio - // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio - // for two sRGB values - // given as arrays of 0.0 to 1.0 - - const L1 = sRGB_to_luminance(RGB1); - const L2 = sRGB_to_luminance(RGB2); - - if (L1 > L2) { - return (L1 + 0.05) / (L2 + 0.05); - } - - return (L2 + 0.05) / (L1 + 0.05); -} - -export function sRGB_to_LCH(RGB: color): color { - // convert an array of gamma-corrected sRGB values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_sRGB_to_XYZ(lin_sRGB(RGB))))); -} - -export function P3_to_LCH(RGB: color): color { - // convert an array of gamma-corrected display-p3 values - // in the 0.0 to 1.0 range - // to linear-light display-p3, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_P3_to_XYZ(lin_P3(RGB))))); -} - -export function r2020_to_LCH(RGB: color): color { - // convert an array of gamma-corrected rec.2020 values - // in the 0.0 to 1.0 range - // to linear-light sRGB, then to CIE XYZ, - // then adapt from D65 to D50, - // then convert XYZ to CIE Lab - // and finally, convert to CIE LCH - - return Lab_to_LCH(XYZ_to_Lab(D65_to_D50(lin_2020_to_XYZ(lin_2020(RGB))))); -} - -export function LCH_to_sRGB(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light sRGB - // and finally to gamma corrected sRGB - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_sRGB(XYZ_to_lin_sRGB(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_P3(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light display-p3 - // and finally to gamma corrected display-p3 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_P3(XYZ_to_lin_P3(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -export function LCH_to_r2020(LCH: color): color { - // convert an array of CIE LCH values - // to CIE Lab, and then to XYZ, - // adapt from D50 to D65, - // then convert XYZ to linear-light rec.2020 - // and finally to gamma corrected rec.2020 - // for in-gamut colors, components are in the 0.0 to 1.0 range - // out of gamut colors may have negative components - // or components greater than 1.0 - // so check for that :) - - return gam_2020(XYZ_to_lin_2020(D50_to_D65(Lab_to_XYZ(LCH_to_Lab(LCH))))); -} - -// this is straight from the CSS Color 4 spec - -export function hslToRgb(hsl: color): color { - // For simplicity, this algorithm assumes that the hue has been normalized - // to a number in the half-open range [0, 6), and the saturation and lightness - // have been normalized to the range [0, 1]. It returns an array of three numbers - // representing the red, green, and blue channels of the colors, - // normalized to the range [0, 1] - const [hue, sat, light] = hsl; - - let t2: number; - if (light <= .5) { - t2 = light * (sat + 1); - } else { - t2 = light + sat - (light * sat); - } - const t1 = light * 2 - t2; - const r = hueToRgb(t1, t2, hue + 2); - const g = hueToRgb(t1, t2, hue); - const b = hueToRgb(t1, t2, hue - 2); - return [r, g, b]; -} - -export function hueToRgb(t1: number, t2: number, hue: number): number { - if (hue < 0) { - hue += 6; - } - if (hue >= 6) { - hue -= 6; - } - - if (hue < 1) { - return (t2 - t1) * hue + t1; - } else if (hue < 3) { - return t2; - } else if (hue < 4) { - return (t2 - t1) * (4 - hue) + t1; - } else { - return t1; - } -} - -// These are the naive algorithms from CS Color 4 - -export function naive_CMYK_to_sRGB(CMYK: [number, number, number, number]): color { - // CMYK is an array of four values - // in the range [0.0, 1.0] - // the optput is an array of [RGB] - // also in the [0.0, 1.0] range - // because the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const cyan = CMYK[0], magenta = CMYK[1], yellow = CMYK[2], black = CMYK[3]; - - const red = 1 - Math.min(1, cyan * (1 - black) + black); - const green = 1 - Math.min(1, magenta * (1 - black) + black); - const blue = 1 - Math.min(1, yellow * (1 - black) + black); - - return [red, green, blue]; - -} - -export function naive_sRGB_to_CMYK(RGB: color): [number, number, number, number] { - // RGB is an arravy of three values - // in the range [0.0, 1.0] - // the output is an array of [CMYK] - // also in the [0.0, 1.0] range - // with maximum GCR and (I think) 200% TAC - // the naive algorithm does not generate out of gamut colors - // neither does it generate accurate simulations of practical CMYK colors - - const red = RGB[0], green = RGB[1], blue = RGB[2]; - - const black = 1 - Math.max(red, green, blue); - const cyan = (black == 1.0) ? 0 : (1 - red - black) / (1 - black); - const magenta = (black == 1.0) ? 0 : (1 - green - black) / (1 - black); - const yellow = (black == 1.0) ? 0 : (1 - blue - black) / (1 - black); - - return [cyan, magenta, yellow, black]; -} - -// Chromaticity utilities - -export function XYZ_to_xy(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to x,y chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const sum = X + Y + Z; - return [X / sum, Y / sum]; -} - -export function xy_to_uv(xy: [number, number]): [number, number] { - // convert an x,y chromaticity pair - // to u*,v* chromaticities - - const x = xy[0]; - const y = xy[1]; - const denom = -2 * x + 12 * y + 3; - return [4 * x / denom, 9 * y / denom]; -} - -export function XYZ_to_uv(XYZ: color): [number, number] { - // Convert an array of three XYZ values - // to u*,v* chromaticity coordinates - - const X = XYZ[0]; - const Y = XYZ[1]; - const Z = XYZ[2]; - const denom = X + 15 * Y + 3 * Z; - return [4 * X / denom, 9 * Y / denom]; -} diff --git a/plugins/postcss-oklab-function/src/on-css-function.ts b/plugins/postcss-oklab-function/src/on-css-function.ts index 1f81acd82..0f660a598 100644 --- a/plugins/postcss-oklab-function/src/on-css-function.ts +++ b/plugins/postcss-oklab-function/src/on-css-function.ts @@ -1,10 +1,7 @@ import valueParser from 'postcss-value-parser'; import type { FunctionNode, Dimension, Node, DivNode, WordNode, SpaceNode } from 'postcss-value-parser'; -import { oklabToDisplayP3 } from './convert-oklab-to-display-p3'; -import { oklchToDisplayP3 } from './convert-oklch-to-display-p3'; import { Declaration, Result } from 'postcss'; -import { oklabToSRgb } from './convert-oklab-to-srgb'; -import { oklchToSRgb } from './convert-oklch-to-srgb'; +import { conversions } from '@csstools/color-helpers'; export function onCSSFunctionSRgb(node: FunctionNode) { const value = node.value.toLowerCase(); @@ -34,7 +31,7 @@ export function onCSSFunctionSRgb(node: FunctionNode) { const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes); /** Corresponding Color transformer. */ - const toRGB = value === 'oklab' ? oklabToSRgb : oklchToSRgb; + const toRGB = value === 'oklab' ? conversions.OKLab_to_sRGB : conversions.OKLCH_to_sRGB; /** RGB channels from the source color. */ const channelNumbers: [number, number, number] = [ @@ -100,7 +97,7 @@ export function onCSSFunctionDisplayP3(node: FunctionNode, decl: Declaration, re const [channelDimension1, channelDimension2, channelDimension3] = channelDimensions(nodes); /** Corresponding Color transformer. */ - const toDisplayP3 = value === 'oklab' ? oklabToDisplayP3 : oklchToDisplayP3; + const toDisplayP3 = value === 'oklab' ? conversions.OKLab_to_P3 : conversions.OKLCH_to_P3; /** RGB channels from the source color. */ const channelNumbers: [number, number, number] = [ diff --git a/plugins/postcss-text-decoration-shorthand/CHANGELOG.md b/plugins/postcss-text-decoration-shorthand/CHANGELOG.md index 1e3a6332d..0dde53614 100644 --- a/plugins/postcss-text-decoration-shorthand/CHANGELOG.md +++ b/plugins/postcss-text-decoration-shorthand/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Text Decoration Shorthand +### Unreleased (minor) + +- Add: `@csstools/color-helpers` dependency for the named colors list. + ### 2.1.0 (January 28, 2023) - Add: support for multiple line values (`text-decoration: overline underline;`) diff --git a/plugins/postcss-text-decoration-shorthand/dist/index.cjs b/plugins/postcss-text-decoration-shorthand/dist/index.cjs index fb9145f78..89dcfc4c8 100644 --- a/plugins/postcss-text-decoration-shorthand/dist/index.cjs +++ b/plugins/postcss-text-decoration-shorthand/dist/index.cjs @@ -1 +1 @@ -"use strict";var e=require("postcss-value-parser");const creator=n=>{const a=Object.assign({preserve:!1},n);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const n=new Map;return{OnceExit:()=>{n.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const s=i.parent.index(i);if(i.parent.nodes.some((e=>"decl"===e.type&&"text-decoration"===e.prop.toLowerCase()&&n.get(i.value)===e.value&&i.parent.index(e)!==s)))return;const u=e(i.value),d=u.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(d.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(d.find((e=>"word"===e.type&&r.includes(e.value))))return;const c={line:[],style:null,color:null,thickness:null};for(let r=0;r{const l=Object.assign({preserve:!1},e);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const e=new Map;return{OnceExit:()=>{e.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const a=i.parent.index(i);if(i.parent.nodes.some((t=>"decl"===t.type&&"text-decoration"===t.prop.toLowerCase()&&e.get(i.value)===t.value&&i.parent.index(t)!==a)))return;const c=t(i.value),u=c.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(u.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(u.find((e=>"word"===e.type&&o.includes(e.value))))return;const p={line:[],style:null,color:null,thickness:null};for(let e=0;e{const a=Object.assign({preserve:!1},n);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const n=new Map;return{OnceExit:()=>{n.clear()},Declaration:i=>{if("text-decoration"!==i.prop.toLowerCase())return;const s=i.parent.index(i);if(i.parent.nodes.some((e=>"decl"===e.type&&"text-decoration"===e.prop.toLowerCase()&&n.get(i.value)===e.value&&i.parent.index(e)!==s)))return;const u=e(i.value),d=u.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(d.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(d.find((e=>"word"===e.type&&r.includes(e.value))))return;const c={line:[],style:null,color:null,thickness:null};for(let r=0;r{const l=Object.assign({preserve:!1},e);return{postcssPlugin:"postcss-text-decoration-shorthand",prepare(){const e=new Map;return{OnceExit:()=>{e.clear()},Declaration:a=>{if("text-decoration"!==a.prop.toLowerCase())return;const i=a.parent.index(a);if(a.parent.nodes.some((t=>"decl"===t.type&&"text-decoration"===t.prop.toLowerCase()&&e.get(a.value)===t.value&&a.parent.index(t)!==i)))return;const c=t(a.value),u=c.nodes.filter((e=>"space"!==e.type&&"comment"!==e.type));if(u.find((e=>"var"===e.value.toLowerCase()&&"function"===e.type)))return;if(u.find((e=>"word"===e.type&&o.includes(e.value))))return;const p={line:[],style:null,color:null,thickness:null};for(let e=0;e