web: draw each landing photo cut to its own box, not to its own shape
This commit is contained in:
@@ -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<HTMLImageElement>(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;
|
||||
|
||||
Reference in New Issue
Block a user