Skip to content

Instantly share code, notes, and snippets.

@legastero
Created September 7, 2018 21:43
Show Gist options
  • Save legastero/e06c9d7f353d5ec148598fad006deb51 to your computer and use it in GitHub Desktop.
Save legastero/e06c9d7f353d5ec148598fad006deb51 to your computer and use it in GitHub Desktop.
Color Generator
import { createHash } from 'iana-hashes';
export type ColorBlindMode = 'red-green' | 'blue';
export interface CbCr {
cb: number;
cr: number;
}
export interface RGB {
r: number;
g: number;
b: number;
}
export interface ColorizeOptions {
background?: RGB;
colorBlindMode?: ColorBlindMode;
gamma?: number;
}
export const Y = 0.732;
export const KR = 0.299;
export const KG = 0.587;
export const KB = 0.114;
export function convertToAngle(text: string): number {
const digest = createHash('sha-1').update(text).digest();
const output = digest.readUInt16LE(0);
return output / 65536 * 2 * Math.PI;
}
export function adjustForVisionDeficiency(angle: number, colorBlindMode?: ColorBlindMode): number {
switch (colorBlindMode) {
case 'red-green':
return angle % Math.PI;
case 'blue':
return ((angle - Math.PI / 2) % Math.PI) + Math.PI / 2;
default:
return angle;
}
}
export function convertToCbCr(angle: number): CbCr {
const cr = Math.sin(angle);
const cb = Math.cos(angle);
let factor = 1;
if (Math.abs(cr) > Math.abs(cb)) {
factor = 0.5 / Math.abs(cr);
} else {
factor = 0.5 / Math.abs(cb);
}
return { cr: cr * factor, cb: cb * factor };
}
export function convertToRGB({ cb, cr }: CbCr, gamma: number = Y): RGB {
const r = 2 * (1 - KR) * cr + Y;
const b = 2 * (1 - KB) * cb + Y;
const g = (Y - (KR * r) - (KB * b)) / KG;
return {
b: Math.max(0, Math.min(b, 1)),
g: Math.max(0, Math.min(g, 1)),
r: Math.max(0, Math.min(r, 1))
};
}
export function adjustForBackground(input: RGB, background: RGB): RGB {
return {
b: 0.2 * (1 - background.b) + 0.8 * input.b,
g: 0.2 * (1 - background.g) + 0.8 * input.g,
r: 0.2 * (1 - background.r) + 0.8 * input.r
};
}
export function colorize(text: string, opts: ColorizeOptions = {}): RGB {
let angle = convertToAngle(text);
if (opts.colorBlindMode) {
angle = adjustForVisionDeficiency(angle, opts.colorBlindMode);
}
const cbcr = convertToCbCr(angle);
let rgb = convertToRGB(cbcr, opts.gamma || Y);
if (opts.background) {
rgb = adjustForBackground(rgb, opts.background);
}
return rgb;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment