diff --git a/docker/frontend/src/Landing.tsx b/docker/frontend/src/Landing.tsx index afa4f12..174044b 100644 --- a/docker/frontend/src/Landing.tsx +++ b/docker/frontend/src/Landing.tsx @@ -25,6 +25,10 @@ const SAMPLE = (n: number) => `/assets/samples/s${n}.jpg`; // that smaller bitmap is what the tag carries, so a saved copy is a screen-sized // one and not the uploader's 4000px original. The save gestures are turned off // on top of it. `data-full` keeps the original address for tests and debugging. +// +// The redraw covers what `object-fit: cover` will show, not the whole frame: a +// 4:3 upload in a 4:5 card would otherwise be handed a stubby bitmap that the +// card had to blow up again — the soft thumbnails the strip used to show. function Shot({ src, alt, filter }: { src: string; alt: string; filter?: string }) { const tag = useRef(null); const [shown, setShown] = useState(src); @@ -33,16 +37,25 @@ function Shot({ src, alt, filter }: { src: string; alt: string; filter?: string let alive = true; const source = new Image(); source.onload = () => { - const box = tag.current?.clientWidth ?? 0; + const boxW = tag.current?.clientWidth ?? 0; + const boxH = tag.current?.clientHeight ?? 0; const scale = Math.min(2, Math.max(1, window.devicePixelRatio || 1)); - const width = Math.min(source.naturalWidth, Math.round(box * scale)); - if (!alive || box === 0 || width >= source.naturalWidth) return; + const width = Math.round(boxW * scale); + const height = Math.round(boxH * scale); + if (!alive || width === 0 || height === 0) return; + if (width >= source.naturalWidth && height >= source.naturalHeight) return; + // The centred slice `cover` would show, cut to exactly the box: scale up + // to fill both sides, keep the middle of the overflow. + const grow = Math.max(width / source.naturalWidth, height / source.naturalHeight); + const sw = width / grow; + const sh = height / grow; const canvas = document.createElement('canvas'); canvas.width = width; - canvas.height = Math.max(1, Math.round((source.naturalHeight * width) / source.naturalWidth)); + canvas.height = height; const ctx = canvas.getContext('2d'); if (!ctx) return; - ctx.drawImage(source, 0, 0, canvas.width, canvas.height); + ctx.imageSmoothingQuality = 'high'; + ctx.drawImage(source, (source.naturalWidth - sw) / 2, (source.naturalHeight - sh) / 2, sw, sh, 0, 0, width, height); setShown(canvas.toDataURL('image/jpeg', 0.85)); }; source.src = src;