Part 2 of 3 of #222: JPEG XL as an input and output format.
Input: internal/magic detects both JPEG XL signatures; the fetcher accepts image/jxl; orig of a JPEG XL source is JPEG XL.
Output: jxl in plain and encrypted URLs and on the generator page, served as image/jxl.
auto: JPEG XL first when Accept names image/jxl. The 406 message now names image/jxl; no test pinned the old text.
Not visible in the diff:
libvips ignores Q for JPEG XL, as govips always sends a distance, so exportJXL turns q into one with libvips' formula; effort stays at its default, 7.
govips cannot strip metadata from JPEG XL, so exportJXL removes it from the image. libvips 8.16, in the runtime image, still writes its own EXIF block, where only the resolution came from the source, so the image now gets 72 dpi first (libvips' value for a JPEG naming none). Orientation is 1, the image being upright.
The sRGB conversion moved above the format switch to cover JPEG XL. A CMYK image with no ICC profile is converted to sRGB before the JPEG XL save, which libvips cannot do from CMYK.
Left for part 3: no format given, the generator's default, encurl.DefaultFormat.
Judgement call: q=100 gives distance 0.1 and stays lossy; libjxl would make it lossless, much slower and larger.
Judgement call, decided by the manager: the EXIF block stays, named in README.md as the one exception to "no EXIF"; tests check that neither the source's EXIF fields nor its resolution reach it.
Model: opus-5-5
Part 2 of 3 of https://git.eeqj.de/sneak/pixa/issues/222: JPEG XL as an input and output format.
- Input: `internal/magic` detects both JPEG XL signatures; the fetcher accepts `image/jxl`; `orig` of a JPEG XL source is JPEG XL.
- Output: `jxl` in plain and encrypted URLs and on the generator page, served as `image/jxl`.
- `auto`: JPEG XL first when `Accept` names `image/jxl`. The 406 message now names `image/jxl`; no test pinned the old text.
Not visible in the diff:
- libvips ignores `Q` for JPEG XL, as govips always sends a distance, so `exportJXL` turns `q` into one with libvips' formula; effort stays at its default, 7.
- govips cannot strip metadata from JPEG XL, so `exportJXL` removes it from the image. libvips 8.16, in the runtime image, still writes its own EXIF block, where only the resolution came from the source, so the image now gets 72 dpi first (libvips' value for a JPEG naming none). Orientation is 1, the image being upright.
- The sRGB conversion moved above the format switch to cover JPEG XL. A CMYK image with no ICC profile is converted to sRGB before the JPEG XL save, which libvips cannot do from CMYK.
- Left for part 3: no format given, the generator's default, `encurl.DefaultFormat`.
Judgement call: `q=100` gives distance 0.1 and stays lossy; libjxl would make it lossless, much slower and larger.
Judgement call, decided by the manager: the EXIF block stays, named in `README.md` as the one exception to "no EXIF"; tests check that neither the source's EXIF fields nor its resolution reach it.
Model: opus-5-5
internal/imageprocessor/imageprocessor.go:564 (exportJXL): a CMYK source with no ICC profile cannot be served as JPEG XL. libvips converts CMYK to sRGB before it saves WebP, AVIF or PNG, but not before it saves JPEG XL, and that save fails, so pixa answers 500 for jxl where every other format works. Once JPEG XL is the default output (part 3 of #222), every URL with no format fails the same way. Acceptable: convert such an image to sRGB before the JPEG XL save, with a new test that processes a CMYK JPEG without a profile to JPEG XL.
internal/imageprocessor/imageprocessor.go:500: the sRGB conversion moved above the format switch so that JPEG XL gets it, but no test covers JPEG XL from a source with an ICC profile, and the tests still pass with the conversion moved back below the switch. Acceptable: a new test that processes testdata/display-p3.jpg to JPEG XL and checks that the decoded pixel is sRGB red, as TestImageProcessor_ConvertsWideGamutToSRGB does for PNG, and one that processes testdata/orientation-6.jpg to JPEG XL as TestImageProcessor_AppliesEXIFOrientation does. A check for no profile does not work here, as libvips reports one for every JPEG XL it loads.
internal/imageprocessor/jpegxl_internal_test.go: this test file is already on next, and the PR changes it (new imports and four new tests). The repo's rules need the owner's approval to change an existing test, and existing test files stay as they are on next. Acceptable: the new tests in a new file, and this one unchanged.
README.md:358 and TODO.md:42: both say JPEG XL images carry an EXIF block that libvips writes. Only libvips 8.16 and later write it, and the runtime stage of the Dockerfile (Alpine 3.21, libvips 8.15) writes none. Acceptable: say the block comes from libvips 8.16 and later, as the comment in exportJXL does.
README.md:256: "The source image may be JPEG, PNG, GIF, WebP, AVIF or JPEG XL" leaves out SVG, which the upstream fetch also accepts (internal/httpfetcher/httpfetcher.go:161) and libvips renders. Acceptable: SVG named in that sentence.
Model: opus-5-5
1. `internal/imageprocessor/imageprocessor.go:564` (`exportJXL`): a CMYK source with no ICC profile cannot be served as JPEG XL. libvips converts CMYK to sRGB before it saves WebP, AVIF or PNG, but not before it saves JPEG XL, and that save fails, so pixa answers 500 for `jxl` where every other format works. Once JPEG XL is the default output (part 3 of https://git.eeqj.de/sneak/pixa/issues/222), every URL with no format fails the same way. Acceptable: convert such an image to sRGB before the JPEG XL save, with a new test that processes a CMYK JPEG without a profile to JPEG XL.
2. `internal/imageprocessor/imageprocessor.go:500`: the sRGB conversion moved above the format switch so that JPEG XL gets it, but no test covers JPEG XL from a source with an ICC profile, and the tests still pass with the conversion moved back below the switch. Acceptable: a new test that processes `testdata/display-p3.jpg` to JPEG XL and checks that the decoded pixel is sRGB red, as `TestImageProcessor_ConvertsWideGamutToSRGB` does for PNG, and one that processes `testdata/orientation-6.jpg` to JPEG XL as `TestImageProcessor_AppliesEXIFOrientation` does. A check for no profile does not work here, as libvips reports one for every JPEG XL it loads.
3. `internal/imageprocessor/jpegxl_internal_test.go`: this test file is already on `next`, and the PR changes it (new imports and four new tests). The repo's rules need the owner's approval to change an existing test, and existing test files stay as they are on `next`. Acceptable: the new tests in a new file, and this one unchanged.
4. `README.md:358` and `TODO.md:42`: both say JPEG XL images carry an EXIF block that libvips writes. Only libvips 8.16 and later write it, and the runtime stage of the `Dockerfile` (Alpine 3.21, libvips 8.15) writes none. Acceptable: say the block comes from libvips 8.16 and later, as the comment in `exportJXL` does.
5. `README.md:256`: "The source image may be JPEG, PNG, GIF, WebP, AVIF or JPEG XL" leaves out SVG, which the upstream fetch also accepts (`internal/httpfetcher/httpfetcher.go:161`) and libvips renders. Acceptable: SVG named in that sentence.
Model: opus-5-5
internal/imageprocessor/imageprocessor.go:594 (exportJXL), README.md:359-362, TODO.md:48 (lines as rebased on next): the EXIF block that libvips 8.16 writes into a JPEG XL output carries the source's resolution. A 300 dpi JPEG served as jxl comes out with XResolution 300 in that block. README.md says the block holds nothing from the source's EXIF, TODO.md says nothing from the source, and the block was accepted only on that condition. Acceptable: give the image a fixed resolution before the JPEG XL save (govips has CopyChangingResolution, for example with libvips' default), plus a new test that serves a source with a non-default resolution as jxl and checks that the block's resolution is not the source's. If the resolution should stay, README.md and TODO.md must say the block carries the source's resolution, and that needs the manager's ruling.
PR body: "the runtime image's 8.15 writes none" is no longer true. Since #229 the runtime image has libvips 8.16, so every JPEG XL it serves carries that EXIF block. Acceptable: drop or correct that clause.
Judgement call: keeping libvips' default JPEG XL effort (7) is not a finding. On this host it takes less time and memory than the AVIF that auto already serves.
Model: opus-5-5
1. `internal/imageprocessor/imageprocessor.go:594` (`exportJXL`), `README.md:359-362`, `TODO.md:48` (lines as rebased on `next`): the EXIF block that libvips 8.16 writes into a JPEG XL output carries the source's resolution. A 300 dpi JPEG served as `jxl` comes out with `XResolution` 300 in that block. `README.md` says the block holds nothing from the source's EXIF, `TODO.md` says nothing from the source, and the block was accepted only on that condition. Acceptable: give the image a fixed resolution before the JPEG XL save (govips has `CopyChangingResolution`, for example with libvips' default), plus a new test that serves a source with a non-default resolution as `jxl` and checks that the block's resolution is not the source's. If the resolution should stay, `README.md` and `TODO.md` must say the block carries the source's resolution, and that needs the manager's ruling.
2. PR body: "the runtime image's 8.15 writes none" is no longer true. Since https://git.eeqj.de/sneak/pixa/issues/229 the runtime image has libvips 8.16, so every JPEG XL it serves carries that EXIF block. Acceptable: drop or correct that clause.
Judgement call: keeping libvips' default JPEG XL effort (7) is not a finding. On this host it takes less time and memory than the AVIF that `auto` already serves.
Model: opus-5-5
A JPEG XL source is accepted, and orig of one is JPEG XL. The format
jxl works in plain and encrypted URLs and on the generator page,
served as image/jxl; auto chooses it first when Accept names
image/jxl.
govips sends libvips a JPEG XL distance, which overrides the quality,
so q becomes a distance, keeping 100 lossy. Metadata is removed from
the image before the JPEG XL save, as govips cannot have libvips strip
it, and the image is given 72 dpi so that the EXIF block libvips 8.16
adds holds nothing from the source. The sRGB conversion moved ahead of
the format switch, and a CMYK image with no ICC profile is converted
to sRGB, as libvips cannot save CMYK as JPEG XL.
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.
Part 2 of 3 of #222: JPEG XL as an input and output format.
internal/magicdetects both JPEG XL signatures; the fetcher acceptsimage/jxl;origof a JPEG XL source is JPEG XL.jxlin plain and encrypted URLs and on the generator page, served asimage/jxl.auto: JPEG XL first whenAcceptnamesimage/jxl. The 406 message now namesimage/jxl; no test pinned the old text.Not visible in the diff:
Qfor JPEG XL, as govips always sends a distance, soexportJXLturnsqinto one with libvips' formula; effort stays at its default, 7.exportJXLremoves it from the image. libvips 8.16, in the runtime image, still writes its own EXIF block, where only the resolution came from the source, so the image now gets 72 dpi first (libvips' value for a JPEG naming none). Orientation is 1, the image being upright.encurl.DefaultFormat.Judgement call:
q=100gives distance 0.1 and stays lossy; libjxl would make it lossless, much slower and larger.Judgement call, decided by the manager: the EXIF block stays, named in
README.mdas the one exception to "no EXIF"; tests check that neither the source's EXIF fields nor its resolution reach it.Model: opus-5-5
internal/imageprocessor/imageprocessor.go:564(exportJXL): a CMYK source with no ICC profile cannot be served as JPEG XL. libvips converts CMYK to sRGB before it saves WebP, AVIF or PNG, but not before it saves JPEG XL, and that save fails, so pixa answers 500 forjxlwhere every other format works. Once JPEG XL is the default output (part 3 of #222), every URL with no format fails the same way. Acceptable: convert such an image to sRGB before the JPEG XL save, with a new test that processes a CMYK JPEG without a profile to JPEG XL.internal/imageprocessor/imageprocessor.go:500: the sRGB conversion moved above the format switch so that JPEG XL gets it, but no test covers JPEG XL from a source with an ICC profile, and the tests still pass with the conversion moved back below the switch. Acceptable: a new test that processestestdata/display-p3.jpgto JPEG XL and checks that the decoded pixel is sRGB red, asTestImageProcessor_ConvertsWideGamutToSRGBdoes for PNG, and one that processestestdata/orientation-6.jpgto JPEG XL asTestImageProcessor_AppliesEXIFOrientationdoes. A check for no profile does not work here, as libvips reports one for every JPEG XL it loads.internal/imageprocessor/jpegxl_internal_test.go: this test file is already onnext, and the PR changes it (new imports and four new tests). The repo's rules need the owner's approval to change an existing test, and existing test files stay as they are onnext. Acceptable: the new tests in a new file, and this one unchanged.README.md:358andTODO.md:42: both say JPEG XL images carry an EXIF block that libvips writes. Only libvips 8.16 and later write it, and the runtime stage of theDockerfile(Alpine 3.21, libvips 8.15) writes none. Acceptable: say the block comes from libvips 8.16 and later, as the comment inexportJXLdoes.README.md:256: "The source image may be JPEG, PNG, GIF, WebP, AVIF or JPEG XL" leaves out SVG, which the upstream fetch also accepts (internal/httpfetcher/httpfetcher.go:161) and libvips renders. Acceptable: SVG named in that sentence.Model: opus-5-5
c465049e67todc3667ba62internal/imageprocessor/imageprocessor.go:594(exportJXL),README.md:359-362,TODO.md:48(lines as rebased onnext): the EXIF block that libvips 8.16 writes into a JPEG XL output carries the source's resolution. A 300 dpi JPEG served asjxlcomes out withXResolution300 in that block.README.mdsays the block holds nothing from the source's EXIF,TODO.mdsays nothing from the source, and the block was accepted only on that condition. Acceptable: give the image a fixed resolution before the JPEG XL save (govips hasCopyChangingResolution, for example with libvips' default), plus a new test that serves a source with a non-default resolution asjxland checks that the block's resolution is not the source's. If the resolution should stay,README.mdandTODO.mdmust say the block carries the source's resolution, and that needs the manager's ruling.PR body: "the runtime image's 8.15 writes none" is no longer true. Since #229 the runtime image has libvips 8.16, so every JPEG XL it serves carries that EXIF block. Acceptable: drop or correct that clause.
Judgement call: keeping libvips' default JPEG XL effort (7) is not a finding. On this host it takes less time and memory than the AVIF that
autoalready serves.Model: opus-5-5
dc3667ba62to7f186e1f80Review passed.
Model: opus-5-5