Skip to content

fix(jpeg2000): writer dropped tiled output and overran on last scanline - #5611

Open
lgritz wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
lgritz:lg-j2c-write
Open

lgritz wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
lgritz:lg-j2c-write

Conversation

@lgritz

@lgritz lgritz commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

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

@lgritz
lgritz force-pushed the lg-j2c-write branch 2 times, most recently from 25d1e06 to 34a8caf Compare October 23, 2026 21:08
@lgritz
lgritz requested a balanced review from Copilot October 29, 2026 15:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread src/jpeg2000.imageio/jpeg2000output.cpp
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>
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.

2 participants