♻️ Outsource color-related functions to colorUtils.ts
This commit is contained in:
@ -1,47 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "./Button.svelte";
|
import Button from "./Button.svelte";
|
||||||
|
|
||||||
function randomRgbColor(): number[] {
|
import {
|
||||||
const r = Math.floor(Math.random() * 255);
|
cmykToRgb,
|
||||||
const g = Math.floor(Math.random() * 255);
|
randomRgbColor,
|
||||||
const b = Math.floor(Math.random() * 255);
|
rgbToCmyk,
|
||||||
return [r, g, b];
|
stringToRgb,
|
||||||
}
|
score,
|
||||||
|
} from "./colorUtils";
|
||||||
function cmykToRgb(cmyk: number[]): number[] {
|
|
||||||
return [
|
|
||||||
Math.round(255 * (1 - cmyk[0] / 100) * (1 - cmyk[3] / 100)),
|
|
||||||
Math.round(255 * (1 - cmyk[1] / 100) * (1 - cmyk[3] / 100)),
|
|
||||||
Math.round(255 * (1 - cmyk[2] / 100) * (1 - cmyk[3] / 100)),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgbToCmyk(rgb: number[]): number[] {
|
|
||||||
let r = rgb[0] / 255;
|
|
||||||
let g = rgb[1] / 255;
|
|
||||||
let b = rgb[2] / 255;
|
|
||||||
let k = 1 - Math.max(r, g, b);
|
|
||||||
let c = Math.round(((1 - r - k) / (1 - k)) * 100);
|
|
||||||
let m = Math.round(((1 - g - k) / (1 - k)) * 100);
|
|
||||||
let y = Math.round(((1 - b - k) / (1 - k)) * 100);
|
|
||||||
return [c || 0, m || 0, y || 0, Math.round(k * 100)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringToRgb(input: string): number[] | undefined {
|
|
||||||
if (input.startsWith("#")) {
|
|
||||||
let parts = input.match(/([0-f0-F]){2}/g);
|
|
||||||
if (!parts || parts.length != 3) return undefined;
|
|
||||||
return parts.map((e) => parseInt(e, 16));
|
|
||||||
} else if (input.startsWith("rgb(")) {
|
|
||||||
let parts = input.match(/[0-9]{1,3}/g);
|
|
||||||
if (!parts || parts.length != 3) return undefined;
|
|
||||||
return parts.map((e) => parseInt(e));
|
|
||||||
} else if (input.startsWith("cmyk(")) {
|
|
||||||
let parts = input.match(/[0-9]{1,3}/g);
|
|
||||||
if (!parts || parts.length != 4) return undefined;
|
|
||||||
return cmykToRgb(parts.map((e) => parseInt(e)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
Rgb,
|
Rgb,
|
||||||
@ -62,21 +28,6 @@
|
|||||||
else if (mode == Mode.Rgb) guessCmykColor = rgbToCmyk(guessColor);
|
else if (mode == Mode.Rgb) guessCmykColor = rgbToCmyk(guessColor);
|
||||||
}
|
}
|
||||||
$: if (realtimeScore) guessScore = score(targetColor, guessColor);
|
$: if (realtimeScore) guessScore = score(targetColor, guessColor);
|
||||||
|
|
||||||
// From: https://github.com/susam/myrgb/blob/main/myrgb.html#L206
|
|
||||||
function score(rgb1: number[], rgb2: number[]) {
|
|
||||||
const maxRErr = Math.max(rgb1[0], 15 - rgb1[0]);
|
|
||||||
const maxGErr = Math.max(rgb1[1], 15 - rgb1[1]);
|
|
||||||
const maxBErr = Math.max(rgb1[2], 15 - rgb1[2]);
|
|
||||||
const maxDist = Math.sqrt(
|
|
||||||
maxRErr * maxRErr + maxGErr * maxGErr + maxBErr * maxBErr
|
|
||||||
);
|
|
||||||
const rErr = Math.abs(rgb2[0] - rgb1[0]);
|
|
||||||
const gErr = Math.abs(rgb2[1] - rgb1[1]);
|
|
||||||
const bErr = Math.abs(rgb2[2] - rgb1[2]);
|
|
||||||
const dist = Math.sqrt(rErr * rErr + gErr * gErr + bErr * bErr);
|
|
||||||
return Math.max(0, Math.floor(100 * (1 - dist / maxDist)));
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
56
src/colorUtils.ts
Normal file
56
src/colorUtils.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
export function randomRgbColor(): number[] {
|
||||||
|
const r = Math.floor(Math.random() * 255);
|
||||||
|
const g = Math.floor(Math.random() * 255);
|
||||||
|
const b = Math.floor(Math.random() * 255);
|
||||||
|
return [r, g, b];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cmykToRgb(cmyk: number[]): number[] {
|
||||||
|
return [
|
||||||
|
Math.round(255 * (1 - cmyk[0] / 100) * (1 - cmyk[3] / 100)),
|
||||||
|
Math.round(255 * (1 - cmyk[1] / 100) * (1 - cmyk[3] / 100)),
|
||||||
|
Math.round(255 * (1 - cmyk[2] / 100) * (1 - cmyk[3] / 100)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rgbToCmyk(rgb: number[]): number[] {
|
||||||
|
let r = rgb[0] / 255;
|
||||||
|
let g = rgb[1] / 255;
|
||||||
|
let b = rgb[2] / 255;
|
||||||
|
let k = 1 - Math.max(r, g, b);
|
||||||
|
let c = Math.round(((1 - r - k) / (1 - k)) * 100);
|
||||||
|
let m = Math.round(((1 - g - k) / (1 - k)) * 100);
|
||||||
|
let y = Math.round(((1 - b - k) / (1 - k)) * 100);
|
||||||
|
return [c || 0, m || 0, y || 0, Math.round(k * 100)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringToRgb(input: string): number[] | undefined {
|
||||||
|
if (input.startsWith("#")) {
|
||||||
|
let parts = input.match(/([0-f0-F]){2}/g);
|
||||||
|
if (!parts || parts.length != 3) return undefined;
|
||||||
|
return parts.map((e) => parseInt(e, 16));
|
||||||
|
} else if (input.startsWith("rgb(")) {
|
||||||
|
let parts = input.match(/[0-9]{1,3}/g);
|
||||||
|
if (!parts || parts.length != 3) return undefined;
|
||||||
|
return parts.map((e) => parseInt(e));
|
||||||
|
} else if (input.startsWith("cmyk(")) {
|
||||||
|
let parts = input.match(/[0-9]{1,3}/g);
|
||||||
|
if (!parts || parts.length != 4) return undefined;
|
||||||
|
return cmykToRgb(parts.map((e) => parseInt(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From: https://github.com/susam/myrgb/blob/main/myrgb.html#L206
|
||||||
|
export function score(rgb1: number[], rgb2: number[]) {
|
||||||
|
const maxRErr = Math.max(rgb1[0], 15 - rgb1[0]);
|
||||||
|
const maxGErr = Math.max(rgb1[1], 15 - rgb1[1]);
|
||||||
|
const maxBErr = Math.max(rgb1[2], 15 - rgb1[2]);
|
||||||
|
const maxDist = Math.sqrt(
|
||||||
|
maxRErr * maxRErr + maxGErr * maxGErr + maxBErr * maxBErr
|
||||||
|
);
|
||||||
|
const rErr = Math.abs(rgb2[0] - rgb1[0]);
|
||||||
|
const gErr = Math.abs(rgb2[1] - rgb1[1]);
|
||||||
|
const bErr = Math.abs(rgb2[2] - rgb1[2]);
|
||||||
|
const dist = Math.sqrt(rErr * rErr + gErr * gErr + bErr * bErr);
|
||||||
|
return Math.max(0, Math.floor(100 * (1 - dist / maxDist)));
|
||||||
|
}
|
Reference in New Issue
Block a user