Image Transforms
Sovrium transforms stored images on the fly via URL query parameters. Width, height, format, quality, and crop are applied at request time using the Sharp library — no external image service. Transformed outputs are cached, and the original file is never modified.
Transforms work on files from any storage backend (S3, local, bytea) and apply to the standard download endpoint:
GET /api/buckets/{bucket}/files/photos/team-photo.jpg?width=400&height=300&fit=cover
Resize
| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
width |
integer | 1–2500 | original | Target width in pixels. |
height |
integer | 1–2500 | original | Target height in pixels. |
fit |
string | see below | contain |
Resize strategy. |
Providing only one dimension auto-calculates the other, preserving aspect ratio. Values outside 1–2500 return 400 Bad Request.
Fit Modes
| Mode | Behavior |
|---|---|
contain |
Fit within the bounds, preserving aspect ratio (may letterbox). |
cover |
Fill the bounds, preserving aspect ratio (may crop edges). |
fill |
Stretch to exact dimensions, ignoring aspect ratio. |
inside |
Like contain, but never upscales. |
outside |
Like cover, but never downscales. |
Format Conversion
Convert to modern formats to cut file size and improve load times.
# Explicit format
GET /api/buckets/{bucket}/files/photos/banner.png?format=webp
# Preserve source format, skip negotiation
GET /api/buckets/{bucket}/files/photos/banner.png?format=origin
# Automatic: negotiated from the Accept header
GET /api/buckets/{bucket}/files/photos/banner.png
Accept: image/avif,image/webp,image/*
| Format | Extension | Use case |
|---|---|---|
avif |
.avif |
Best compression, newest browsers. |
webp |
.webp |
Strong compression, broad modern support. |
jpeg |
.jpg |
Universal compatibility. |
png |
.png |
Transparency, lossless. |
origin |
(source) | Preserve source format, opt out of negotiation. |
Without a format parameter, the server negotiates the best supported format from the Accept header. The response Content-Type always reflects the actual output. An unsupported format value returns 400 Bad Request.
AVIF is the eco default. Sovrium's frugal-by-default posture sets ECO_IMAGE_FORMAT=avif so server-side transcoding favors the smallest payload. Operators opt out per Ecoconception; format=origin opts out per request.
Quality
GET /api/buckets/{bucket}/files/photos/hero.jpg?quality=95
GET /api/buckets/{bucket}/files/photos/hero.jpg?width=100&quality=30
| Behavior | Result |
|---|---|
quality accepts 1–100 |
Higher values produce larger files. |
| Default | 80 when omitted. |
| Out of range | 400 Bad Request. |
| Applies to lossy formats | JPEG, WebP, AVIF. |
| Ignored for | Lossless PNG output. |
Crop
Crop strategies only apply when fit=cover; otherwise the crop parameter is ignored.
GET /api/buckets/{bucket}/files/photos/team.jpg?width=300&height=300&fit=cover&crop=entropy
GET /api/buckets/{bucket}/files/photos/team.jpg?width=300&height=300&fit=cover&crop=50,30
| Strategy | Syntax | Description |
|---|---|---|
| center | crop=center (default) |
Crop from the center of the image. |
| entropy | crop=entropy |
Smart crop using Shannon entropy. |
| attention | crop=attention |
Smart crop using Sharp's attention strategy. |
| focal | crop=x,y |
Crop around a focal point (x,y as 0–100 percentages). |
Focal-point values outside 0–100 return 400 Bad Request.
Presets
Define named transform presets once via an environment variable, then request them by name.
| Variable | Default | Purpose |
|---|---|---|
STORAGE_TRANSFORM_PRESETS |
(none) | JSON string of named presets. |
STORAGE_TRANSFORM_PRESETS='{"thumbnail":{"width":150,"height":150,"fit":"cover"},"preview":{"width":600,"quality":80},"avatar":{"width":64,"height":64,"fit":"cover","crop":"attention"}}'
# Apply a preset
GET /api/buckets/{bucket}/files/photos/profile.jpg?preset=avatar
# Preset with overrides — explicit params win
GET /api/buckets/{bucket}/files/photos/profile.jpg?preset=thumbnail&quality=95
| Behavior | Result |
|---|---|
| Known preset | Applies its width, height, fit, quality, and crop. |
| Explicit URL params alongside a preset | Override the preset values. |
| Unknown preset name | 400 Bad Request. |
preset used when none configured |
400 Bad Request. |
Preset names must be alphanumeric with hyphens (validated on startup).
Caching
Transformed images are cached so repeated requests are served instantly.
| Mechanism | Detail |
|---|---|
| Response header | Cache-Control: public, max-age=31536000, immutable (1 year, content-addressed). |
ETag |
Hash of the source file plus transform parameters. |
If-None-Match |
A matching ETag returns 304 Not Modified. |
| Disk cache | Stored in STORAGE_TRANSFORM_CACHE_DIR, keyed by sha256(file_path + transform_params). |
| Eviction | LRU, bounded by STORAGE_TRANSFORM_CACHE_MAX_SIZE. |
| Variable | Default | Purpose |
|---|---|---|
STORAGE_TRANSFORM_CACHE_DIR |
OS temp dir | Directory for cached transforms. |
STORAGE_TRANSFORM_CACHE_MAX_SIZE |
500 |
Maximum cache size in MB. |
Original Preservation
| Guarantee | Behavior |
|---|---|
| Source bytes are immutable | Original file is byte-identical after any number of transform requests. |
| No-param request | Returns the unmodified original. |
| Cache deletion | Never affects original-file availability. |
| Non-image files (PDF, CSV) | Transform params return 400 Bad Request. |
| Supported types | JPEG, PNG, WebP, AVIF, GIF, TIFF, SVG (SVG is passed through). |
Related Pages
- Buckets Overview — backends and bucket configuration.
- File Operations — upload, download, delete.
- Signed URLs — transforms can be embedded in signed URLs.
- Attachment Fields — thumbnail transforms on record attachments.
- Ecoconception —
ECO_IMAGE_FORMATand frugal-by-default posture. - Environment Variables — preset and cache configuration.