5 Commits

Author SHA1 Message Date
Henk
0e56ca6e63 fix: eliminate AVIF/WebP grey halo on white backgrounds (v0.2.3)
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 <noreply@anthropic.com>
v0.2.3
2026-05-19 15:31:53 +10:00
Henk
c54eccc2d5 fix: postmeta tracking on synchronous AVIF + add reconcile-meta (v0.2.2)
Two improvements after v0.2.1 deploy revealed the avif_status bug
wasn't fully fixed:

Fix:
  Format_Generator::make_avif() now calls record_avif_outcome() at the
  end of the synchronous path. Previously only the cron path recorded
  outcomes, so wp h4b-img generate-missing-siblings (synchronous) left
  4067 stale 'queued' rows even though it successfully generated 603
  AVIFs on disk. process_avif_job() simplified to a thin wrapper
  around make_avif(avif_async=false).

Added:
  wp h4b-img reconcile-meta — walks _h4b_img_optim postmeta, checks
  for .webp / .avif files on disk, and updates avif_status / webp size
  fields to match reality. One-shot reconciliation for stale records
  left by earlier plugin versions. --dry-run supported.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v0.2.2
2026-05-19 14:59:18 +10:00
Henk
868dbe0ff4 fix: avif tracking + new generate-missing-siblings command (v0.2.1)
Two related fixes to the AVIF pipeline:

Fix #1 — postmeta tracking
  Format_Generator::process_avif_job() now updates _h4b_img_optim's
  avif_status from 'queued' → 'done' (with byte size) or 'error' (with
  reason) after the cron job runs. Previously the postmeta said
  'queued' forever even when AVIF files existed on disk.

Fix #2 — root cause of missing AVIFs on rds.ink bulk run
  wp_schedule_single_event(time()+30, …) coalesces identical args at
  the same timestamp, so bulk-queueing hundreds of AVIF jobs in the
  same second silently dropped many. Added wp h4b-img generate-missing-siblings
  that walks attachment metadata, finds files missing .webp/.avif, and
  generates them SYNCHRONOUSLY (no queue, no coalescing). Only processes
  registered sizes by default; --include-orphans flag for disk-walk mode.

Verified on prod rds.ink: 1,134 of 1,737 registered images >=20KB have
AVIF, 603 are missing. Of 389 orphan files >=20KB missing AVIF, those
aren't referenced from any post/postmeta — correctly excluded.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v0.2.1
2026-05-19 14:52:50 +10:00
Henk
4cd1390a94 feat: migrate-from-smush + Picture-tag rewriter (v0.2.0)
Unblocks production use on sites previously running Smush.

migrate-from-smush:
  - Reads wp-smpro-smush-data postmeta, writes _h4b_img_optim marker
  - --dry-run / --force-rescan / --remove-smush-meta / --limit flags
  - Verified: 100 attachments migrated cleanly on dev.rds.ink,
    bulk count drops from 734 → 634

Picture_Tag rewriter:
  - Hooks the_content + post_thumbnail_html + widget_text + Elementor
    frontend + wp_get_attachment_image at priority 99
  - Wraps <img> in <picture><source avif><source webp><img></picture>
    when sibling files exist
  - Double-wrap protection via byte-range tracking of existing <picture> blocks
  - Per-image opt-out via data-no-h4b attribute
  - Cached sibling lookups per request
  - 8 edge-case tests pass

LOC: 2480 (was 1997). Adds class-cli-migrate.php (193 LOC) and
class-picture-tag.php (284 LOC).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v0.2.0
2026-05-19 13:50:41 +10:00
Henk
7e1c86f215 feat: initial v0.1.0 MVP
Replaces Smush Pro's optimisation pipeline without the grey-wash bug.

CLI commands working:
  wp h4b-img status
  wp h4b-img optimise --id=<n>
  wp h4b-img bulk
  wp h4b-img rescue

Verified on dev.rds.ink:
- ICC profile preservation works (the Smush-bug fix)
- Bulk: 20 attachments → 487 KB saved (10.4%), 0 errors
- Rescue: end-to-end mechanism verified on WorkingAsOne_horse fixture
- WebP synchronous, AVIF queued via WP-Cron
- Originals backed up to wp-content/h4b-img-originals/

See CHANGELOG.md for details + ../DESIGN-h4b-image-optim.md for architecture.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v0.1.0
2026-05-19 13:41:03 +10:00