Skip to content

perf(media): resize profile and event photos on upload - #1291

Open
leahpeker wants to merge 3 commits into
mainfrom
fix-avatar-thumbnail-perf
Open

leahpeker wants to merge 3 commits into
mainfrom
fix-avatar-thumbnail-perf

Conversation

@leahpeker

Copy link
Copy Markdown
Collaborator

Summary

  • Profile and event photos were stored and served at full original resolution (up to 5MB avatars, 10MB event photos) with no thumbnail generation — every consumer (member lists, comment popovers, tiny avatar thumbnails, event cards) downloaded the full-size original and relied on CSS to shrink it, causing slow loads even for tiny thumbnails.
  • Added resize_image() in config/media_proxy.py (Pillow, already a dependency via Django's ImageField) and wired it into both upload endpoints: avatars cap at 512px, event photos at 1600px.
  • Unreadable formats (e.g. HEIC without a plugin) fall back to storing the original unchanged rather than failing the upload.

Test plan

  • ruff check / ruff format --check clean
  • ty check clean
  • pytest tests/test_photos.py — 21 passed, including new resize-dimension assertions for both profile and event photo uploads
  • Manually verify avatar/event photo upload + display in the app

Note: existing already-uploaded photos in prod/staging remain full-size until re-uploaded; no backfill included in this PR.

Photos were stored and served at full original resolution (up to 5MB
avatars, 10MB event photos) with no thumbnail generation, so every
consumer — member lists, comment popovers, tiny avatar thumbnails,
event cards — downloaded the full-size original and relied on CSS to
shrink it. Resize on upload with Pillow: avatars cap at 512px, event
photos at 1600px. Unreadable formats (e.g. HEIC without a plugin) fall
back to storing the original unchanged rather than failing the upload.
image/heic was accepted as an upload type but Pillow has no built-in
HEIC codec, so resize_image() silently passed the original bytes
through unresized and unconverted. HEIC also doesn't render in
browsers, so stored photos with a .heic extension were unreadable
in the app.

Adds pillow-heif and registers its opener so Pillow can decode HEIC,
and always converts HEIC/HEIF uploads to JPEG on save so the stored
file is actually displayable.
…ression bombs

- skip resize for animated GIFs (thumbnail+save would flatten to one frame)
- apply ImageOps.exif_transpose before resizing so rotated phone photos
  don't render sideways once orientation metadata is dropped on re-encode
- catch Image.DecompressionBombError so a small, high-pixel-count image
  falls back to the original instead of 500ing the upload
- trim resize_image's docstring/comments to satisfy the single-line
  comment convention
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant