we need jpeg xl support as a first class citizen in pixa, with it being used as the default output type if no type is specified.
Definition of done
JPEG XL is a first-class format: accepted as an input (fetched, detected from its bytes, decoded) and produced as an output, everywhere the other formats are (format=jxl in plain and encrypted URLs, the content type image/jxl, quality settings, caching of variants).
When a request specifies no output format, the output is JPEG XL.
The image build has JPEG XL support compiled into libvips (libjxl), checked by a test that encodes and decodes a JPEG XL image, so a build without it fails make check.
Tests, each failing first: a JPEG XL source is served and resized; format=jxl returns image/jxl; a request with no format returns image/jxl.
README.md documents JPEG XL as a supported input and output, and the new default output format.
Lands on next as reviewed PRs.
Model: opus-5-5
From sneak, 2026-10-07, in chat, verbatim:
> we need jpeg xl support as a first class citizen in pixa, with it being used as the default output type if no type is specified.
## Definition of done
- JPEG XL is a first-class format: accepted as an input (fetched, detected from its bytes, decoded) and produced as an output, everywhere the other formats are (`format=jxl` in plain and encrypted URLs, the content type `image/jxl`, quality settings, caching of variants).
- When a request specifies no output format, the output is JPEG XL.
- The image build has JPEG XL support compiled into libvips (libjxl), checked by a test that encodes and decodes a JPEG XL image, so a build without it fails `make check`.
- Tests, each failing first: a JPEG XL source is served and resized; `format=jxl` returns `image/jxl`; a request with no format returns `image/jxl`.
- `README.md` documents JPEG XL as a supported input and output, and the new default output format.
- Lands on `next` as reviewed PRs.
Model: opus-5-5
clawbot
self-assigned this 2026-10-08 01:04:28 +02:00
Three PRs to next, in order, each reviewed before the next starts (each needs the one before it).
1. Build support (part of this issue)
script/bootstrap --cgo installs libvips' JPEG XL support (on Alpine the vips-jxl package; check the apt, brew and nix branches too), and the runtime stage of the Dockerfile installs it.
A test in internal/imageprocessor encodes an image to JPEG XL with govips and decodes it back, so a test phase without the support fails make check.
pixad refuses to start, saying what is missing, when libvips cannot load and save JPEG XL. It will be the default output, so an image without it would fail nearly every request; this way the runtime image's health check fails instead.
2. JPEG XL as an input and output format (part of this issue)
Input: internal/magic detects both JPEG XL signatures (the bare codestream FF 0A and the container 00 00 00 0C 4A 58 4C 20 0D 0A 87 0A); the upstream fetch accepts image/jxl; orig of a JPEG XL source is JPEG XL.
Output: the format jxl in plain and encrypted URLs and on the generator page, served as image/jxl, with q setting the encoder's quality and each variant cached like the other formats.
auto: JPEG XL first when Accept names image/jxl, then AVIF, WebP, JPEG as now. Like AVIF and WebP it must be named; a client that names nothing still gets JPEG.
Tests, each failing first: a JPEG XL source is served and resized; .jxl answers image/jxl; auto with Accept: image/jxl answers image/jxl.
README.md: JPEG XL as an input and output, and in the auto order.
3. JPEG XL as the default (closes this issue)
A plain URL may leave the format out: /v1/image/<host>/<path>/<size> (e.g. 800x600 or orig, no extension) answers JPEG XL, and is signed as jxl.
An encrypted URL whose token holds no format answers JPEG XL; the generator page selects JPEG XL by default, an empty format field means JPEG XL, and the generated URL's name ends in .jxl.
Tests, each failing first: a request with no format answers image/jxl, through both routes.
README.md: the new default.
Decisions taken from the issue's words, recorded here: "no format specified" means a URL or token that names none, as above; auto is a format named in the URL and keeps JPEG as its last resort, since a client that does not name image/jxl may not be able to show it.
Model: opus-5-5
## Plan
Three PRs to `next`, in order, each reviewed before the next starts (each needs the one before it).
**1. Build support** (part of this issue)
- `script/bootstrap --cgo` installs libvips' JPEG XL support (on Alpine the `vips-jxl` package; check the apt, brew and nix branches too), and the runtime stage of the `Dockerfile` installs it.
- A test in `internal/imageprocessor` encodes an image to JPEG XL with govips and decodes it back, so a test phase without the support fails `make check`.
- `pixad` refuses to start, saying what is missing, when libvips cannot load and save JPEG XL. It will be the default output, so an image without it would fail nearly every request; this way the runtime image's health check fails instead.
**2. JPEG XL as an input and output format** (part of this issue)
- Input: `internal/magic` detects both JPEG XL signatures (the bare codestream `FF 0A` and the container `00 00 00 0C 4A 58 4C 20 0D 0A 87 0A`); the upstream fetch accepts `image/jxl`; `orig` of a JPEG XL source is JPEG XL.
- Output: the format `jxl` in plain and encrypted URLs and on the generator page, served as `image/jxl`, with `q` setting the encoder's quality and each variant cached like the other formats.
- `auto`: JPEG XL first when `Accept` names `image/jxl`, then AVIF, WebP, JPEG as now. Like AVIF and WebP it must be named; a client that names nothing still gets JPEG.
- Tests, each failing first: a JPEG XL source is served and resized; `.jxl` answers `image/jxl`; `auto` with `Accept: image/jxl` answers `image/jxl`.
- `README.md`: JPEG XL as an input and output, and in the `auto` order.
**3. JPEG XL as the default** (closes this issue)
- A plain URL may leave the format out: `/v1/image/<host>/<path>/<size>` (e.g. `800x600` or `orig`, no extension) answers JPEG XL, and is signed as `jxl`.
- An encrypted URL whose token holds no format answers JPEG XL; the generator page selects JPEG XL by default, an empty format field means JPEG XL, and the generated URL's name ends in `.jxl`.
- Tests, each failing first: a request with no format answers `image/jxl`, through both routes.
- `README.md`: the new default.
Decisions taken from the issue's words, recorded here: "no format specified" means a URL or token that names none, as above; `auto` is a format named in the URL and keeps JPEG as its last resort, since a client that does not name `image/jxl` may not be able to show it.
Model: opus-5-5
Part 1 is #226: script/bootstrap --cgo and the runtime image install libvips' JPEG XL support (vips-jxl on Alpine), and pixad does not start without it. Apt's libvips on Ubuntu 22.04 (8.12) has no JPEG XL support, so pixad will not start there.
Model: opus-5-5
Part 1 is https://git.eeqj.de/sneak/pixa/pulls/226: `script/bootstrap --cgo` and the runtime image install libvips' JPEG XL support (`vips-jxl` on Alpine), and `pixad` does not start without it. Apt's libvips on Ubuntu 22.04 (8.12) has no JPEG XL support, so `pixad` will not start there.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
From sneak, 2026-10-07, in chat, verbatim:
Definition of done
format=jxlin plain and encrypted URLs, the content typeimage/jxl, quality settings, caching of variants).make check.format=jxlreturnsimage/jxl; a request with no format returnsimage/jxl.README.mddocuments JPEG XL as a supported input and output, and the new default output format.nextas reviewed PRs.Model: opus-5-5
Plan
Three PRs to
next, in order, each reviewed before the next starts (each needs the one before it).1. Build support (part of this issue)
script/bootstrap --cgoinstalls libvips' JPEG XL support (on Alpine thevips-jxlpackage; check the apt, brew and nix branches too), and the runtime stage of theDockerfileinstalls it.internal/imageprocessorencodes an image to JPEG XL with govips and decodes it back, so a test phase without the support failsmake check.pixadrefuses to start, saying what is missing, when libvips cannot load and save JPEG XL. It will be the default output, so an image without it would fail nearly every request; this way the runtime image's health check fails instead.2. JPEG XL as an input and output format (part of this issue)
internal/magicdetects both JPEG XL signatures (the bare codestreamFF 0Aand the container00 00 00 0C 4A 58 4C 20 0D 0A 87 0A); the upstream fetch acceptsimage/jxl;origof a JPEG XL source is JPEG XL.jxlin plain and encrypted URLs and on the generator page, served asimage/jxl, withqsetting the encoder's quality and each variant cached like the other formats.auto: JPEG XL first whenAcceptnamesimage/jxl, then AVIF, WebP, JPEG as now. Like AVIF and WebP it must be named; a client that names nothing still gets JPEG..jxlanswersimage/jxl;autowithAccept: image/jxlanswersimage/jxl.README.md: JPEG XL as an input and output, and in theautoorder.3. JPEG XL as the default (closes this issue)
/v1/image/<host>/<path>/<size>(e.g.800x600ororig, no extension) answers JPEG XL, and is signed asjxl..jxl.image/jxl, through both routes.README.md: the new default.Decisions taken from the issue's words, recorded here: "no format specified" means a URL or token that names none, as above;
autois a format named in the URL and keeps JPEG as its last resort, since a client that does not nameimage/jxlmay not be able to show it.Model: opus-5-5
Part 1 is #226:
script/bootstrap --cgoand the runtime image install libvips' JPEG XL support (vips-jxlon Alpine), andpixaddoes not start without it. Apt's libvips on Ubuntu 22.04 (8.12) has no JPEG XL support, sopixadwill not start there.Model: opus-5-5