Skip to content

fix(j2k): write the last row of output buffers without trailing padding - #313

Merged
jcwal1516 merged 1 commit into
mainfrom
fix/strided-last-row
Nov 1, 2026
Merged

jcwal1516 merged 1 commit into
mainfrom
fix/strided-last-row

Conversation

@jcwal1516

Copy link
Copy Markdown
Member

The packed 8- and 16-bit writers zipped the source rows with
out.chunks_exact_mut(stride). Buffer validation accepts a buffer of
strided_output_len bytes, stride * (height - 1) + row_bytes, which
has no padding after the last row; with a stride wider than the row, that
last row is a partial chunk, chunks_exact_mut drops it, and the decode
returned Ok with the row unwritten. This hit full-image and scaled 8-bit
decodes at such a stride (row copies, RGB to RGBA and RGBA to RGB) and
every 16-bit decode at one, regions included. The 8-bit region row sink and
the component-plane writers already index rows and were not affected.

The five loops now take their rows from one helper that chunks by stride
and keeps the last, shorter chunk, sliced to the row's bytes as before.
The loops are otherwise unchanged.

A new decode test writes every 8- and 16-bit format of gray, RGB and RGBA
images at 8 and 12 bits, full, region, scaled and region-scaled, serial
and parallel, into a buffer of exactly strided_output_len bytes and
compares it with a decode into a padded buffer: 96 of its 160 cases lost
the last row before this change.

Validation

  • The staged change passed the recorded ARM64 macOS and x86-64 Linux branch checks, including the native/facade tests, formatting, linting, API snapshots and repository checks.
  • The regression test covers 160 format, request and parallelism combinations; 96 failed before the fix in the recorded red run.
  • No public API changes.
  • Required CUDA and Metal quick validation will run on this PR’s exact head before merge.

The packed 8- and 16-bit writers zipped the source rows with
`out.chunks_exact_mut(stride)`. Buffer validation accepts a buffer of
`strided_output_len` bytes, `stride * (height - 1) + row_bytes`, which
has no padding after the last row; with a stride wider than the row, that
last row is a partial chunk, `chunks_exact_mut` drops it, and the decode
returned Ok with the row unwritten. This hit full-image and scaled 8-bit
decodes at such a stride (row copies, RGB to RGBA and RGBA to RGB) and
every 16-bit decode at one, regions included. The 8-bit region row sink and
the component-plane writers already index rows and were not affected.

The five loops now take their rows from one helper that chunks by stride
and keeps the last, shorter chunk, sliced to the row's bytes as before.
The loops are otherwise unchanged.

A new decode test writes every 8- and 16-bit format of gray, RGB and RGBA
images at 8 and 12 bits, full, region, scaled and region-scaled, serial
and parallel, into a buffer of exactly `strided_output_len` bytes and
compares it with a decode into a padded buffer: 96 of its 160 cases lost
the last row before this change.
@jcwal1516
jcwal1516 merged commit 0fd7d0b into main Nov 1, 2026
30 of 32 checks passed
@jcwal1516
jcwal1516 deleted the fix/strided-last-row branch November 1, 2026 20:09
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