Files
IliesAllaliandClaude Opus 5.5 291dde8073 Aperçus flous (BlurHash) pendant le chargement des photos et des portraits
Les photos partent en taille réelle, sans miniature : sur un réseau lent, une vignette restait un carré
vide et un portrait montrait ses initiales. Chaque photo et chaque portrait a maintenant un aperçu flou
aux bonnes couleurs (une chaîne de 28 caractères), affiché jusqu'à l'arrivée de l'image, sans fondu.

- Base : media_items.blurhash et persons.avatarBlurhash (migration additive 20261027_001).
- API : calculé à l'envoi d'une photo et d'un portrait (sharp, 32 px), publié dans le graphe ; les autres
  chemins (Immich, import GEDCOM, propositions acceptées) et les photos d'avant sont rattrapés en tâche de
  fond (lots de 25, puis une passe par minute). Un fichier illisible reçoit un aperçu vide.
- Navigateur : vignettes de la fiche, de la frise et du gestionnaire de souvenirs, portrait de la fiche,
  portraits et souvenirs dessinés sur l'arbre.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:17:58 +01:00

27 lines
1.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { readFile } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
import { decode, isBlurhashValid } from 'blurhash'
import { describe, expect, it } from 'vitest'
import { computeBlurhash } from '../src/lib/blurhash.js'
// Aperçu flou calculé à l'envoi d'une photo : une chaîne valide, aux couleurs de la photo
const demo = (name: string) => fileURLToPath(new URL(`../../frontend/public/demo/${name}`, import.meta.url))
describe('computeBlurhash', () => {
it('donne un aperçu valide pour une vraie photo', async () => {
const hash = await computeBlurhash(await readFile(demo('souvenir-mariage-1918.webp')))
expect(hash).toBeTruthy()
expect(isBlurhashValid(hash as string).result).toBe(true)
// 4 × 3 composantes : 4 + 2 × 4 × 3 - 2 = 28 caractères
expect(hash).toHaveLength(28)
// Photo en noir et blanc : l'aperçu reste gris (rouge, vert et bleu proches)
const px = decode(hash as string, 8, 8)
const [r, g, b] = [px[0], px[1], px[2]]
expect(Math.max(r, g, b) - Math.min(r, g, b)).toBeLessThan(24)
})
it('renvoie null pour un fichier qui n’est pas une image', async () => {
expect(await computeBlurhash(Buffer.from('pas une image'))).toBeNull()
})
})