fix(image-io): support 32-bit integer TIFF read/write#1547
Open
thewtex wants to merge 3 commits into
Open
Conversation
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>
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>
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.
Summary
Fixes #1544 —
writeImageNode/writeImagecrashed when given aUint32Array(component typeuint32), whileuint8/uint16worked.Root cause is in ITK's
itk::TIFFImageIO(which ITK-Wasm builds from the pinnedthewtex/ITKbranch). Althoughuint32/int32are advertised as supported component types and the TIFF metadata reader maps 32-bit samples toIOComponentEnum::UINT/::INT, the pixel paths did not handle them:itk::ExceptionObjectforuint32/int32, which surfaced to JS as an unrecoverable WASM abort (the raw exception-pointer number in the issue).UINT/INTdispatch case, so a 32-bit-integer TIFF read back as a zero-filled buffer.Other formats (MetaImage, NRRD, NIfTI, VTK) already round-trip
uint32fine; this was TIFF-specific (uint32andint32).Changes
src/docker/itk-wasm-base/patches/itk-tiff-uint32-int32.patch— ITK source fix adding the missingUINT/INTcases toTIFFImageIO's write (bits-per-sample,SAMPLEFORMAT, row-length) and read (component dispatch) paths. Formatted as agit format-patchso it can also be applied withgit am.src/docker/itk-wasm-base/Dockerfile— applypatches/*.patchto the ITK source after checkout, via an idempotentgit applyloop (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.js—uint32andint32TIFF 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/emscriptenimages (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), anduint32/int32round-trip with full 32-bit fidelity (values up to ~1.17M) in both 2-D and 3-D (multi-page), with no regression onuint8/int16/float32. Upstream, the ITK TIFFctestsuite passes 64/64 including 4 new cases.🤖 Generated with Claude Code