diff --git a/package.json b/package.json index 006694b2..5b53c657 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@lingui/macro": "~4.13.0", "@lingui/react": "~4.13.0", "@szhsin/react-menu": "~4.2.2", + "chroma-js": "~3.1.2", "compare-versions": "~6.1.1", "fast-blurhash": "~1.1.4", "fast-equals": "~5.0.1", diff --git a/src/components/media-modal.jsx b/src/components/media-modal.jsx index 1d2d1be3..8d277afd 100644 --- a/src/components/media-modal.jsx +++ b/src/components/media-modal.jsx @@ -10,7 +10,7 @@ import { } from 'preact/hooks'; import { useHotkeys } from 'react-hotkeys-hook'; -import { oklab2rgb, rgb2oklab } from '../utils/color-utils'; +import { oklch2rgb, rgb2oklch } from '../utils/color-utils'; import isRTL from '../utils/is-rtl'; import showToast from '../utils/show-toast'; import states from '../utils/states'; @@ -116,59 +116,28 @@ function MediaModal({ return () => clearTimeout(timer); }, []); - const mediaOklabColors = useMemo(() => { + const mediaOkColors = useMemo(() => { return mediaAttachments?.map((media) => { const { blurhash } = media; if (blurhash) { const averageColor = getBlurHashAverageColor(blurhash); - return rgb2oklab(averageColor); + return rgb2oklch(averageColor); } return null; }); }, [mediaAttachments]); - // const mediaAccentColors = useMemo(() => { - // return mediaOklabColors?.map((labAverageColor) => { - // if (labAverageColor) { - // return oklab2rgb([0.6, labAverageColor[1], labAverageColor[2]]); - // } - // return null; - // }); - // }, [mediaOklabColors]); const mediaAccentColors = useMemo(() => { - return mediaOklabColors?.map((labAverageColor) => { - if (labAverageColor) { + return mediaOkColors?.map((okColor) => { + if (okColor) { return { - light: oklab2rgb([0.95, labAverageColor[1], labAverageColor[2]]), - dark: oklab2rgb([0.25, labAverageColor[1], labAverageColor[2]]), - default: oklab2rgb([0.6, labAverageColor[1], labAverageColor[2]]), + light: oklch2rgb([0.95, 0.01, okColor[2]]), + dark: oklch2rgb([0.35, 0.01, okColor[2]]), + default: oklch2rgb([0.6, okColor[1], okColor[2]]), }; } return {}; }); }); - // const mediaAccentGradient = useMemo(() => { - // const gap = 5; - // const range = 100 / mediaAccentColors.length; - // return ( - // mediaAccentColors - // ?.map((color, i) => { - // const start = i * range + gap; - // const end = (i + 1) * range - gap; - // if (color) { - // return ` - // rgba(${color?.join(',')}, 0.4) ${start}%, - // rgba(${color?.join(',')}, 0.4) ${end}% - // `; - // } - - // return ` - // transparent ${start}%, - // transparent ${end}% - // `; - // }) - // ?.join(', ') || 'transparent' - // ); - // }, [mediaAccentColors]); const mediaAccentGradients = useMemo(() => { const gap = 5; const range = 100 / mediaAccentColors.length; diff --git a/src/locales/en.po b/src/locales/en.po index 2ae08b2e..29a768ab 100644 --- a/src/locales/en.po +++ b/src/locales/en.po @@ -106,7 +106,7 @@ msgstr "" #: src/components/account-info.jsx:1118 #: src/components/compose.jsx:2488 #: src/components/media-alt-modal.jsx:45 -#: src/components/media-modal.jsx:388 +#: src/components/media-modal.jsx:357 #: src/components/status.jsx:1721 #: src/components/status.jsx:1738 #: src/components/status.jsx:1862 @@ -410,7 +410,7 @@ msgstr "" #: src/components/keyboard-shortcuts-help.jsx:39 #: src/components/list-add-edit.jsx:35 #: src/components/media-alt-modal.jsx:33 -#: src/components/media-modal.jsx:352 +#: src/components/media-modal.jsx:321 #: src/components/notification-service.jsx:156 #: src/components/report-modal.jsx:75 #: src/components/shortcuts-settings.jsx:230 @@ -858,13 +858,13 @@ msgid "Type to search GIFs" msgstr "" #: src/components/compose.jsx:3491 -#: src/components/media-modal.jsx:492 +#: src/components/media-modal.jsx:461 #: src/components/timeline.jsx:889 msgid "Previous" msgstr "" #: src/components/compose.jsx:3509 -#: src/components/media-modal.jsx:511 +#: src/components/media-modal.jsx:480 #: src/components/timeline.jsx:906 msgid "Next" msgstr "" @@ -1185,27 +1185,27 @@ msgstr "" msgid "Speak" msgstr "" -#: src/components/media-modal.jsx:399 +#: src/components/media-modal.jsx:368 msgid "Open original media in new window" msgstr "" -#: src/components/media-modal.jsx:403 +#: src/components/media-modal.jsx:372 msgid "Open original media" msgstr "" -#: src/components/media-modal.jsx:419 +#: src/components/media-modal.jsx:388 msgid "Attempting to describe image. Please wait…" msgstr "" -#: src/components/media-modal.jsx:434 +#: src/components/media-modal.jsx:403 msgid "Failed to describe image" msgstr "" -#: src/components/media-modal.jsx:444 +#: src/components/media-modal.jsx:413 msgid "Describe image…" msgstr "" -#: src/components/media-modal.jsx:467 +#: src/components/media-modal.jsx:436 msgid "View post" msgstr "" diff --git a/src/utils/color-utils.js b/src/utils/color-utils.js index 02f5eed7..52c8e3d8 100644 --- a/src/utils/color-utils.js +++ b/src/utils/color-utils.js @@ -1,52 +1,6 @@ -// https://gist.github.com/earthbound19/e7fe15fdf8ca3ef814750a61bc75b5ce -function clamp(value, min, max) { - return Math.max(Math.min(value, max), min); -} +import oklab2rgb from 'chroma-js/src/io/oklab/oklab2rgb.js'; +import rgb2oklab from 'chroma-js/src/io/oklab/rgb2oklab.js'; +import oklch2rgb from 'chroma-js/src/io/oklch/oklch2rgb.js'; +import rgb2oklch from 'chroma-js/src/io/oklch/rgb2oklch.js'; -const gammaToLinear = (c) => - c >= 0.04045 ? Math.pow((c + 0.055) / 1.055, 2.4) : c / 12.92; -const linearToGamma = (c) => - c >= 0.0031308 ? 1.055 * Math.pow(c, 1 / 2.4) - 0.055 : 12.92 * c; - -export function rgb2oklab([r, g, b]) { - r = gammaToLinear(r / 255); - g = gammaToLinear(g / 255); - b = gammaToLinear(b / 255); - var l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; - var m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b; - var s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b; - l = Math.cbrt(l); - m = Math.cbrt(m); - s = Math.cbrt(s); - return [ - l * +0.2104542553 + m * +0.793617785 + s * -0.0040720468, - l * +1.9779984951 + m * -2.428592205 + s * +0.4505937099, - l * +0.0259040371 + m * +0.7827717662 + s * -0.808675766, - ]; -} - -export function oklab2rgb([L, a, b]) { - var l = L + a * +0.3963377774 + b * +0.2158037573; - var m = L + a * -0.1055613458 + b * -0.0638541728; - var s = L + a * -0.0894841775 + b * -1.291485548; - // The ** operator here cubes; same as l_*l_*l_ in the C++ example: - l = l ** 3; - m = m ** 3; - s = s ** 3; - var r = l * +4.0767416621 + m * -3.3077115913 + s * +0.2309699292; - var g = l * -1.2684380046 + m * +2.6097574011 + s * -0.3413193965; - var b = l * -0.0041960863 + m * -0.7034186147 + s * +1.707614701; - // Convert linear RGB values returned from oklab math to sRGB for our use before returning them: - r = 255 * linearToGamma(r); - g = 255 * linearToGamma(g); - b = 255 * linearToGamma(b); - // OPTION: clamp r g and b values to the range 0-255; but if you use the values immediately to draw, JavaScript clamps them on use: - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - // OPTION: round the values. May not be necessary if you use them immediately for rendering in JavaScript, as JavaScript (also) discards decimals on render: - r = Math.round(r); - g = Math.round(g); - b = Math.round(b); - return [r, g, b]; -} +export { oklab2rgb, rgb2oklab, oklch2rgb, rgb2oklch };