Skip to content

v4.0b Windows & Linux

Choose a tag to compare

@github-actions github-actions released this 28 Apr 03:51
· 19 commits to master since this release

v4.0b (2026-04-27) — format simplification + diagonal DC neighbor context

v4.0b is the new starting point of the post-v4.0 lineage. It collapses
the three-format dispatch (v4.0 + v4.0a + v3.1d-via-legacy) into a single
accepted version byte (0x28 / 40) plus an optional sub-marker (0x02)
that flags the new diagonal DC neighbor context. The -legacy flag is
removed; v3.1d archives are no longer decoded by this build.

Versioning policy (new): N.0x releases (4.0, 4.0a, 4.0b, …) are
LTS-style with binary filename packJPG, bug-fix only after their
initial drop. N.Mx releases (4.1, 4.1a, 4.2, …) are feature-bearing
with binary filename packJPG-N.Mx, format breaks land here. v4.0b is
a one-time exception — it carries the diagonal DC change that was
originally tagged v4.1 (never released publicly), rebranded so the v4.1
slot stays available for a real feature drop.

The diagonal DC change adds a 4-bucket variance context computed from
|L − T| + |T − TR| (absolute values of the already-encoded left, top
and top-right DC neighbors). It captures directional gradient patterns
that the existing weighted-average context blends away. Result: a small
but consistent ratio win at neutral wall time.

Inspired by the SITX (StuffIt JPEG) reverse-engineered codebase shared
by Melirius on encode.su. SITX dequant achieves ~5 % better than
packJPG via ensemble-blended context models (4 parallel histograms with
weights 8/6/4/2); packJPG's single-context arith coder can't replicate
that without a major refactor. Of three SITX-inspired ideas tested
(diagonal context, multi-resolution variance, zigzag-position AC priors)
only the diagonal context paid off — multi-resolution variance
correlated too tightly with the existing ctx_len, and zigzag AC priors
spread statistics too thin across the well-tuned AC bit-length model.

Format

  • new: 0x02 sub-marker before the version byte (0x28) signals
    v4.0b features. Decoder semantics:
    • JS 28 … → v4.0 / v4.0a file, pjg_use_diag_dc_now = false
      (old DC context, full backward-compat decode of legacy archives)
    • JS 02 28 … → v4.0b file, pjg_use_diag_dc_now = true
      (new diagonal DC context active)
    • v4.0 / v4.0a binaries reading a v4.0b file see 0x02, fall through
      to "unknown header code" → clean error, no silent corruption.
  • removed: -legacy CLI flag and format_version_legacy = 31 /
    format_version_v40_compat = 40 constants. Single accepted format byte.
  • removed: legacy_mode THREAD_LOCAL global and its MT-worker propagation.

Encoder / decoder

  • new: diagonal/anti-diagonal DC neighbor context in pjg_encode_dc
    and pjg_decode_dc. 4 buckets from |L − T| + |T − TR| of the
    absolute-value neighbors, multiplying mod_len_maxc by 4 (or 32 when
    stacked with cross-component). Gated by pjg_use_diag_dc_now.
  • the v4.0a cross-component DC prediction stays on permanently in the
    sequential encode/decode path. Sfth workers keep it off (no Y available
    during parallel Cb/Cr encoding) — unchanged from v4.0.

Repository

  • renamed source4xp/sourcelegacy/ and build4xp.shbuild_legacy.sh
    (Win XP/Win7/Win8 community-maintained port now lives here; documents
    the boundary explicitly: source/ targets Win10+/Linux/macOS via
    std::filesystem, sourcelegacy/ targets legacy Windows via Win32 API
    through xp_compat.h).
  • source/ Win-version-specific comments updated to reflect Win10+ scope.

Bench

43 mixed JPGs / 10.86 MB on Linux x64:

Output Ratio Time
v4.0a 6,730,670 B 65.574 % 12.09 s
v4.0b 6,727,753 B 65.566 % 12.02 s

Δ: −0.043 % bytes, 0.994× wall time, all round-trips byte-exact. All
v4.0/v4.0a-encoded files in the test corpus decoded byte-exactly with
v4.0b (backward-compat verified).

Migration notes

  • Existing v4.0 / v4.0a .pjg archives keep working — v4.0b reads them
    transparently.
  • v4.0b-encoded .pjg files are NOT readable by v4.0/v4.0a binaries
    (clean rejection, no crash).
  • v3.1d archives need the original v3.1d binary (or v4.0 with -legacy,
    for which a v4.0a build is still archived in dist/ of the v4.0a tag).