Image Fidelity
Produce high fidelity images without compromising on performance
Majid Ali Khan
I am a software engineer working with 1x Internet from last 9 years and with Drupal roughy 14 years.
Images Dominate the Web
Source: HTTP Archive 2024, desktop median
Typical page weight breakdown
How Normally Drupal Processes Images
★ Covered in this talk
PHP GD
Ships with Drupal core
★ Covered in this talk
ImageMagick
Contrib module + server binary
CDN
e.g. Cloudinary, imgix, Fastly
GD is Drupal's default — it runs on every site that hasn't deliberately switched. ImageMagick requires installing a contrib module and a server binary, but gives you real control over image quality.
PHP GD — Drupal's default image toolkit
1
Drupal's out-of-the-box image toolkit — works with zero configuration
Drupal core selects GD automatically unless you explicitly switch. Every image style resize, crop, and scale operation runs through GD without any server setup, making it universally available.
2
Processes images in memory using pixel-level operations — Slow and eats a lot of RAM
GD reads the source image into a PHP resource, applies transformations (resize, crop, rotate, convert) pixel by pixel, then writes the output file. It supports JPEG, PNG, GIF, and WebP as input and output formats.
Simple but limited — quality and format control are constrained
GD offers no per-format quality tuning beyond a single integer, no AVIF support, no metadata handling, and uses a fixed resampling algorithm. It is reliable for basic use but leaves advanced image optimisation out of reach.
3
"Quality 80" is not "Quality 80"
JPEG, WebP and AVIF use completely different internal scales — the same number means a completely different thing
| JPEG | WebP | AVIF |
Algorithm | DCT — rigid 8×8 px blocks | VP8 predictive coding�(single video frame) | AV1 dynamic blocks�(4 px – 128 px) |
Internal scale | 0–100 (IJG 1992) | 0–100 (Google-mapped) | 0–100 → QP 0–63 (translated) |
★ Recommended | Q 85 | Q 80 | Q 60–65 |
Failure artifact | Blocky & crunchy�(8×8 grids visible) | Soft & blurry�(watercolour smearing) | Smooth & waxy�(over-smoothed gradients) |
Size vs JPEG | Baseline | ~25% smaller | ~50% smaller |
⚠ Never use a single global quality for all formats. Q 85 on AVIF produces bloated files — it is equivalent to JPEG Q 95. Use Q85 / Q80 / Q60 for JPEG / WebP / AVIF respectively.
The Core Patch — a proposed fix for GD2
✦ New in patch
Proposed a core patch per-format quality controls for the GD2 core toolkit
Seems like the problem is solved … unfortunately, no
1
GD strips colour profile
GD simply dose not care and strips out all the color profile in image.
2
Fixed resampling — always bicubic
No filter choice. For sharp downscales the Mitchell or Lanczos filter is measurably better, but GD hardcodes bicubic with no override.
3
Memory explosion on large images
A 10 MB JPEG becomes 200 MB+ in RAM as raw RGBA pixels. Large image styles regularly crash PHP processes on memory-limited hosts.
4
No metadata
EXIF orientation, ICC colour profiles, copyright data — GD handles none selectively. You get everything or nothing.
✕
Two big problems with it — Soft & Dull images
Enter ImageMagick — the professional's toolkit
✓
200+ format support
AVIF, WebP, HEIF, TIFF, RAW, HDR — every modern format GD cannot touch.
✓
Per-format quality & encoding
Separate quality targets per codec. JPEG Q 85, WebP Q 80, AVIF Q 60 — each optimal.
✓
Resampling filter selection
Mitchell, Lanczos, Sinc — choose the right filter for each resize operation.
✓
Metadata & colour-profile control
Strip, preserve, or selectively copy EXIF/ICC data. Correct colour rendering across devices.
✓
Drupal contrib module
drupal.org/project/imagemagick wraps the CLI with a clean admin UI. Drop-in replacement for GD.
But the current ImageMagick UI has gaps
✕
Single global quality — same problem as GD
One field for all formats. JPEG and AVIF at the same integer produces either bloated AVIF or degraded JPEG.
✕
AVIF: no encoder controls in the UI
ImageMagick supports AVIF via libheif, but there was no UI to set encoding speed, bit depth, or chroma subsampling.
✕
WebP: no lossless, method, or sharp-YUV options
Only a quality number. No lossless toggle, no encoding method selector, no sharp-YUV for better chroma reproduction.
✕
No resampling filter selector
The current default varies by operation. No way for site builders to choose a sharper or faster filter.
✕
Arguments field fails silently
Typos, wrong flags, unsupported options — the free-text arguments box gives no feedback. You never know what actually ran.
Patch: Advanced image settings
Resampling filter
Controls the algorithm used when resizing. Mitchell is the best general-purpose choice. Lanczos is sharper for downscales. Defaults to ImageMagick's built-in per-operation choice.
Rendering intent
Controls how out-of-gamut colours are mapped during ICC colour-profile conversion. Perceptual is recommended for photographs; Relative colorimetric for logos.
Strip metadata
Removes EXIF, IPTC, and XMP metadata from output files. Reduces file size and prevents leaking GPS coordinates or camera info in public images.
Patch: JPEG quality & chroma
JPEG quality
Separate quality field for JPEG output (0–100). Values 80–85 are typical for high-quality web images. Overrides the fallback quality.
Fallback quality
A global fallback for formats not covered by per-format tabs (PNG, GIF, etc.). JPEG, WebP, and AVIF tabs override this.
Chroma subsampling
Eyes resolve brightness sharply but colour poorly — storing colour at half resolution saves ~30 % with no visible loss.
drupal.org/project/imagemagick/issues/3585578
Patch: WebP encoding settings
WebP quality (0–100)
Independent quality for WebP output. Q 80 is the recommended sweet spot — ~25% smaller than JPEG Q 85 at equivalent visual quality.
Encoding method (0–6)
Trade encoding time for file size. Method 4 (default) is a good balance; method 6 squeezes out extra bytes at the cost of slower saves.
Use sharp YUV
Improves chroma accuracy on high-contrast edges. Recommended ON for photos; has a small encoding cost.
Auto filter
Lets the WebP encoder automatically choose optimal filtering per block. Slightly slower but can improve quality at same file size.
Image hint
Hints the encoder about image type (photo, picture, graph). Allows format-specific optimisation paths.
Patch: AVIF encoding settings
AVIF quality (0–100)
AVIF Q 60 is roughly equivalent to JPEG Q 85 — ~50% smaller file. The scale is inverted internally (higher = lower QP), so Q 85 would bloat the file.
Encoding speed (0–10)
Lower = better compression but slower. Speed 5 (libheif default) is a balanced starting point. Speed 0 is best quality for offline processing.
Bit depth
8-bit for standard web photos; 10/12-bit for HDR/wide-gamut sources. 10-bit is the only option ImageMagick never chooses automatically — the only way to produce a true 10-bit AVIF. Smart guard: for 10/12-bit configs the patch reads source depth via identify; if the source does not carry sufficient depth the flag is skipped entirely, letting ImageMagick encode at the native source depth. 8-bit is always applied unconditionally — the only way to force downscale from a high-depth source.
Chroma subsampling
4:2:0 (default) is recommended for most photos — smallest files. 4:4:4 for graphics with text or sharp colour transitions.
Uses heic: coder prefix — heif: is silently ignored by ImageMagick 7
Patch: Resampling filter
34 filters — server-probed
The patch queries ImageMagick at runtime and populates the dropdown from what is actually installed on the server.
Old UI: argument field
Without the patch, users had to type the filter name into a raw text field — no hint of what was available.
MagicKernelSharp2021 (default)
Modern sharpening kernel; best general-purpose choice. Great detail retention without ringing artefacts.
LanczosSharp
Lanczos with a subtle sharpening bias — the go-to recommendation for photo-heavy sites.
Lanczos
Classic gold-standard downscaling filter; widely trusted and preserves fine detail.
drupal.org/project/imagemagick/issues/3585578
https://qrco.de/bgl3Gz
PHP GD
Image Magic
Key Take-Aways
Use the latest image format where possible
JPEG for universal compatibility — WebP for modern browsers with ~25 % savings — AVIF where you need the best compression and can accept encoding time.
Start with quality source material
Re-encoding cannot recover lost detail. A blurry, over-compressed, or low-resolution source stays that way regardless of settings.
Use proven per-format quality settings
JPEG Q85 · WebP Q80 + SharpYUV · AVIF Q60 speed 5 · Chroma 4:2:0 for all three.
Choose a sharp resampling filter
MagicKernelSharp2021 (default) or LanczosSharp. Avoid the ImageMagick built-in default — it is intentionally soft and typically needs an unsharp mask step.
Strip metadata, keep the ICC profile
Saves bytes on every image without colour shift on wide-gamut displays. Stripping the ICC profile makes colours look wrong on P3/Adobe RGB monitors.
Thank you!
Feel free to reach out:
m.ali@1xinternet.de�majid-a@live.com
www.drupal.org/u/majidali
LinkedIn Profile
Thank you for joining us!