/* eslint-disable eqeqeq */ /* eslint-disable prefer-template */ /* eslint-disable prefer-const */ /* eslint-disable prefer-destructuring */ /* eslint-disable one-var */ /* eslint-disable one-var-declaration-per-line */ import { preloadImage } from './files'; /** * HEX > RGB * input: 'xxxxxx' (ex. 'ed15fa') case-insensitive * output: [r, g, b] ([0-255, 0-255, 0-255]) */ export function hex2rgb(param: string): [number, number, number] { return [ parseInt(param.substring(0, 2), 16), parseInt(param.substring(2, 4), 16), parseInt(param.substring(4, 6), 16), ]; } /** * RGB > HEX * input: [r, g, b] ([0-255, 0-255, 0-255]) * output: 'xxxxxx' (ex. 'ff0000') */ export function rgb2hex(param: [number, number, number]) { const p0 = param[0].toString(16); const p1 = param[1].toString(16); const p2 = param[2].toString(16); return (p0.length == 1 ? '0' + p0 : p0) + (p1.length == 1 ? '0' + p1 : p1) + (p2.length == 1 ? '0' + p2 : p2); } /** * Converts an RGB color value to HSV. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSV_color_space. * Assumes r, g, and b are contained in the set [0, 255] and * returns h, s, and v in the set [0, 1]. * * @param Number r The red color value * @param Number g The green color value * @param Number b The blue color value * @return Array The HSV representation */ export function rgb2hsb([r, g, b]: [number, number, number]): [number, number, number] { r /= 255; g /= 255; b /= 255; let max = Math.max(r, g, b), min = Math.min(r, g, b); let h!: number, s: number, v: number = max; let d = max - min; s = max == 0 ? 0 : d / max; if (max == min) { h = 0; // achromatic } else { switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return [h, s, v]; } /** * Converts an HSV color value to RGB. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSV_color_space. * Assumes h, s, and v are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. * * @param Number h The hue * @param Number s The saturation * @param Number v The value * @return Array The RGB representation */ export function hsb2rgb([h, s, v]: [number, number, number]): [number, number, number] { let r!: number, g!: number, b!: number; let i = Math.floor(h * 6); let f = h * 6 - i; let p = v * (1 - s); let q = v * (1 - f * s); let t = v * (1 - (1 - f) * s); switch (i % 6) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } return [ Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), ]; } export async function getAverageColor(url: string): Promise<[number, number, number]> { // Only visit every 5 pixels const blockSize = 5; const defaultRGB: [number, number, number] = [0, 0, 0]; let data; let width; let height; let i = -4; let length; let rgb: [number, number, number] = [0, 0, 0]; let count = 0; const canvas = document.createElement('canvas'); const context = canvas.getContext && canvas.getContext('2d'); if (!context) { return defaultRGB; } const image = await preloadImage(url); height = image.naturalHeight || image.offsetHeight || image.height; width = image.naturalWidth || image.offsetWidth || image.width; canvas.height = height; canvas.width = width; context.drawImage(image, 0, 0); try { data = context.getImageData(0, 0, width, height); } catch (e) { return defaultRGB; } length = data.data.length; // eslint-disable-next-line no-cond-assign while ((i += blockSize * 4) < length) { if (data.data[i + 3] === 0) continue; // Ignore fully transparent pixels ++count; rgb[0] += data.data[i]; rgb[1] += data.data[i + 1]; rgb[2] += data.data[i + 2]; } rgb[0] = Math.floor(rgb[0] / count); rgb[1] = Math.floor(rgb[1] / count); rgb[2] = Math.floor(rgb[2] / count); return rgb; } export function getColorLuma(rgbColor: [number, number, number]) { const [r, g, b] = rgbColor; const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; return luma; } // Function was adapted from https://github.com/telegramdesktop/tdesktop/blob/35ff621b5b52f7e3553fb0f990ea13ade7101b8e/Telegram/SourceFiles/data/data_wall_paper.cpp#L518 export function getPatternColor(rgbColor: [number, number, number]) { let [hue, saturation, value] = rgb2hsb(rgbColor); saturation = Math.min(1, saturation + 0.05 + 0.1 * (1 - saturation)); value = value > 0.5 ? Math.max(0, value * 0.65) : Math.max(0, Math.min(1, 1 - value * 0.65)); return `hsla(${hue * 360}, ${saturation * 100}%, ${value * 100}%, .4)`; }