import { Buffer } from 'buffer' import JPEG from 'jpeg-js' import PNG from 'png-ts' import { DEFAULT_COLOR, predefinedTokenColors } from '../constants' export default async function getColor(image: string | undefined, checkDistance = false) { if (!image) { return DEFAULT_COLOR } if (image in predefinedTokenColors) { return predefinedTokenColors[image] } try { const data = await fetch(image) const buffer = await data.arrayBuffer() const arrayBuffer = Buffer.from(buffer) const type = data.headers.get('content-type') ?? '' return getAverageColor(arrayBuffer, type, checkDistance) } catch (e) { return DEFAULT_COLOR } } function getAverageColor(arrayBuffer: Uint8Array, type: string, checkDistance: boolean) { let pixels switch (type) { case 'image/png': { const image = PNG.load(arrayBuffer) pixels = image.decode() break } case 'image/jpeg' || 'image/jpg': { const jpeg = JPEG.decode(arrayBuffer, { useTArray: true }) pixels = jpeg.data break } default: { return DEFAULT_COLOR } } const pixelCount = pixels.length / 4 let transparentPixels = 0 let r = 0 let g = 0 let b = 0 for (let i = 0; i < pixelCount; i++) { if (pixels[i * 4 + 3] === 0) { transparentPixels++ continue } r += pixels[i * 4] g += pixels[i * 4 + 1] b += pixels[i * 4 + 2] } r = Math.floor(r / (pixelCount - transparentPixels)) g = Math.floor(g / (pixelCount - transparentPixels)) b = Math.floor(b / (pixelCount - transparentPixels)) if (checkDistance) { const distance = Math.sqrt(Math.pow(r - 255, 2) + Math.pow(g - 255, 2) + Math.pow(b - 255, 2)) if (distance < 50) { return DEFAULT_COLOR } } return [r, g, b] }