Files
immich-folio/lib/thumbhash.ts
ralksta 52fa16c1c8 feat: visual polish & UX — fade-in, theme toggle, scroll-to-top, footer, cursor, badge
- Add FadeIn component (IntersectionObserver scroll-reveal + load animation)
- Add dark/light theme toggle (useSyncExternalStore + localStorage)
- Add scroll-to-top button (appears after 300px scroll)
- Add configurable footer with social links (gallery.yaml)
- Add crosshair cursor on photo grid items
- Add 'X photos' count badge on subpage cover images
- Add light theme color palette in tokens.css
2026-02-14 11:47:26 +01:00

49 lines
1.4 KiB
TypeScript

/**
* ThumbHash utilities for generating blur placeholders and dominant colors.
* Uses the thumbhash package to decode Immich's base64-encoded ThumbHash strings
* into data URLs and hex color values.
*/
import { thumbHashToRGBA, thumbHashToDataURL } from 'thumbhash';
/**
* Convert an Immich base64-encoded ThumbHash into a tiny data URL
* suitable for next/image's blurDataURL prop.
*/
export function thumbHashToBlurDataUrl(base64: string): string {
const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
return thumbHashToDataURL(bytes);
}
/**
* Extract the dominant/average color from a ThumbHash as a hex string.
* Computes the weighted average of all non-transparent pixels.
*/
export function thumbHashToDominantHex(base64: string): string {
const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
const { w, h, rgba } = thumbHashToRGBA(bytes);
let r = 0,
g = 0,
b = 0,
total = 0;
for (let i = 0; i < w * h; i++) {
const a = rgba[i * 4 + 3];
if (a > 0) {
const weight = a / 255;
r += rgba[i * 4] * weight;
g += rgba[i * 4 + 1] * weight;
b += rgba[i * 4 + 2] * weight;
total += weight;
}
}
if (total === 0) return '#888888';
const avg = (v: number) =>
Math.round(v / total)
.toString(16)
.padStart(2, '0');
return `#${avg(r)}${avg(g)}${avg(b)}`;
}