Skip to main content
View as Markdown

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.

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).