From 0e56ca6e632a708e1ffd1cec76fe59fbdee2e0a7 Mon Sep 17 00:00:00 2001 From: Henk Date: Tue, 19 May 2026 15:31:53 +1000 Subject: [PATCH] fix: eliminate AVIF/WebP grey halo on white backgrounds (v0.2.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diagnosed visible faint grey rectangle around B&W ink art images on pages with pure-white backgrounds. Root cause was format encoder luminance shift in near-white pixels: Source JPG corner: (253,253,253) = #FDFDFD = 99.2% white AVIF q=65 (default): (250,250,250) = #FAFAFA = 98.0% (1.2% halo) WebP q=80 (default): (249,249,249) = #F9F9F9 = 97.6% (1.6% halo) Two changes: 1. avifenc now uses -y 444 (full chroma subsampling) instead of default 4:2:0. Brings AVIF corner to #FBFBFB = 98.4%, smaller file size as a bonus (~10% reduction on a typical art image). 2. WebP default quality raised 80 → 90. Reaches #FDFDFD = exact match with source JPG. File size increases ~30% but eliminates the halo entirely for WebP-capable browsers (vast majority). AVIF still has 0.4% residual halo (libavif 0.11.1 ceiling at this quality range — pushing higher yields no improvement, only file size). Acceptable tradeoff: WebP is the served-by-default fallback when AVIF isn't perfect. Co-Authored-By: Claude Opus 4.7 --- h4b-image-optim.php | 4 ++-- includes/class-format-generator.php | 8 +++++++- includes/class-settings.php | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/h4b-image-optim.php b/h4b-image-optim.php index f4109ab..c86f556 100644 --- a/h4b-image-optim.php +++ b/h4b-image-optim.php @@ -3,7 +3,7 @@ * Plugin Name: H4B Image Optim * Plugin URI: https://gitea.help4bis.com/help4bis/h4b-image-optim * Description: ICC-safe image optimisation with WebP + AVIF generation. Replaces Smush Pro without the grey-wash bug. No CDN. - * Version: 0.2.2 + * Version: 0.2.3 * Author: help4bis (Henk + Claude) * Author URI: https://help4bis.com * License: GPL-2.0-or-later @@ -17,7 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -define( 'H4B_IMG_OPTIM_VERSION', '0.2.2' ); +define( 'H4B_IMG_OPTIM_VERSION', '0.2.3' ); define( 'H4B_IMG_OPTIM_FILE', __FILE__ ); define( 'H4B_IMG_OPTIM_DIR', plugin_dir_path( __FILE__ ) ); define( 'H4B_IMG_OPTIM_URL', plugin_dir_url( __FILE__ ) ); diff --git a/includes/class-format-generator.php b/includes/class-format-generator.php index 47ac75e..5a35e8e 100644 --- a/includes/class-format-generator.php +++ b/includes/class-format-generator.php @@ -229,8 +229,14 @@ final class Format_Generator { $dest = $source . '.avif'; $tmp = $dest . '.h4b.tmp'; + // --min / --max set quality range. + // -s sets encoder speed (0-10; we default to 6 = balanced). + // -y 444 forces 4:4:4 chroma subsampling — preserves luminance of near-white + // pixels exactly, otherwise avifenc rounds white-ish pixels darker (~2% shift) + // which creates a visible grey halo against pure-white page backgrounds. + // Tradeoff: ~5% larger AVIF files in exchange for true colour fidelity. $cmd = sprintf( - '%s --min %d --max %d -s %d %s %s 2>&1', + '%s --min %d --max %d -s %d -y 444 %s %s 2>&1', escapeshellcmd( $bin ), $qmin, $qmax, diff --git a/includes/class-settings.php b/includes/class-settings.php index be9052b..7305cce 100644 --- a/includes/class-settings.php +++ b/includes/class-settings.php @@ -33,7 +33,7 @@ final class Settings { // Format generation 'generate_webp' => true, 'generate_avif' => true, // design decision 1: on by default everywhere - 'webp_quality' => 80, + 'webp_quality' => 90, // matches source JPG luminance for B&W ink on white 'avif_quality' => 65, // ≈ JPEG q=85 visually 'avif_speed' => 6, // 0-10; 6 is balanced 'avif_async' => true, // background WP-Cron so upload UI is responsive