Перейти к содержимому

Получение доминируещего цвета из изображения

colorImages(src, opts) - Передаем сслуку на изображения и опции(?) (ignore?: string[]; scale?: number; skipTransparentPixels?: boolean;), получаем массив всех цветов от большему к меньшему

export interface Opts {
ignore?: string[];
scale?: number;
skipTransparentPixels?: boolean;
}
function getContext(width: string, height: string) {
const canvas = document.createElement("canvas");
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
return canvas.getContext("2d");
}
function getImageData(src: string, scale: number) {
if (scale === void 0) scale = 1;
const img = new Image();
if (!src.startsWith("data")) img.crossOrigin = "Anonymous";
return new Promise((resolve, reject) => {
img.onload = () => {
const width = img.width * scale;
const height = img.height * scale;
const context = getContext(String(width), String(height));
context?.drawImage(img, 0, 0, width, height);
const ref = context?.getImageData(0, 0, width, height);
const data = ref?.data;
resolve(data);
};
const errorHandler = () =>
reject(new Error("An error occurred attempting to load image"));
img.onerror = errorHandler;
img.onabort = errorHandler;
img.src = src;
});
}
function getCounts(data: any, ignore?: string[]) {
const countMap: { [key: string]: any } = {};
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i + 3];
if (+alpha === 0) continue;
const rgbComponents = Array.from(data.subarray(i, i + 3));
if (rgbComponents.indexOf(undefined) !== -1) continue;
const color =
alpha && alpha !== 255
? "rgba(" + rgbComponents.concat([alpha]).join(",") + ")"
: "rgb(" + rgbComponents.join(",") + ")";
if (ignore?.indexOf(color) !== -1) continue;
if (countMap[color]) countMap[color].count++;
else countMap[color] = { color: color, count: 1 };
}
const counts = Object.values(countMap);
return counts.sort((a, b) => b.count - a.count);
}
const defaultOpts = { ignore: [], scale: 1 };
export default async function colorImages(src: string, opts?: Opts) {
if (opts === void 0) opts = defaultOpts;
try {
opts = Object.assign({}, defaultOpts, opts);
const ignore = opts.ignore;
const scale = opts.scale;
if ((!!scale && scale > 1) || (!!scale && scale <= 0)) {
console.warn(
"You set scale to " +
scale +
", which isn't between 0-1. This is either pointless (> 1) or a no-op (≤ 0)"
);
}
const data = await Promise.resolve(getImageData(src, Number(scale)));
return getCounts(data, ignore);
} catch (e) {
return Promise.reject(e);
}
}