| 123456789101112131415161718192021222324252627282930313233343536373839404142 |
- import sharp from "sharp";
- const hex = (rgb) => `#${rgb.map((value) => Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
- const mix = (a, b, ratio) => a.map((value, index) => value * (1 - ratio) + b[index] * ratio);
- export async function compileDesignTokens(productBuffer) {
- const { data, info } = await sharp(productBuffer).resize({ width: 160 }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
- const buckets = new Map();
- for (let index = 0; index < data.length; index += info.channels) {
- if (data[index + 3] < 180) continue;
- const rgb = [data[index], data[index + 1], data[index + 2]];
- const max = Math.max(...rgb); const min = Math.min(...rgb);
- if (max > 242 && max - min < 12) continue;
- const key = rgb.map((value) => Math.floor(value / 32) * 32).join(",");
- buckets.set(key, (buckets.get(key) || 0) + 1);
- }
- const ranked = [...buckets.entries()].map(([key, count]) => {
- const rgb = key.split(",").map(Number).map((value) => value + 16);
- const saturation = Math.max(...rgb) - Math.min(...rgb);
- const luminance = rgb[0] * 0.2126 + rgb[1] * 0.7152 + rgb[2] * 0.0722;
- return { rgb, count, saturation, luminance, score: count * (1 + saturation / 55) * (luminance < 210 ? 1.25 : 0.5) };
- }).sort((a, b) => b.score - a.score);
- const primary = ranked.find((item) => item.saturation >= 18 && item.luminance < 190)?.rgb
- || ranked[0]?.rgb
- || [38, 49, 38];
- const accentCandidate = ranked.find((item) => (
- item.saturation > 24
- && item.rgb[0] > 120
- && item.rgb[0] >= item.rgb[1] * 0.95
- && item.rgb[1] > item.rgb[2] * 1.12
- ));
- const accent = accentCandidate?.rgb || mix(primary, [218, 160, 72], 0.58);
- return {
- primary: hex(primary),
- primarySoft: hex(mix(primary, [255, 255, 255], 0.72)),
- primaryDark: hex(mix(primary, [15, 20, 16], 0.42)),
- surface: hex(mix(primary, [250, 247, 239], 0.88)),
- accent: hex(accent),
- ink: "#1D2922",
- lightText: "#FAF7EF",
- };
- }
|