Skip to content

Instantly share code, notes, and snippets.

@Unbinilium
Last active June 21, 2025 14:24
Show Gist options
  • Save Unbinilium/b0b944e0886006f7e590b59f94c7f5e7 to your computer and use it in GitHub Desktop.
Save Unbinilium/b0b944e0886006f7e590b59f94c7f5e7 to your computer and use it in GitHub Desktop.
Color Conv
interface CIE {
x: number;
y: number;
z: number;
};
interface RGB {
r: number;
g: number;
b: number;
};
interface HSV {
h: number;
s: number;
v: number;
};
const gamma_correction_linear_2_srgb = (value: number): number => {
if (value <= 0.0031308) {
return 12.92 * value;
} else {
return (1.055 * Math.pow(value, 1.0 / 2.4)) - 0.055;
}
};
const reference_brightness_normalized = (color: RGB): number => {
return (0.2126 * color.r) + (0.7152 * color.g) + (0.0722 * color.b);
};
const raw_rgb_normalized_2_cie = (color: RGB, calibration_matrix: number[][]): CIE => {
const r = color.r;
const g = color.g;
const b = color.b;
const x = (r * calibration_matrix[0][0]) + (g * calibration_matrix[0][1]) + (b * calibration_matrix[0][2]);
const y = (r * calibration_matrix[1][0]) + (g * calibration_matrix[1][1]) + (b * calibration_matrix[1][2]);
const z = (r * calibration_matrix[2][0]) + (g * calibration_matrix[2][1]) + (b * calibration_matrix[2][2]);
return { x, y, z };
};
const cie_normalized_2_rgb_linear = (color: CIE): RGB => {
const x = color.x;
const y = color.y;
const z = color.z;
const r = (3.2406 * x) - (1.5372 * y) - (0.4986 * z);
const g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z);
const b = (0.0557 * x) - (0.2040 * y) + (1.0570 * z);
return { r, g, b };
};
const rgb_linear_apply_luminance = (color: RGB, luminance: number, eps: number = 0.0001): RGB => {
const current = reference_brightness_normalized(color);
if (current < eps) {
return { r: 0, g: 0, b: 0 };
}
const scale = luminance / current;
return {
r: Math.min(1, color.r * scale),
g: Math.min(1, color.g * scale),
b: Math.min(1, color.b * scale)
};
};
const rgb_linear_2_srgb = (color: RGB): RGB => {
return {
r: gamma_correction_linear_2_srgb(color.r),
g: gamma_correction_linear_2_srgb(color.g),
b: gamma_correction_linear_2_srgb(color.b)
};
};
const srgb_normalized_2_srgb_quantized = (color: RGB): RGB => {
return {
r: Math.round(color.r * 255.0),
g: Math.round(color.g * 255.0),
b: Math.round(color.b * 255.0)
};
};
const srgb_normalized_2_hsv_normalized = (color: RGB): HSV => {
const r = color.r;
const g = color.g;
const b = color.b;
const maxc = Math.max(r, g, b);
const minc = Math.min(r, g, b);
const rangec = maxc - minc;
const v = maxc;
if (minc == maxc) {
return { h: 0, s: 0, v: v };
}
const s = rangec / maxc;
const rc = (maxc - r) / rangec;
const gc = (maxc - g) / rangec;
const bc = (maxc - b) / rangec;
let h: number;
if (r == maxc) {
h = bc - gc;
}
else if (g == maxc) {
h = 2.0 + rc - bc;
}
else {
h = 4.0 + gc - rc;
}
h = (h / 6.0) % 1.0;
if (h < 0) {
h += 1.0;
}
return { h: h, s: s, v: v };
};
const hsv_normalized_color_strength = (current: HSV, target: HSV, weight: HSV): number => {
const delta_h = Math.abs(current.h - target.h);
const delta_s = Math.abs(current.s - target.s);
const delta_v = Math.abs(current.v - target.v);
const weighted_h = Math.min(delta_h, 1.0 - delta_h) * weight.h;
const weighted_s = delta_s * weight.s;
const weighted_v = delta_v * weight.v;
const strength = 1.0 - ((weighted_h + weighted_s + weighted_v) / 3.0);
return Math.max(0.0, Math.min(1.0, strength));
};
const hsv_normalized_presets: Map<string, HSV> = new Map([
["red", { h: 0, s: 1, v: 1 }],
["green", { h: 0.3333, s: 1, v: 1 }],
["blue", { h: 0.6667, s: 1, v: 1 }],
["yellow", { h: 0.1667, s: 1, v: 1 }],
["cyan", { h: 0.5, s: 1, v: 1 }],
["magenta", { h: 0.8333, s: 1, v: 1 }],
["white", { h: 0, s: 0, v: 1 }],
["black", { h: 0, s: 0, v: 0 }],
]);
const hexToRgb = (hex: string): RGB => {
const bigint = parseInt(hex.slice(1), 16);
return {
r: ((bigint >> 16) & 0xff) / 255.0,
g: ((bigint >> 8) & 0xff) / 255.0,
b: (bigint & 0xff) / 255.0
};
};
const printColorInfo = (hex: string): void => {
const rgb = hexToRgb(hex);
const hsv = srgb_normalized_2_hsv_normalized(rgb);
console.log(`Hex: ${hex} \x1b[38;2;${Math.round(rgb.r * 255)};${Math.round(rgb.g * 255)};${Math.round(rgb.b * 255)}m█\x1b[0m`);
console.log(`RGB: ${JSON.stringify(rgb)}`);
console.log(`HSV: ${JSON.stringify(hsv)}`);
console.log(`Strength against presets:`);
hsv_normalized_presets.forEach((preset, name) => {
const strength = hsv_normalized_color_strength(hsv, preset, { h: 8, s: 3, v: 3 });
console.log(` ${name}: ${strength.toFixed(2)}`);
});
};
import * as readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';
async function main() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
while (true) {
try {
const hex = await rl.question('Enter a hex color (e.g., #ff5733): ');
if (!/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(hex)) {
console.log('Invalid hex color format. Please use #RRGGBB or #RGB.');
continue;
}
console.clear();
console.log(`Processing color: ${hex}`);
printColorInfo(hex);
}
catch (error) {
console.error('Error:', error);
rl.close();
break;
}
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment