Embrace chroma.js and okLCH

This commit is contained in:
Lim Chee Aun 2024-11-12 17:45:28 +08:00
parent c6e562c62e
commit cc591237f5
4 changed files with 24 additions and 100 deletions

View file

@ -26,6 +26,7 @@
"@lingui/macro": "~4.13.0", "@lingui/macro": "~4.13.0",
"@lingui/react": "~4.13.0", "@lingui/react": "~4.13.0",
"@szhsin/react-menu": "~4.2.2", "@szhsin/react-menu": "~4.2.2",
"chroma-js": "~3.1.2",
"compare-versions": "~6.1.1", "compare-versions": "~6.1.1",
"fast-blurhash": "~1.1.4", "fast-blurhash": "~1.1.4",
"fast-equals": "~5.0.1", "fast-equals": "~5.0.1",

View file

@ -10,7 +10,7 @@ import {
} from 'preact/hooks'; } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook'; 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 isRTL from '../utils/is-rtl';
import showToast from '../utils/show-toast'; import showToast from '../utils/show-toast';
import states from '../utils/states'; import states from '../utils/states';
@ -116,59 +116,28 @@ function MediaModal({
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, []); }, []);
const mediaOklabColors = useMemo(() => { const mediaOkColors = useMemo(() => {
return mediaAttachments?.map((media) => { return mediaAttachments?.map((media) => {
const { blurhash } = media; const { blurhash } = media;
if (blurhash) { if (blurhash) {
const averageColor = getBlurHashAverageColor(blurhash); const averageColor = getBlurHashAverageColor(blurhash);
return rgb2oklab(averageColor); return rgb2oklch(averageColor);
} }
return null; return null;
}); });
}, [mediaAttachments]); }, [mediaAttachments]);
// const mediaAccentColors = useMemo(() => {
// return mediaOklabColors?.map((labAverageColor) => {
// if (labAverageColor) {
// return oklab2rgb([0.6, labAverageColor[1], labAverageColor[2]]);
// }
// return null;
// });
// }, [mediaOklabColors]);
const mediaAccentColors = useMemo(() => { const mediaAccentColors = useMemo(() => {
return mediaOklabColors?.map((labAverageColor) => { return mediaOkColors?.map((okColor) => {
if (labAverageColor) { if (okColor) {
return { return {
light: oklab2rgb([0.95, labAverageColor[1], labAverageColor[2]]), light: oklch2rgb([0.95, 0.01, okColor[2]]),
dark: oklab2rgb([0.25, labAverageColor[1], labAverageColor[2]]), dark: oklch2rgb([0.35, 0.01, okColor[2]]),
default: oklab2rgb([0.6, labAverageColor[1], labAverageColor[2]]), default: oklch2rgb([0.6, okColor[1], okColor[2]]),
}; };
} }
return {}; 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 mediaAccentGradients = useMemo(() => {
const gap = 5; const gap = 5;
const range = 100 / mediaAccentColors.length; const range = 100 / mediaAccentColors.length;

20
src/locales/en.po generated
View file

@ -106,7 +106,7 @@ msgstr ""
#: src/components/account-info.jsx:1118 #: src/components/account-info.jsx:1118
#: src/components/compose.jsx:2488 #: src/components/compose.jsx:2488
#: src/components/media-alt-modal.jsx:45 #: 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:1721
#: src/components/status.jsx:1738 #: src/components/status.jsx:1738
#: src/components/status.jsx:1862 #: src/components/status.jsx:1862
@ -410,7 +410,7 @@ msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:39 #: src/components/keyboard-shortcuts-help.jsx:39
#: src/components/list-add-edit.jsx:35 #: src/components/list-add-edit.jsx:35
#: src/components/media-alt-modal.jsx:33 #: 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/notification-service.jsx:156
#: src/components/report-modal.jsx:75 #: src/components/report-modal.jsx:75
#: src/components/shortcuts-settings.jsx:230 #: src/components/shortcuts-settings.jsx:230
@ -858,13 +858,13 @@ msgid "Type to search GIFs"
msgstr "" msgstr ""
#: src/components/compose.jsx:3491 #: src/components/compose.jsx:3491
#: src/components/media-modal.jsx:492 #: src/components/media-modal.jsx:461
#: src/components/timeline.jsx:889 #: src/components/timeline.jsx:889
msgid "Previous" msgid "Previous"
msgstr "" msgstr ""
#: src/components/compose.jsx:3509 #: src/components/compose.jsx:3509
#: src/components/media-modal.jsx:511 #: src/components/media-modal.jsx:480
#: src/components/timeline.jsx:906 #: src/components/timeline.jsx:906
msgid "Next" msgid "Next"
msgstr "" msgstr ""
@ -1185,27 +1185,27 @@ msgstr ""
msgid "Speak" msgid "Speak"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:399 #: src/components/media-modal.jsx:368
msgid "Open original media in new window" msgid "Open original media in new window"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:403 #: src/components/media-modal.jsx:372
msgid "Open original media" msgid "Open original media"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:419 #: src/components/media-modal.jsx:388
msgid "Attempting to describe image. Please wait…" msgid "Attempting to describe image. Please wait…"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:434 #: src/components/media-modal.jsx:403
msgid "Failed to describe image" msgid "Failed to describe image"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:444 #: src/components/media-modal.jsx:413
msgid "Describe image…" msgid "Describe image…"
msgstr "" msgstr ""
#: src/components/media-modal.jsx:467 #: src/components/media-modal.jsx:436
msgid "View post" msgid "View post"
msgstr "" msgstr ""

View file

@ -1,52 +1,6 @@
// https://gist.github.com/earthbound19/e7fe15fdf8ca3ef814750a61bc75b5ce import oklab2rgb from 'chroma-js/src/io/oklab/oklab2rgb.js';
function clamp(value, min, max) { import rgb2oklab from 'chroma-js/src/io/oklab/rgb2oklab.js';
return Math.max(Math.min(value, max), min); import oklch2rgb from 'chroma-js/src/io/oklch/oklch2rgb.js';
} import rgb2oklch from 'chroma-js/src/io/oklch/rgb2oklch.js';
const gammaToLinear = (c) => export { oklab2rgb, rgb2oklab, oklch2rgb, rgb2oklch };
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];
}