Created
September 7, 2018 21:43
-
-
Save legastero/e06c9d7f353d5ec148598fad006deb51 to your computer and use it in GitHub Desktop.
Color Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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