Persimmon is an image server that implements the IIIF Image API 3.0. It serves private JPEG 2000 (JP2) images stored in S3, decoding them with the pure-Rust j2k crate. It can also serve JPEG XL source images.
- IIIF Image API 3.0 regions, sizes, rotations, and qualities
- Output as JPEG, PNG, AVIF, lossless WebP, or lossless JPEG XL
- Reads JP2 or JPEG XL source images from any S3-compatible store
- Caches source files on local disk and rendered images in S3, shared across instances
- Authenticated purge endpoint to clear the caches for an image
- Native TLS, a health check, and Prometheus metrics
| Route | Description |
|---|---|
GET /v3/{identifier}/info.json |
Image information |
GET /v3/{identifier}/{region}/{size}/{rotation}/{quality}.{format} |
An image (jpg, png, webp, avif, or jxl) |
GET /v3/{identifier} |
Redirects to info.json |
POST /admin/purge |
Clears cached images for {"identifier":"a/b"} (Basic auth) |
GET /healthz |
Health check |
GET /metrics |
Prometheus metrics |
The identifier is the S3 key of the source image. Encode any slash in it as %2F, so key a/b.jp2 is requested as /v3/a%2Fb.jp2/info.json.
Persimmon needs Rust 1.99 or newer. Run the tests and build the binary:
cargo test
cargo build --releaseBuild the Docker image for your machine, or add --platform linux/amd64 for an amd64 deployment:
docker buildx build --load -t persimmon:dev .Persimmon is configured with environment variables. See Configuring.md.
- Developers.md: project status, local testing, and internals
- PLAN.md: design goals and acceptance criteria
- JPEGXL_NOTES.md: how JPEG XL sources are handled and their performance trade-offs
- J2K_NOTES.md: the JP2 decoder and how it compared to Kakadu, which Persimmon used before