import { Color, PaletteMap } from "./base.ts"; import { UIPalette } from "./config.ts"; import { cmp } from "../deps.ts"; import { Display } from "./display.ts"; export async function getPaletteMapping( palette: UIPalette, display: Display, ): Promise { // get the colors supported by display const app_colors = palette.map((c): Color[] => Array.isArray(c) ? c : [c]); const all_colors = app_colors.reduce((acc, val) => acc.concat(val), []); const display_colors = await display.setupPalette(all_colors); // rank all supported colors by proximity to each app color let ranked: { color: Color; idx: number; penalty: number; matches: { color: Color; idx: number; distance: number }[]; }[] = []; app_colors.forEach((colors, idx) => { colors.forEach((color, alt) => { ranked.push({ color, idx, penalty: alt + 1, matches: display_colors.map((display_color, didx) => { return { color: display_color, idx: didx, distance: colorDistance(color, display_color), }; }).sort(cmp({ key: (info) => info.distance })), }); }); }); // TODO negatively score colors too much near previously chosen ones // find the best color mapping for each source color const result = palette.map(() => -1); while (ranked.length > 0) { ranked.sort( cmp({ key: (info) => info.matches[0].distance * info.penalty }), ); const best = ranked[0]; const app_idx = best.idx; const display_idx = best.matches[0].idx; result[app_idx] = display_idx; for (const color of ranked) { color.matches = color.matches.filter((match) => match.idx !== display_idx ); } ranked = ranked.filter((color) => color.idx !== app_idx && color.matches.length > 0 ); } return result; } function colorDistance(e1: Color, e2: Color): number { /*return (e2.r - e1.r) * (e2.r - e1.r) + (e2.g - e1.g) * (e2.g - e1.g) + (e2.b - e1.b) * (e2.b - e1.b);*/ const c = (x: number) => Math.round(x * 255); const rmean = (c(e1.r) + c(e2.r)) / 2; const r = c(e1.r) - c(e2.r); const g = c(e1.g) - c(e2.g); const b = c(e1.b) - c(e2.b); return Math.sqrt( (((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8), ); }