Controls log detail. RUST_LOG overrides this value when set.
Docs / Configuration & operations / Config key reference
Config key reference v0.2.0
Every key in config.toml, with its type, default and what it does. All of them are
optional, and picturium runs fine without a config file at all.
Configuration & operations explains how config is loaded and how to
size caches, concurrency, CORS and logs. Signing, validators, cache busting and capacity
are covered in the Request model.
- To use an environment variable, uppercase the key, add the
PICTURIUM__prefix, and put__between levels. For example,output.encoder.avif.bitdepthbecomesPICTURIUM__OUTPUT__ENCODER__AVIF__BITDEPTH. Environment variables override the file. - List values (
cors.allowed_origins,data.serve,output.format_priority,output.metadata) are comma-separated in an environment variable. - picturium validates values at startup. An out-of-range value or unknown key prevents the server from starting.
- The repository includes
config.toml.examplewith the same defaults and inline comments.
[server]
Address used by the HTTP listener. 0.0.0.0 accepts connections on every network interface.
TCP port the listener binds to.
Maximum number of images rendered at once. 0 means twice the logical CPU count.
Maximum number of requests waiting for a worker. A full queue rejects new requests with 503.
[security]
Requires every request to include a valid HMAC token for its path and query. When false, requests do not need a signature.
Shared secret used for HMAC-SHA256 signatures. Generate one with openssl rand -hex 48. Used only when signature_enabled is true.
Bearer token that unlocks details on GET /health (version, worker and queue counts, memory statistics) when sent as Authorization: Bearer <token> or as ?token=<token>. The query form ends up in access logs, so prefer the header. Without a token /health returns only the status; a wrong token gets 401. Empty disables the details.
[cors]
Origins allowed to read responses across origins. "*" allows all origins; otherwise each origin must match exactly. Invalid entries are ignored.
[vips]
Turns on libvips leak checking and prints the objects still alive at shutdown. Diagnostics only; it adds overhead.
Threads libvips may use inside a single operation. Total threads ≈ server.workers × vips.concurrency.
[data]
Root folder for source files. Requests cannot access files outside it.
Non-image file extensions that picturium may return unchanged, such as "zip" or "txt". ["*"] allows every extension; unlisted types return 415.
[cache]
Both cache tiers are enabled by default. picturium checks memory first, then disk. A result that fits neither is returned without being cached.
Directory used by the disk cache. Only one running process can use it at a time.
Sent verbatim as Cache-Control on every successful response. A force=true response sends no-store instead.
Enables the memory cache, which is checked before disk.
Total memory budget for the memory tier. Each entry is charged its own size.
Largest single response kept in memory. Bigger renders fall through to disk, or are served uncached.
Enables the disk cache and locks the cache directory for this process.
Effective on-disk capacity, shared by finished responses and Office / SVG / video intermediates. foyer evicts and reclaims automatically.
Largest single response written to disk. Also foyer's block size, the unit it reclaims in. Changing it discards the existing disk cache.
[svg]
Allow loading SVG files larger than libvips' 10 MB safety limit.
Resolution an SVG is rasterised at when the request gives no dpi.
Allows an SVG rendered as PDF (f=pdf) to embed files referenced by <image href>. References must stay inside the data directory; absolute paths and ".." are rejected. Keep this off when users should not read each other's files.
[pdf]
Resolution a PDF page is rasterised at when the request gives no dpi.
Colour behind PDF and Office pages when they are rasterised. A bg parameter on the request wins. Must parse as a colour or startup fails.
PDFs larger than this are not rendered. The original file is served as-is instead, or the fallback is rendered when the request has one.
Most pages one request may select with page / pages. Larger selections get a 400, or the fallback when the request has one. Applies to PDF, Office and vector-art sources; animated images are not limited by it.
Refuses to render a PDF when its first page, at the resolved render scale, would exceed this many pixels. The request fails with a 500, or renders the fallback when the request has one.
[office]
How long LibreOffice may take to convert one document before the request fails.
Hard limit for one LibreOffice run. A conversion that outlives conversion_timeout keeps going in the background to fill the cache until this limit kills it. Must not be lower than conversion_timeout.
Maximum number of LibreOffice processes running at once, background conversions included. Further conversions wait for a free slot. 0 means the logical CPU count.
[vector]
How long Inkscape may take to convert one .ai / .cdr / .cmx / .cdt / .eps / .dxf source before the request fails.
[video]
See Animation & video for request syntax and how these defaults affect still-frame and clip extraction.
Frame position used when the request does not set t. The one-second default avoids many black or fading first frames.
Time budget for pulling a single frame out of a video.
Time limit for extracting a clip. Unlike a single-frame seek, a clip decodes every frame in its range.
Frames sampled for a clip when anim gives no count.
Sample rate for a clip when anim gives no timing or fps.
Hard ceiling on frames in one clip, whatever anim=frames asks for.
[image]
Default sizing and layout values. Each value can be overridden by the matching URL parameter.
See Cropping for how image.crop_gravity controls the grouped crop= parameter.
Apply the EXIF orientation tag so the image faces the right way. Request override: autorot.
Allows output larger than the source. When false, picturium shrinks the requested box to fit the original. Request override: upsize.
How area added by padding or aspect-ratio fill is filled. bg uses the background colour. Request override: extend.
Controls how the image fills the requested box: cover crops overflow, contain adds padding, and force stretches. Request override: fit.
Chooses which part a cover crop keeps, or where a contained image sits. attention and entropy use libvips smart cropping. Request override: g.
Default gravity for the crop= parameter specifically — it does not inherit image.gravity.
Resampling kernel used when scaling. Request override: resample.
[watermark]
Defaults for watermarks when enabled is true. Each key can be overridden with watermark=…, and watermark=false disables the mark for one request. An image takes priority over text.
See Watermarking for request syntax, source precedence, placement,
and complete configuration examples.
Adds a watermark to every supported response unless the request opts out. Set image.path or text.text before enabling it.
Where the mark sits. repeat tiles it across the image.
Mark opacity, in percent.
CSS-like shorthand. Gap between the mark and the edge, and between tiles under position = "repeat".
Rotation of the mark, any angle.
Largest fraction of the image width and height the mark itself may cover. Padding can reduce the available space further.
Operator-supplied path to the watermark image. Not confined to the data directory, unlike a request-supplied watermark=image: path.
Scale factor applied to the watermark image.
Text drawn as the watermark when no image path is set.
Font used for a text watermark.
Font size for a text watermark.
Colour of a text watermark. Must parse as a colour or startup fails.
[output]
See Output format & quality for how these defaults affect a request.
Order used by f=auto when checking the client's Accept header. It falls back to webp. gif is not selected automatically.
Reserved; the current pipeline does not use this key to gate AVIF output.
Reserved; the current pipeline does not use this key to gate WebP output.
Reserved; the current pipeline does not use this key to gate JPEG XL output.
Metadata blocks copied into the output. none strips everything. Request override: meta.
Default quality. A named level shifts the per-format quality curve; a number is used directly. Request override: q.
Reserved; the current raster encoder pipeline does not read this key.
Reserved; the current raster encoder pipeline does not read this key.
Maximum output width. Wider results are scaled down without changing their aspect ratio. Request override: limit=dimension.
Ceiling on output height.
Maximum output file size. picturium re-encodes the image at a lower quality until it fits. Request override: limit=size.
How far under max_size counts as close enough — a result in that band is accepted without another recompress.
Maximum recompress passes when chasing max_size.
Quality floor for the recompress search.
Hard cap on frames in one animated response. Each frame is a full pass through the geometry stages.
[output.quality_curves]
Each format has a quality curve based on image size. Images at or below max_area use
max quality; images at or above min_area use min quality. Sizes between them are
interpolated. The requested q level then shifts that value; medium and auto do not
apply an offset. All formats, including JXL, use the shared 1–100 scale here. low,
high, and maximum are offsets from −100 to 100.
At or above this area, quality bottoms out at each curve's min.
At or below this area, quality tops out at each curve's max. Must be above 0 and below min_area.
Per-format curves — output.quality_curves.<format>.<key>:
[output.encoder]
Encoder settings live under output.encoder.<format> for jpeg, webp, png, avif,
jxl, and gif. Each codec has its own effort scale; higher values usually encode more
slowly and produce smaller files.
Optimise Huffman tables — slower, slightly smaller. JPEG has no effort setting.
Encode effort. Higher is slower and smaller.
At or below this area the WebP encoder uses preset_small instead of preset_large.
libwebp preset for images at or below text_preset_area.
libwebp preset for larger images.
Alpha is never encoded below this quality.
Still images only. Smarter chroma subsampling; skipped on animation where it is slower and larger.
Animation only. Try every frame encoding and keep the smallest file. Much slower.
Animation only. Smallest gap between keyframes. 0 lets libwebp place none.
Animation only. Largest gap between keyframes. Closer keyframes seek better but cost encode time and size.
Encode effort.
Quality at or above which PNG switches to the lossless (non-palette) branch.
Deflate level for the palette branch.
Deflate level for the lossless branch.
Quantisation dithering for the palette branch.
Quantisation dithering for the lossless branch.
Encode effort.
Bits per channel.
Codec carried in the AVIF container.
Which encoder implementation to use.
Chroma subsampling.
Encode effort.
Decode-speed tier. Higher decodes faster and compresses worse.
Force lossless JXL.
Converts the shared 1–100 quality to a JXL distance: distance = distance_per_quality × (100 − q).
Encode effort.
Palette at quality 100 is 2^bitdepth colours.
Palette bit depth at quality 1, interpolated up to bitdepth across the quality range.
Quantisation dithering at quality 100.
Quantisation dithering at quality 1.
Animation only. At quality 1 (0 at quality 100), pixels that changed less than this are reused from the previous frame.
Animation only. At quality 1 (0 at quality 100), above this a frame reuses the previous frame’s palette.