Repository navigation
Conversation
lgritz
force-pushed
the
lg-j2c-write
branch
2 times, most recently
from
October 23, 2026 21:08
25d1e06 to
34a8caf
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The tiled round-trip tests omit invalid-row boundary cases, leaving the JPEG2000 scanline guard unprotected against a regression that could reintroduce a buffer overrun.
1 open issue
What changed in this PR
This PR fixes JPEG2000 writer behavior so buffered tiled output is saved on close and invalid scanline indices are rejected before accessing component buffers.
Changes:
- Detect open writers using image objects rather than the output stream.
- Correct scanline bounds checks and remove duplicate origin subtraction.
- Add tiled-output round-trip tests for the OpenJPEG and OpenJPH writers.
| File | Description |
|---|---|
testsuite/jpeg2000/run.py |
Adds an OpenJPEG tiled-output regression test. |
testsuite/jpeg2000/ref/out.txt |
Records the expected tiled round-trip result. |
testsuite/jpeg2000/ref/out-icc.txt |
Updates the ICC-enabled reference with the tiled result. |
testsuite/htj2k/run.py |
Adds an OpenJPH tiled-output regression test. |
testsuite/htj2k/ref/out.txt |
Records the expected OpenJPH tiled round-trip result. |
src/jpeg2000.imageio/jpeg2000output.cpp |
Fixes close-state detection, scanline bounds, and row offsets. |
Review effort: Balanced
Tiles are emulated by buffering the whole image and writing it out as scanlines on close(). But close() took a null m_stream to mean "already closed", and m_stream is only created once the last scanline is written (never, on the OpenJPH path), so the buffered image was silently dropped, leaving an empty or truncated file. Test for the image objects instead. Tests added for both the OpenJPEG and OpenJPH writers. Also, write_scanline() let y == height through, so copy_scanline() wrote a row past the end of the OpenJPEG component buffers, and negative y was not checked at all. And copy_scanline() subtracted m_spec.y a second time; that is latent only because check_open() zeroes the origin for this format. Assisted-by: Claude Code / Claude Opus 5.5 Signed-off-by: Larry Gritz <lg@larrygritz.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Tiles are emulated by buffering the whole image and writing it out as scanlines on close(). But close() took a null m_stream to mean "already closed", and m_stream is only created once the last scanline is written (never, on the OpenJPH path), so the buffered image was silently dropped, leaving an empty or truncated file. Test for the image objects instead. Tests added for both the OpenJPEG and OpenJPH writers.
Also, write_scanline() let y == height through, so copy_scanline() wrote a row past the end of the OpenJPEG component buffers, and negative y was not checked at all. And copy_scanline() subtracted m_spec.y a second time; that is latent only because check_open() zeroes the origin for this format.
Assisted-by: Claude Code / Claude Opus 5.5