ifixkart-admin/lib/blurhash.ts

53 lines
2 KiB
TypeScript

import { decode } from "blurhash";
export const DEFAULT_FALLBACK_BLUR_HASH = "LEHV6nWB2yk8pyo0adR*.7kCMdnj";
const cache = new Map<string, string>();
/**
* Decodes a BlurHash string into a Base64 PNG Data URL using browser Canvas API.
* Uses local Map cache to avoid re-decoding identical hashes.
*/
export function blurHashToDataURL(
blurHash?: string | null,
width: number = 32,
height: number = 32
): string {
const hash = blurHash && blurHash.trim().length > 5 ? blurHash : DEFAULT_FALLBACK_BLUR_HASH;
const cacheKey = `${hash}_${width}x${height}`;
if (cache.has(cacheKey)) {
return cache.get(cacheKey)!;
}
if (typeof window === "undefined") {
// SSR static fallback SVG placeholder
return "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23e5e7eb'/%3E%3C/svg%3E";
}
try {
const pixels = decode(hash, width, height);
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
if (!ctx) {
return "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23e5e7eb'/%3E%3C/svg%3E";
}
const imageData = ctx.createImageData(width, height);
imageData.data.set(pixels);
ctx.putImageData(imageData, 0, 0);
const dataUrl = canvas.toDataURL("image/png");
cache.set(cacheKey, dataUrl);
return dataUrl;
} catch (error) {
console.warn("Failed to decode BlurHash, using default fallback:", error);
if (hash !== DEFAULT_FALLBACK_BLUR_HASH) {
return blurHashToDataURL(DEFAULT_FALLBACK_BLUR_HASH, width, height);
}
return "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23e5e7eb'/%3E%3C/svg%3E";
}
}