Problem
The Awards admin badge is cropped to a fixed 1:1 square on the public Awards page (via image_cropping + Cropper.js, shipped in #1408). For a logo/emblem that isn't already square, the square crop chops off content. Today the workaround is to open an external image editor, pad the image to a square by hand, then upload it — a recurring papercut in the upload flow.
Desired behavior
On upload, if a badge isn't square, offer to pad it to a centered square instead of cropping — adding equal blank margins on the two short sides so the original pixels stay centered and nothing is lost.
- Transparent margins for alpha-capable formats (PNG/WebP); white margins for JPEG.
- Keep the existing crop tool available for cases where cropping is what you want.
Design decision (the tricky part)
The cropper's instant preview is client-side, so naive server-side padding would make that preview lie (it would show a center-crop, not the pad). We resolve this with:
- Server-side Pillow padding (Pillow is already a dependency) — a small, robust transform; no fiddly browser canvas + file-replacement dance.
- A "Pad badge to a square (don't crop)" checkbox in
AwardAdminForm (the one bit of signal needed, since the cropper otherwise always forces a square box). Default on for badges.
- A CSS-only honest preview: when "pad" is checked, hide the interactive cropper (nothing to crop) and show an
object-fit: contain letterbox preview that mirrors exactly how the server will pad. No model/schema change.
When padding is applied, a full-image crop box is stored so the existing crop_corners render path is a no-op on the already-square file.
Scope
Award badge first. The padding helper is field-agnostic, so the same square (245×245) treatment can later extend to Person.image / Sponsor.icon by calling it from their save_model.
Implementation status
Initial implementation drafted on branch 1408-awards-badge-crop:
pad_image_to_square() in website/utils/fileutils.py (+ unit tests)
AwardAdminForm checkbox + AwardAdmin.save_model wiring (+ integration tests)
pad_to_square.js / pad_to_square.css for the live preview
Pending: manual click-through in the admin (wide JPEG → white bars; tall PNG → transparent bars).
Problem
The Awards admin badge is cropped to a fixed 1:1 square on the public Awards page (via
image_cropping+ Cropper.js, shipped in #1408). For a logo/emblem that isn't already square, the square crop chops off content. Today the workaround is to open an external image editor, pad the image to a square by hand, then upload it — a recurring papercut in the upload flow.Desired behavior
On upload, if a badge isn't square, offer to pad it to a centered square instead of cropping — adding equal blank margins on the two short sides so the original pixels stay centered and nothing is lost.
Design decision (the tricky part)
The cropper's instant preview is client-side, so naive server-side padding would make that preview lie (it would show a center-crop, not the pad). We resolve this with:
AwardAdminForm(the one bit of signal needed, since the cropper otherwise always forces a square box). Default on for badges.object-fit: containletterbox preview that mirrors exactly how the server will pad. No model/schema change.When padding is applied, a full-image crop box is stored so the existing
crop_cornersrender path is a no-op on the already-square file.Scope
Award badge first. The padding helper is field-agnostic, so the same square (245×245) treatment can later extend to
Person.image/Sponsor.iconby calling it from theirsave_model.Implementation status
Initial implementation drafted on branch
1408-awards-badge-crop:pad_image_to_square()inwebsite/utils/fileutils.py(+ unit tests)AwardAdminFormcheckbox +AwardAdmin.save_modelwiring (+ integration tests)pad_to_square.js/pad_to_square.cssfor the live previewPending: manual click-through in the admin (wide JPEG → white bars; tall PNG → transparent bars).