Image Quality Options
1. How comparable are these Quality option values to each other?
They are not numerically comparable. They share a 0–100 scale and a monotone direction (higher = better), but each number is interpreted by a completely different internal parameter with a different curve.
quality 80 in JPEG and quality 80 in JXL are two different things that merely happen to share an integer.What is comparable is the perceptual tier («near-lossless», “good for web”, “aggressive”), and you can build a per-format mapping for those tiers.
2. What each 0–100 actually maps to
| Format | ImageMagick maps the value onto | Underlying parameter | Direction | “Best” endpoint |
|---|---|---|---|---|
| JPEG | libjpeg quality | quantization table scale | higher = finer tables | 100 — still lossy (DCT rounding, chroma subsampling) |
| WebP | libwebp quality | VBR quality target | higher = better | 100 — near-lossless, still lossy |
| AVIF | AV1 quantizer (0–63, inverted) | qp / quantizer |
higher quality → lower quantizer | quantizer 0 — mathematically lossless |
| JXL | libjxl distance | distance |
higher quality → lower distance | distance 0 — mathematically lossless |
Two consequences worth internalising:
- JXL and AVIF are the only two here with a true lossless mode reachable via the quality setting. JPEG and WebP top out at “visually lossless”.
- JXL and AVIF are inverted internally — a higher ImageMagick quality means a smaller underlying distance/quantizer. So the relationship between the number and the output is not even monotonic in the same shape across codecs.
3. Approximate perceptual equivalence
Roughly equivalent visual tiers for photographic content:
| Tier | JPEG | WebP | AVIF | JXL |
|---|---|---|---|---|
| Near-lossless | 90–95 | 90–95 | 70–80 | 90–100 (distance 0–1) |
| Good / typical web | 75–85 | 75–85 | 50–60 | 75–85 |
| Aggressive / small | 50–65 | 60–70 | 30–45 | 60–70 |
These are estimates, not guarantees. Treat them as starting points and validate on your own content — the exact ImageMagick↔codec mappings have shifted between releases, and content type matters enormously (a screenshot at JPEG 70 is usually fine; a night sky at JPEG 70 is not).
4. File size at comparable visual quality
For photographic content, the size ranking at equivalent perceived quality is roughly:
JXL ≈ AVIF < WebP < JPEG
JXL and AVIF typically land 30–50% smaller than WebP at the same visual quality. So if you were previously using one number across all formats, the practical consequence is that AVIF and JXL at a “moderate” setting are already better than JPEG at a “high” setting — and smaller.
5. Practical recommendation: presets, not shared numbers
Rather than pretending the numbers are interchangeable, expose tiers:
/**
* Per-format quality values that produce a comparable perceptual result.
* Numbers are NOT interchangeable between formats — these are tuned
* per codec so that "medium" looks the same everywhere.
*/
const QUALITY_PRESETS = [
'max' => ['jpeg' => 100, 'webp' => 100, 'avif' => 100, 'jxl' => 100],
'high' => ['jpeg' => 90, 'webp' => 88, 'avif' => 65, 'jxl' => 90],
'medium' => ['jpeg' => 80, 'webp' => 78, 'avif' => 50, 'jxl' => 78],
'low' => ['jpeg' => 65, 'webp' => 62, 'avif' => 35, 'jxl' => 62],
];
Usage:
$preset = \PHPThumb\Imagick::QUALITY_PRESETS['medium'];
$thumb = new \PHPThumb\Imagick('photo.jpg', [
'jpegQuality' => $preset['jpeg'],
'webpQuality' => $preset['webp'],
'avifQuality' => $preset['avif'],
'jxlQuality' => $preset['jxl'],
]);
This is exactly the argument for a separate
jxlQuality option rather than reusing jpegQuality: the numbers differ, so a shared knob would systematically mis-set three of the four formats.6. Measuring it yourself
Don't trust the table above — measure on your build and your content. Use a lossless PNG as the reference, not the source JPEG, otherwise you measure the source JPEG's own artifacts as if they were the new codec's.
#!/usr/bin/env bash
SRC=reference.png
for fmt in jpg webp avif jxl; do
echo "=== $fmt ==="
for q in 40 50 60 70 80 90 100; do
magick "$SRC" -quality "$q" "/tmp/t.$fmt" 2>/dev/null || continue
size=$(stat -c%s "/tmp/t.$fmt")
ssim=$(magick compare -metric SSIM "$SRC" "/tmp/t.$fmt" null: 2>&1 | awk '{print $1}')
printf " q=%-4s %9d bytes SSIM=%s\n" "$q" "$size" "$ssim"
done
done
Then pick, for each format, the lowest quality whose SSIM still clears your threshold (e.g.
0.98). Those are your real per-format constants.6.1. Don't forget the effort/speed defines
For the two modern codecs, encoder effort changes file size substantially at identical quality:
# AVIF — slower = smaller, same visual quality
magick photo.jpg -quality 50 -define heic:speed=0 out.avif
# JXL — higher effort = smaller
magick photo.jpg -quality 90 -define jxl:effort=9 out.jxl
So a tuned AVIF at
speed=0 can undercut an untuned one at speed=5 at the same quality number — another reason quality numbers alone aren't a reliable cross-format comparison.7. Caveats
- Chroma subsampling affects JPEG/WebP heavily at lower qualities and is invisible to the quality number itself.
- WebP alpha quality is a separate knob from the main image quality; the
qualityoption here does not control it. - Graphics/flat colour behave very differently from photos — AVIF/JXL handle flat areas poorly relative to their reputation, and PNG/WebP lossless may win outright.
- The exact ImageMagick mapping is version-dependent. Treat any table (including this one) as a starting point, and verify with the script above if file size or fidelity matters.
8. TL;DR
| Question | Answer |
|---|---|
| Are the numbers interchangeable? | No — different internal parameters, different curves, two of them inverted |
| Are the perceptual tiers comparable? | Yes, with a per-format mapping table |
| Which formats can be truly lossless via quality? | AVIF and JXL only |
| Typical size ranking at equal visual quality | JXL ≈ AVIF < WebP < JPEG |
Does this justify a separate jxlQuality? |
Yes — sharing jpegQuality would mis-set JXL (and the others) |