image: add on-demand size=large preview tier (~2048px JPEG q85) #100
Reference in New Issue
Block a user
Delete Branch "feature/image-large-preview"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds a third PhotoSize between Thumb (200px) and Full (original). The
viewer placeholder and map callout previously upscaled a 200px thumb
into a full-screen / full-width view, which looked visibly blocky on
3× devices. The new tier is generated on-demand, disk-cached, and
served via the existing /image endpoint.
Storage layout mirrors the Thumb branch's lookup chain:
libraries when content_hash is known)
Generation pipeline mirrors generate_image_thumbnail:
resize to 2048-long-edge, encode JPEG q85
Never upscales — sources below the 2048 cap re-encode at native size.
Handler offloads decode/resize to web::block to keep the actix worker
free (a 24MP source takes 100–500ms). Writes via tempfile+rename so
concurrent readers can't observe a half-written JPEG. On any
generation failure, falls through to the Full branch (which itself
serves the RAW embedded preview for unrenderable RAW containers).
Video requests for size=large fall back to the existing thumb pipeline
since there's no useful 2048px video tier.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Adds a third PhotoSize between Thumb (200px) and Full (original). The viewer placeholder and map callout previously upscaled a 200px thumb into a full-screen / full-width view, which looked visibly blocky on 3× devices. The new tier is generated on-demand, disk-cached, and served via the existing /image endpoint. Storage layout mirrors the Thumb branch's lookup chain: 1. hash-keyed: <thumbs>/_large/<hash[..2]>/<hash>.jpg (shared across libraries when content_hash is known) 2. library-scoped legacy: <thumbs>/_large/<lib_id>/<rel_path> Generation pipeline mirrors generate_image_thumbnail: - RAW: decode the embedded JPEG preview, apply EXIF orientation, resize to 2048-long-edge, encode JPEG q85 - HEIC/HEIF: ffmpeg with scale + q:v 5 (≈ q85) - everything else: image crate decode + thumbnail() + JpegEncoder Never upscales — sources below the 2048 cap re-encode at native size. Handler offloads decode/resize to web::block to keep the actix worker free (a 24MP source takes 100–500ms). Writes via tempfile+rename so concurrent readers can't observe a half-written JPEG. On any generation failure, falls through to the Full branch (which itself serves the RAW embedded preview for unrenderable RAW containers). Video requests for size=large fall back to the existing thumb pipeline since there's no useful 2048px video tier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>