{"uuid": "b7df32de-b9ea-4e24-b64f-d83cc38a51d0", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "GHSA-h27h-jf9v-m8rg", "type": "seen", "source": "https://gist.github.com/zero-two-rafaeltab/0f4f611a90dc63ebecb331c36fd13029", "content": "# Native HDR codec alternatives for Media\n\nResearch date: 2026-09-28. This answers [Evaluate native HDR codec backends beyond Sharp](https://github.com/rafaeltab/wallpaperdb/issues/276). It is evidence for the live [HDR representation and rendering decision](https://github.com/rafaeltab/wallpaperdb/issues/263), not an encoder selection or implementation. No repository files or dependencies changed.\n\n## Finding\n\nNo single maintained alternative is currently proven to satisfy the entire requested matrix in Media's Node 22 Alpine deployment. A split native path is plausible: **libavif for single-layer PQ/HLG AVIF, including sequences with alpha**, and **libultrahdr, directly or through libvips, for JPEG gain maps**. The tested libavif sequence proves file structure, not color appearance. The current libultrahdr Apple JPEG re-encode bug prevents declaring authored Apple gain-map preservation solved. Native libraries perform decoding, resizing, encoding, and gain-map arithmetic; Media would still orchestrate operations and verify results. These facts do not establish browser or physical-display HDR rendering.\n\n[Previous pinned probe](https://gist.github.com/zero-two-rafaeltab/9f9d442e872fe782d6c83759f5823e4b#file-report-md): libavif 1.3.0/AOM emitted independently decodable 8/10/12-bit PQ, 10-bit HLG, and two-frame 10-bit PQ with fractional alpha and unequal durations. Sharp 0.35.5 on Alpine failed to retain both Apple old/new maps; its regenerated map changed the authored SDR base. Direct Sharp JPEG-to-AVIF outputs were labeled SDR. Those observations remain the empirical baseline.\n\n## Ranked candidates by job\n\n| Job and rank | Native path | Evidence | Unproved or blocked |\n| --- | --- | --- | --- |\n| AVIF, first | Direct [libavif 1.4.2](https://github.com/AOMediaCodec/libavif/tree/v1.4.2), with an AV1 codec such as AOM for encode and dav1d for independent decode | Its C API has explicit image-sequence timing, alpha, CICP/ICC, depth, gain-map, and size-limit controls. The earlier pinned 1.3.0 CLI probe emitted the needed PQ/HLG and animated-alpha structures. [API](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/include/avif/avif.h) | A production-like Alpine build; actual 8/10/12-bit source-detail retention, frame composition, orientation, linear-light color accuracy, privacy metadata policy, resource ceilings, and physical browser rendering. The C API requires a Media native binding or bounded helper process; neither integration has been built. |\n| HDR JPEG, first candidate after upstream fix | Direct [libultrahdr 2.0.2](https://github.com/google/libultrahdr/tree/v2.0.2) | Native decoder/encoder accepts HDR and SDR intents, or compressed SDR base, compressed gain map, and metadata. It exposes crop, rotate, resize and gain-map reconstruction operations. Apple old/new decode support [merged in June 2026](https://github.com/google/libultrahdr/pull/385). [API](https://github.com/google/libultrahdr/blob/v2.0.2/ultrahdr_api.h) | [Open re-encode fix](https://github.com/google/libultrahdr/pull/484): decoded Apple metadata has the wrong color-space flag for reassembling compressed base and map; re-encode fails with the same missing-ICC error seen in the Alpine Sharp probe. Effects cannot simply be applied to compressed JPEG components. Source-preserving geometry, orientation, dual metadata, SDR/HDR appearance, and deployed build still require a fixture suite. |\n| HDR JPEG, useful higher-level wrapper | Custom [libvips UltraHDR build](https://github.com/libvips/libvips/blob/master/doc/uhdr.md), optionally exposed through a common Sharp upgrade | `thumbnail` updates the base and gain map together. libvips describes its use of libultrahdr and warns that other geometry operations need explicit map handling. A glibc Sharp 0.35.5 probe retained both tested Apple maps, so a controlled glibc build may be worth repeating. | It is still a libultrahdr path, not an independent cure for the Apple bug; Alpine Sharp failed. [Apple recognition issue](https://github.com/libvips/libvips/issues/4952) remains open. Use [libvips 8.18.3 or later](https://github.com/libvips/libvips/security/advisories/GHSA-h27h-jf9v-m8rg) for gain-map resize. `thumbnail` does not prove center crop. Reconstruct-and-regenerate loses the original SDR grading unless separately supplied. |\n| AVIF alternative | Direct [libheif 1.23.5](https://github.com/strukturag/libheif/releases/tag/v1.23.5) | Supports HDR, alpha, and timed HEIF/AVIF sequences; its [sequence API](https://github.com/strukturag/libheif/wiki/Reading-and-Writing-Sequences) exposes timing/repetition. libvips' [HEIF saver](https://github.com/libvips/libvips/blob/master/libvips/foreign/heifsave.c) accepts 8/10/12-bit output and PQ/HLG labels. | No equivalent production-like AVIF fixture proof here. libvips' pages are not proof of timed AVIF sequence encoding. libheif's [gain-map `tmap` API](https://github.com/strukturag/libheif/pull/1503) is still an open PR; libultrahdr's HEIF/AVIF gain-map build uses a patched libheif. Plugin/codec packaging must be pinned. |\n\nImageMagick's UHDR coder and a newer Sharp/libvips package are wrappers around libultrahdr for this JPEG path. The [open Apple fix](https://github.com/google/libultrahdr/pull/484) explicitly cites ImageMagick resize failure; changing only the wrapper does not qualify Apple preservation.\n\n## JPEG gain-map details\n\n[libultrahdr's reference API](https://github.com/google/libultrahdr/blob/v2.0.2/README.md) distinguishes supplying only HDR pixels, supplying HDR plus authored SDR pixels, supplying compressed SDR bytes, and supplying compressed SDR plus gain-map bytes/metadata. This matters because the HDR-only mode tone maps its own SDR base. It does not retain the creator's chosen SDR look. The compressed-component mode can retain an authored base in principle, but [maintainers explain](https://github.com/google/libultrahdr/issues/395) that crop/resize effects do not operate on those compressed intents. A preservation path must decode and geometrically edit both components, recompress them, and reassemble with valid map metadata. Do this with native codec operations, not hand editing JPEG markers. Whether that round trip is visually faithful needs measurement.\n\nVersion 2.0.2 can enable both `UHDR_WRITE_ISO` and `UHDR_WRITE_XMP` at build time; its [CMake defaults](https://github.com/google/libultrahdr/blob/v2.0.2/CMakeLists.txt) enable ISO and disable XMP. Dual signaling is an output validation obligation, not an observed property of the tested files. The [JPEG decoder contract](https://github.com/google/libultrahdr/blob/v2.0.2/lib/include/ultrahdr/jpegr.h) assumes sRGB base transfer and requires recognized color information. P3 and Rec.2020 inputs must be tested, not inferred from format support.\n\nThe upstream [Apple bug report and proposed fix](https://github.com/google/libultrahdr/pull/484) include old/new fixtures and a base-plus-map round trip. The PR remained open on the research date. A merged fix and passing upstream test will justify a new deployment-like probe; they will not, by themselves, qualify resized appearance. For unsupported or unknown source facts, the accepted policy remains original-only with no transformations.\n\n## AVIF and cross-format details\n\nDirect libavif is the clearest maintained native sequence path. [Its API](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/include/avif/avif.h) exposes per-image depth, color primaries, transfer characteristics, alpha, sequence timescale/durations, and decoder/encoder limits. The [prior probe](https://gist.github.com/zero-two-rafaeltab/9f9d442e872fe782d6c83759f5823e4b#file-report-md) proves that standalone libavif 1.3.0 can emit the requested AVIF structures. It does not prove Media integration or the visual fidelity of animated P3/Rec.2020 PQ/HLG transformations. HDR is a transfer function and appearance property, not a bit-depth label: keep 8-bit HDR eligible if the whole path passes validation.\n\n[libavif 1.4.0 added Apple-style JPEG gain-map import](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/CHANGELOG.md). Version 1.4.2 [tests both old and new Apple corpus images](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/tests/gtest/avifjpeggainmaptest.cc) and [encodes them to AVIF gain-map files](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/tests/test_cmd_enc_gainmap_boxes_golden.sh). Its JPEG gain-map conversion is conditional on [libxml2 in the build](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/CMakeLists.txt). The older Ubuntu 1.3.0 CLI used in the previous probe lacked that build feature. This is a promising alternative to Sharp for **JPEG gain-map to AVIF gain-map import**, but it is not proof of a faithful resized JPEG, a single-layer HDR AVIF output, or browser display of AVIF gain maps. The [conversion code](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/apps/avifgainmaputil/convert_command.cc) can assume PQ when alternate transfer metadata is missing. That assumption must not silently become a verified source fact in Media.\n\nFor a single-layer HDR AVIF from a JPEG gain map, a pipeline would need to reconstruct linear HDR pixels using the map, perform orientation/geometry/color operations, then encode with explicit PQ or HLG/CICP output. libavif has [gain-map application and computation APIs](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/include/avif/avif.h), but no tested end-to-end production path is established. The reverse conversion needs both intended HDR pixels and a chosen SDR appearance before libultrahdr can generate a map. A high-bit-depth AVIF or JPEG with SDR tags does not count as faithful HDR conversion.\n\n## Deployment and verification boundary\n\nMedia currently runs on [Node 22 Alpine](https://github.com/rafaeltab/wallpaperdb/blob/main/apps/media/Dockerfile). Direct libraries need pinned native versions, codec/plugin availability, a binding or bounded helper, and memory/time/pixel/frame limits in that image. A switch to a glibc base is a packaging option, not evidence of fidelity. [libultrahdr's build guide](https://github.com/google/libultrahdr/blob/v2.0.2/docs/building.md) documents Linux builds and extra patched libheif requirements for HEIF/AVIF gain maps. libavif is BSD-2-Clause, libultrahdr offers MIT or Apache-2.0, libheif's library is LGPL-3.0, and libvips is LGPL-2.1. Check the actual linked AV1/JPEG codec dependencies before selecting a distribution. [libavif license](https://github.com/AOMediaCodec/libavif/blob/v1.4.2/LICENSE) \u00b7 [libultrahdr license](https://github.com/google/libultrahdr/blob/v2.0.2/README.md#license) \u00b7 [libheif license](https://github.com/strukturag/libheif/blob/v1.23.5/COPYING) \u00b7 [libvips license](https://github.com/libvips/libvips/blob/master/COPYING).\n\nA production-like fixture suite must record versions, hashes, build flags, and output facts, then independently decode outputs. At minimum:\n\n- Android Ultra HDR/ISO and old/new Apple JPEGs; orientations 1-8; noninteger resize and center crop; map/base alignment; single- and three-channel maps; unequal map sizes; both ISO and Android XMP output markers. Compare decoded authored SDR bases and reconstructed HDR pixels before/after in a declared color space with numerical and viewed tolerances. Exercise the upstream Apple fix, once available, in the actual deployment image.\n- Still and animated AVIF with PQ and HLG, P3 and Rec.2020, 8/10/12-bit coded sources, partial alpha, unequal frame durations, and first fully composed frame. Verify encoded depth, primaries, transfer, alpha, dimensions, durations, and output facts with an independent decoder. Include frame count, decoded-pixel and time limits.\n- Explicit SDR from an authored companion or embedded base, and controlled tone mapping where neither exists. Measure reference white, highlight retention, clipping, gamut mapping, and consistency across motion frames. Strip private metadata from derivatives while retaining required orientation/color/gain-map signaling; exact-byte no-ops still return the original. Metadata reads must use stored facts and fetch no bytes.\n\nThose tests establish processing. Browser support requires separate file/rendering checks, and HDR luminance on the MacBook, iPad, Windows HDR monitor, and Galaxy phone remains a manual user check. Container validity, native processing, browser decode, browser HDR presentation, downloaded-file interpretation, and OS wallpaper rendering are separate claims.\n\n## Research method and limits\n\nThis review read pinned primary library source, release notes, native API and build documentation, upstream issue/PR test cases, and the earlier reproducible codec probe. It did not build libavif 1.4.2 or libultrahdr 2.0.2 in Media's image, run a new native fixture suite, select a product support matrix, or inspect a physical HDR display. Temporary source checkout: `/tmp/wallpaperdb-hdr-alternatives-libavif` at commit `c5240fc79fe5c2407e10afd35f5505ef6333ea49`. The prior probe's temporary outputs remain under `/tmp/wallpaperdb-hdr-proof`.\n", "creation_timestamp": "2026-09-28T11:35:12.000000Z"}