Media: Add HEIC canvas fallback for client-side processing#76731
Media: Add HEIC canvas fallback for client-side processing#76731adamsilverstein wants to merge 9 commits intotrunkfrom
Conversation
When users upload HEIC images, try server processing first. If the server lacks HEIC support, fall back to the browser's native createImageBitmap() + OffscreenCanvas to decode and convert to JPEG. The original HEIC is sideloaded as the original, the JPEG as the scaled version, and sub-sizes are generated from the JPEG via the existing vips resize pipeline. PHP: bypass MIME type check for HEIC/HEIF uploads so files can be stored even when the server can't process them. JS: add HEIC detection in prepareItem(), canvas conversion utility, and HEIC-aware generateThumbnails() fallback.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +3.18 kB (+0.04%) Total Size: 7.66 MB
ℹ️ View Unchanged
|
|
Flaky tests detected in 781b9f5. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/23373218279
|
Links core PR wordpress-develop#11323 to Gutenberg PR #76731.
Three issues prevented the HEIC canvas fallback from working: 1. generate_sub_sizes was set to true for HEIC uploads, causing the server to attempt (and silently fail) sub-size generation instead of letting the client handle it. 2. The server can't read HEIC files, so it always returned an empty missing_image_sizes array. The client now derives missing sizes from registered image sizes in settings. 3. createImageBitmap() doesn't support HEIC in Chrome. Added a fallback using <img> element + HTMLCanvasElement, which works on macOS because Chrome exposes OS-level HEIC decoding through the img rendering pipeline.
Chrome doesn't expose macOS's native HEIC decoder through image APIs (createImageBitmap, ImageDecoder, <img>). However, Chrome 107+ supports HEVC video decoding via the WebCodecs VideoDecoder API using macOS VideoToolbox. This adds a new decoding strategy that bridges the gap: 1. Parse the HEIC/ISOBMFF container in pure JS to extract the HEVC decoder configuration (hvcC) and compressed image data 2. Feed the HEVC frames through VideoDecoder (hardware-accelerated) 3. Composite decoded tiles onto a canvas and convert to JPEG Handles both single-image and grid/tiled HEIC files (the common iPhone format where photos are split into multiple HEVC tiles). No WASM decoder or patented codec is shipped — only the standard container format is parsed, and decoding uses Chrome's already-licensed platform decoder. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Register HEIC/HEIF as allowed upload MIME types so macOS file picker doesn't silently convert them to JPEG - Handle idat construction method in HEIC container parser for grid descriptor data stored inside the meta box - Relax grid tile count validation to allow extra iref entries (alpha planes, thumbnails) - Disable server-side sub-size generation and format conversion for HEIC uploads (client handles these) - Add debug logging throughout HEIC upload pipeline
The initial upload already saves the HEIC file on the server. The scaled sideload handler records it as original_image in metadata, so a separate original sideload is unnecessary and creates a duplicate file.
Don't update blocks with HEIC attachment URLs since browsers can't display them. The scaled JPEG sideload will provide a usable URL once client-side conversion completes. Also removes all HEIC debug logging added during development.
Tests cover: - Bit reversal for HEVC codec string construction - Single-image HEIC parsing with synthetic binary fixtures - Codec string generation (e.g. hvc1.1.6.L93.B0) - HEVCDecoderConfigurationRecord extraction - Error cases: empty buffer, missing meta/pitm/iloc boxes
Validate grid descriptor data length before accessing fields to avoid out-of-bounds reads on malformed files.
Summary
original, the JPEG becomes thescaledversion, and sub-sizes are generated from the JPEG via the existing vips resize pipelineNo HEIC decoder or patented codec is shipped — only standard container parsing is done client-side, and decoding uses the browser's already-licensed platform decoders.
Client-side decoding strategies
The canvas conversion tries three strategies in order:
createImageBitmap()+OffscreenCanvas— Works natively in Safari (all platforms). The simplest path.ImageDecoderAPI — Uses platform codecs exposed via the WebCodecs image pipeline. May work in future Chrome versions if HEIC is added.VideoDecoder— For Chrome 107+ on macOS. Parses the HEIC/ISOBMFF container in pure JS to extract the HEVC bitstream and decoder configuration (hvcC), then feeds the HEVC frames through Chrome's hardware-acceleratedVideoDecoder(backed by macOS VideoToolbox). Handles both single-image and grid/tiled HEIC files (the common iPhone format where photos are split into multiple HEVC tiles).Upload flow
Server has HEIC support: Upload → server processes everything → done.
Server lacks HEIC support, browser can decode: Upload → sideload original HEIC → canvas converts HEIC → JPEG (using strategies above) → sideload JPEG as scaled → generate sub-sizes from JPEG via vips → sideload each → finalize.
Neither supports HEIC: Upload → all client-side decode strategies fail → error shown to user.
Browser support matrix
createImageBitmapScreencast
screencast.2026-03-20.22-50-56.mp4
Test instructions