Skip to content

fix(image-io): support 32-bit integer TIFF read/write#1547

Open
thewtex wants to merge 3 commits into
InsightSoftwareConsortium:mainfrom
thewtex:write-image-uint32
Open

fix(image-io): support 32-bit integer TIFF read/write#1547
thewtex wants to merge 3 commits into
InsightSoftwareConsortium:mainfrom
thewtex:write-image-uint32

Conversation

@thewtex

@thewtex thewtex commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #1544writeImageNode / writeImage crashed when given a Uint32Array (component type uint32), while uint8/uint16 worked.

Root cause is in ITK's itk::TIFFImageIO (which ITK-Wasm builds from the pinned thewtex/ITK branch). Although uint32/int32 are advertised as supported component types and the TIFF metadata reader maps 32-bit samples to IOComponentEnum::UINT/::INT, the pixel paths did not handle them:

  • Write threw itk::ExceptionObject for uint32/int32, which surfaced to JS as an unrecoverable WASM abort (the raw exception-pointer number in the issue).
  • Read had no UINT/INT dispatch case, so a 32-bit-integer TIFF read back as a zero-filled buffer.

Other formats (MetaImage, NRRD, NIfTI, VTK) already round-trip uint32 fine; this was TIFF-specific (uint32 and int32).

Changes

  • src/docker/itk-wasm-base/patches/itk-tiff-uint32-int32.patch — ITK source fix adding the missing UINT/INT cases to TIFFImageIO's write (bits-per-sample, SAMPLEFORMAT, row-length) and read (component dispatch) paths. Formatted as a git format-patch so it can also be applied with git am.
  • src/docker/itk-wasm-base/Dockerfile — apply patches/*.patch to the ITK source after checkout, via an idempotent git apply loop (reverse-check skips an already-applied patch, so a local ITK with the fix — USE_LOCAL_ITK=1 — is left untouched).
  • src/docker/itk-wasm-base/patches/README.md — documents the patch mechanism.
  • packages/image-io/typescript/test/node/tiff-test.jsuint32 and int32 TIFF round-trip regression tests (values exceed the 16-bit range to exercise real 32-bit storage).

Upstream

The same fix is submitted to ITK: InsightSoftwareConsortium/ITK#6541. The patch here is a stopgap and should be removed once that lands in the pinned ITK branch. Reaching users requires rebuilding and republishing the emscripten-base / emscripten images (the fix rebuilds ITK).

Testing

Verified end-to-end with a targeted ITK + pipeline rebuild against the patched source: the original issue reproduction now succeeds, written TIFFs are byte-correct (BitsPerSample=32), and uint32/int32 round-trip with full 32-bit fidelity (values up to ~1.17M) in both 2-D and 3-D (multi-page), with no regression on uint8/int16/float32. Upstream, the ITK TIFF ctest suite passes 64/64 including 4 new cases.

🤖 Generated with Claude Code

Writing a uint32/int32 TIFF image (e.g. writeImageNode with a .tif output)
aborted the WebAssembly module, and reading one back silently returned a
zero-filled buffer. ITK's itk::TIFFImageIO handled only 8-/16-bit integers and
32-bit float in its pixel read/write paths, even though it advertises
uint32/int32 as supported component types.

Carry an ITK source patch, applied during the emscripten-base image build, that
adds the missing UINT/INT cases to TIFFImageIO's write (bits-per-sample,
sample-format, row-length) and read (component dispatch) paths, and wire an
idempotent `git apply` step into the base Dockerfile so a local ITK that already
carries the fix is left untouched. Add a uint32/int32 TIFF round-trip regression
test to the image-io Node test suite.

The fix has been submitted upstream as InsightSoftwareConsortium/ITK#6541; the
patch is a stopgap until it lands in the pinned ITK branch.

Fixes InsightSoftwareConsortium#1544

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Matt McCormick <matt@fideus.io>
@thewtex thewtex requested review from blowekamp and removed request for blowekamp July 2, 2026 19:53
thewtex and others added 2 commits July 2, 2026 15:55
Regenerate itk-tiff-uint32-int32.patch from the amended upstream commit
(InsightSoftwareConsortium/ITK@1f3573ab) after a Greptile review collapsed the
duplicated uint32/int32 arms in TIFFImageIO's bits-per-sample and row-length
switches into single C++ fall-through cases. Behavior is unchanged; the patch
stays byte-identical to the source portion of the upstream fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Matt McCormick <matt@fideus.io>
Regenerate itk-tiff-uint32-int32.patch from the amended upstream commit
(InsightSoftwareConsortium/ITK@b9a1b03e) after review: TIFFImageIO now sets
SAMPLEFORMAT_UINT explicitly for the unsigned 8- and 16-bit cases (UCHAR/USHORT)
instead of relying on libtiff's default. Behavior-preserving (the byte-exact
--compare-MD5 TIFF tests are unchanged); keeps the patch byte-identical to the
source portion of the upstream fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Matt McCormick <matt@fideus.io>
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.

[Bug] writeImageNode crashes with Uint32Array, but not Uint8Array or Uint16Array

1 participant