From daed101714d4aebc1eb848767a83ea1bc47bf9b3 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Tue, 15 Aug 2023 10:49:14 -0400 Subject: [PATCH 1/6] Compute contrast based on premultipled fg --- src/lib/components/colors/Header.svelte | 21 +++++++++++++++++++++ src/lib/components/colors/index.svelte | 11 ++++++++--- src/lib/components/ratio/index.svelte | 14 ++++++++++---- src/lib/stores.ts | 5 ++++- src/lib/utils.ts | 20 +++++++++++++++++++- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/lib/components/colors/Header.svelte b/src/lib/components/colors/Header.svelte index 7e339c1b..04882063 100644 --- a/src/lib/components/colors/Header.svelte +++ b/src/lib/components/colors/Header.svelte @@ -9,12 +9,16 @@ export let type: 'bg' | 'fg'; export let color: Writable; export let format: ColorFormatId; + export let premultipliedFg: PlainColorObject | null; $: targetSpace = getSpaceFromFormatId(format); $: display = serialize($color, { inGamut: false, format }); $: displayType = type === 'bg' ? 'Background' : 'Foreground'; $: editing = false; $: inputValue = ''; + $: displayPremultipliedFg = premultipliedFg + ? serialize(premultipliedFg, { inGamut: false, format }) + : ''; let hasError = false; // When not editing, sync input value with color (e.g. when sliders change) @@ -89,6 +93,15 @@ {#if hasError}
Could not parse input as a valid color.
{/if} + {#if premultipliedFg} +
+ {displayPremultipliedFg} + +
+ {/if} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index f6abef9f..1ebb089a 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -7,10 +7,6 @@ import { FORMATS } from '$lib/constants'; export const getSpaceFromFormatId = (formatId: ColorFormatId) => formatId === 'hex' ? 'srgb' : formatId; -// hsl should be mixed in the srgb space for a more uniform hue gradient -export const getMixSpaceFromFormatId = (formatId: ColorFormatId) => - ['hex', 'hsl'].includes(formatId) ? 'srgb' : formatId; - export const sliderGradient = ( color: PlainColorObject, channel: string, @@ -102,9 +98,11 @@ export const premultiplyFG = ([fg, bg, format]: [ bgNoAlpha.alpha = 1; const fgNoAlpha = clone(fg); fgNoAlpha.alpha = 1; - const space = getMixSpaceFromFormatId(format); + return mix(fgNoAlpha, bgNoAlpha, 1 - fg.alpha, { - space, - outputSpace: space, + // We always mix in srgb, as we are approximating the color as it will be + // displayed on a monitor. + space: 'srgb', + outputSpace: format, }); }; From 797229dfcc1ccfe4ff463692a45cbbc525e7a0c1 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Thu, 17 Aug 2023 13:56:14 -0400 Subject: [PATCH 4/6] Handle hex --- src/lib/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 1ebb089a..0efff719 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -103,6 +103,6 @@ export const premultiplyFG = ([fg, bg, format]: [ // We always mix in srgb, as we are approximating the color as it will be // displayed on a monitor. space: 'srgb', - outputSpace: format, + outputSpace: getSpaceFromFormatId(format), }); }; From b5ffa4da28b5b98426de636e63d5d88601c0dd95 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Thu, 17 Aug 2023 15:47:46 -0400 Subject: [PATCH 5/6] Add approximate message, hide premultiplied colors when no alpha --- src/lib/components/ratio/index.svelte | 17 +++++++++++------ src/lib/utils.ts | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/lib/components/ratio/index.svelte b/src/lib/components/ratio/index.svelte index 5878fe85..e1ae704b 100644 --- a/src/lib/components/ratio/index.svelte +++ b/src/lib/components/ratio/index.svelte @@ -11,7 +11,8 @@ $: { const bgNoAlpha = clone($bg); bgNoAlpha.alpha = 1; - ratio = contrast(bgNoAlpha, $premultipliedFg, 'WCAG21'); + + ratio = contrast(bgNoAlpha, $premultipliedFg || $fg, 'WCAG21'); } $: displayRatio = Math.round((ratio + Number.EPSILON) * 100) / 100; $: pass = ratio >= RATIOS.AA.Large; @@ -35,12 +36,16 @@

-
-
With alpha
-
- Alpha premultipled + {#if $premultipliedFg} + Because WCAG 2 doesn't account for alpha, this is approximated by + premultiplying the foreground color in the sRGB space. +
+
With alpha
+
+ Alpha premultipled +
-
+ {/if}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 0efff719..471f640f 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -94,6 +94,7 @@ export const premultiplyFG = ([fg, bg, format]: [ bg: PlainColorObject, format: ColorFormatId, ]) => { + if (fg.alpha === 1) return; const bgNoAlpha = clone(bg); bgNoAlpha.alpha = 1; const fgNoAlpha = clone(fg); From 84d573bed39b4a5305f43c51cfca0e9510136f09 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Thu, 17 Aug 2023 15:53:26 -0400 Subject: [PATCH 6/6] Fix tests --- test/js/lib/components/colors/Header.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/js/lib/components/colors/Header.spec.ts b/test/js/lib/components/colors/Header.spec.ts index 7849c24f..3dc428e8 100644 --- a/test/js/lib/components/colors/Header.spec.ts +++ b/test/js/lib/components/colors/Header.spec.ts @@ -11,6 +11,7 @@ describe('Header', () => { const { getByLabelText } = render(Header, { type: 'bg', color, + premultipliedFg: HSL_WHITE, format: 'hsl', }); const input = getByLabelText('Background Color'); @@ -31,6 +32,7 @@ describe('Header', () => { const { getByText, getByLabelText } = render(Header, { type: 'fg', color, + premultipliedFg: HSL_WHITE, format: 'hsl', }); const input = getByLabelText('Foreground Color'); @@ -55,6 +57,7 @@ describe('Header', () => { const { getByText, getByLabelText } = render(Header, { type: 'fg', color, + premultipliedFg: HSL_WHITE, format: 'hsl', }); const input = getByLabelText('Foreground Color'); @@ -78,6 +81,7 @@ describe('Header', () => { const { getByLabelText } = render(Header, { type: 'fg', color, + premultipliedFg: HSL_WHITE, format: 'hsl', }); const input = getByLabelText('Foreground Color');