Image Processing
Picora can resize, crop, and reformat any image on the fly by appending query parameters to its URL. No uploads, no batch jobs — just edit the URL and the image is regenerated through image-serve and cached at the CDN edge for next time.
https://media.picora.me/abc123.jpg ?w=800 &h=600 &fit=cover &fmt=webp &q=85The URL above asks for the image scaled to fill an 800×600 box (cropping if needed), encoded as WebP at quality 85.
Supported parameters
| Parameter | Meaning | Range | Default |
|---|---|---|---|
w | Width in pixels | 1–4096 | original |
h | Height in pixels | 1–4096 | original |
fit | Scaling strategy | cover / contain / fill / inside / outside | inside |
fmt | Output format | webp / jpeg / png / avif | original |
q | Quality (jpeg / webp / avif) | 1–100 | 85 |
wm | Watermark template id (pro_plus only) | nanoid(21) | none |
Anything else — for instance ?rotate=90, ?filter=blur, or ?text=hi — is rejected with 400 INVALID_IMAGE_PARAMS. This is intentional: the strict whitelist keeps the CDN cache key space bounded and prevents abuse vectors like SVG filter injection or text-overlay bombing.
Caching
A processed result is stored under variants/{imageId}/{paramsHash}.{ext} in object storage and cached at the CDN edge with Cache-Control: public, max-age=31536000. The cache key is a SHA-256 of the canonicalized parameter set, so callers passing the same parameters in any order share a cache hit.
Hit rate goal in production: ≥ 95 % measured over 24 hours.
Live preview
When you tweak parameters in the picora-center UI builder, the SDK appends ?preview=1 to the test URL. The server still processes the image but does not persist the result to storage and returns Cache-Control: no-store. This avoids polluting the cache with hundreds of throwaway combinations while you scrub a slider. Click “Copy URL” — the copied value never carries preview=1, so the first real visit triggers a normal cache write.
?preview=1 is rate-limited to 60 req/min per user.
Cross-platform consistency
The same URL produces visually identical output on picora.me (Cloudflare R2) and picora.cn (Aliyun OSS). The contract is “consistency tolerance < 5 % pixel diff” measured over the bundled validation set — Aliyun’s ?x-oss-process=image/resize produces slightly different aliasing than R2 + WebAssembly resize, but no consumer-perceptible difference.
If you need pixel-perfect determinism, generate the variant once on a single platform and serve the resulting variants/... key directly.
Errors
| Code | When |
|---|---|
INVALID_IMAGE_PARAMS | A parameter is out of range, mistyped, or unknown |
IMAGE_NOT_FOUND | The image was deleted or never existed |
IMAGE_PROCESS_FAILED | Internal error during resize / encode (retry once before giving up) |
Errors from media.picora.me return a small placeholder PNG rather than JSON, so a <img src> tag renders gracefully even when the request fails.