Skip to content

v1.2.0: public reverse JPEG recompression + YCoCg-R lossless RCT#83

Merged
SureshKViswanathan merged 3 commits into
mainfrom
feature/reverse-transcode-and-rct
Jun 30, 2026
Merged

v1.2.0: public reverse JPEG recompression + YCoCg-R lossless RCT#83
SureshKViswanathan merged 3 commits into
mainfrom
feature/reverse-transcode-and-rct

Conversation

@SureshKViswanathan

Copy link
Copy Markdown
Contributor

v1.2.0 — public reverse JPEG recompression + YCoCg-R lossless RCT

Completes JPEG-XL transfer-syntax exposure and adds a lossless ratio win.

Reverse JPEG recompression (public API)

  • New public JXLDecoder.decodeLosslessJPEG(_:) throws -> Data — the symmetric mirror of encodeLosslessJPEG; reconstructs the byte-identical original JPEG from a JPEG-bridge JXL. Adapter/bridge types stay package.
  • jxl transcode --mode reverse refactored into a thin client over it (kept the --source fallback).
  • async overloads for the recompression pair (J2KSwift facade parity).
  • New PublicAPILosslessJPEGTests (plain import JXLSwift, not @testable) pins external reachability + a fail-safe negative case.

Lossless YCoCg-R RCT — RGB/RGBA, single + multi-group

  • Decorrelates R,G,B → Y,Co,Cg before prediction; transform descriptor written in the global / section-0 GroupHeader; decoder inverts on the assembled image (libjxl-canonical).
  • Cost-gated — applied only when its estimated cost beats raw R,G,B, so it can never inflate a frame.
  • Dropped the redundant [0,sampleHi] gradient-predictor clamp in the residual paths (a no-op in-range; required so RCT's signed/over-range chroma round-trips).
  • New testRCT_LosslessRGB_DecorrelatesIdenticalChannels regression guard.
  • 21–66 % smaller on correlated RGB/RGBA; grayscale and all decode output unchanged.

Verification (reference libjxl 0.11.2, via CLI)

  • RCT lossless: our jxl encode -ldjxl decode → original pixels byte-exact across single/multi-group, 8/16-bit RGB/RGBA, correlated + random.
  • JPEG recompression: cjxl --lossless_jpeg=1 → our decodeLosslessJPEGbyte-identical, and our forward bridge → djxlbyte-identical (4:4:4 / 4:2:2 / 4:2:0 / grayscale).
  • swift build -c release clean.

⚠️ The full XCTest suite was not run in the dev environment (CommandLineTools only, no Xcode); the djxl byte-exact spec gate was exercised directly through the CLI. Recommend swift test -c release on an Xcode host for completeness.

🤖 Generated with Claude Code

Ranjithkumar and others added 3 commits June 30, 2026 16:41
Add `public JXLDecoder.decodeLosslessJPEG(_:)` — the symmetric mirror of the
existing public `encodeLosslessJPEG(_:)`. It chains the previously
package-only reverse pipeline (parseJXLContainer -> extractJBRDBox ->
JBRDBoxReader -> BrotliDecoder -> decodeJPEGBridgeData ->
JXLToJPEGAdapter.reconstruct) so an external `import JXLSwift` consumer can
reconstruct the byte-identical original JPEG. The adapter/bridge types stay
`package`; only the one wrapper becomes public.

- Refactor `jxl-tool transcode --mode reverse` into a thin client over the
  new public API (extract transcodeJXLtoJPEGFromSource / writeReverseOutput;
  keep the optional --source fallback).
- Add `async` overloads for the recompression pair (encodeLosslessJPEG /
  decodeLosslessJPEG) to complete the J2KSwift async-facade parity.
- Add PublicAPILosslessJPEGTests using a plain `import JXLSwift` (NOT
  @testable) so compilation alone pins external reachability, plus a
  forward -> reverse byte-identical round trip and a fail-safe negative case.

Validated end-to-end through the built `jxl` binary: forward bridge ->
reverse is byte-identical for 4:4:4 / 4:2:0 / 4:2:2 / grayscale; a JXL with
no jbrd box is refused (no wrong bytes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…p), cost-gated

Apply the reversible YCoCg-R colour transform to RGB/RGBA channels before
prediction in SpecModularEncoder, decorrelating R,G,B -> Y,Co,Cg so the chroma
channels compress to near-nothing. `RCT.forwardPixel(.ycocgR)` is the exact
inverse of the decoder's `SpecRCT.inverse(rctType: 6)`. The transform
descriptor is emitted only in the section-0 / DC-global GroupHeader of every
single- and multi-group candidate (baseline / activity-split / greedy);
per-AC-group headers stay empty, so the decoder inverts on the assembled image
(libjxl-canonical — transforms live in the global modular header).

- Drop the redundant `[0, sampleHi]` clamp on the gradient predictor in the
  modular residual paths: a no-op for in-range data (existing byte-exact
  output is unchanged) but it diverged from the decoder's ClampedGradient
  (applyLibjxlPredictor id 5) for RCT's signed / over-range Co/Cg, which would
  have broken the round trip.
- Cost-gate RCT (estimateGradientResidualBits): apply YCoCg-R only when its
  estimated residual bit-cost beats the raw R,G,B estimate, so RCT can never
  inflate a frame (already-decorrelated / independent-channel content keeps
  the identity path).
- Add the testRCT_LosslessRGB_DecorrelatesIdenticalChannels regression guard
  (R=G=B => Co=Cg=0 => RGB ~ grayscale, not 3x) to catch a silent RCT-disable.

Self-round-trip validated pixel-exact across single- and multi-group, 8/16-bit
RGB/RGBA, efforts 3/7/9, correlated + adversarial random, grayscale
no-regression. A/B vs a no-RCT build: 21-66% smaller on correlated content,
equal on independent content.

NOTE: the djxl byte-exact cross-validation (RobustnessTests DjxlSubset /
ConformanceTests) must be run on a host with djxl + XCTest; it could not be
run in the dev env where this was authored. The change is high-confidence
(the decoder's RCT is already djxl-validated against cjxl RGB output) but
should be confirmed before merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump JXLToolVersion 1.1.0 -> 1.2.0, Package.swift status, and add the
CHANGELOG 1.2.0 entry.

Highlights (full notes in CHANGELOG.md):
- Public `JXLDecoder.decodeLosslessJPEG(_:)` — reverse JPEG recompression,
  the mirror of `encodeLosslessJPEG`; `jxl transcode --mode reverse` is now a
  thin client over it. Plus async overloads for the recompression pair.
- Lossless RGB/RGBA YCoCg-R RCT (single + multi-group), cost-gated: 21-66 %
  smaller on correlated content, never inflates, decode unchanged.

Verified via reference libjxl 0.11.2: RCT output djxl-byte-exact across
single/multi-group 8/16-bit RGB/RGBA; JPEG recompression byte-identical both
directions (cjxl->our reverse, our forward->djxl). The full XCTest suite needs
an Xcode host (the dev env has only CommandLineTools); the djxl spec gate was
exercised directly through the CLI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SureshKViswanathan SureshKViswanathan merged commit 4b5af09 into main Jun 30, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant