fix(image-io): support 32-bit integer TIFF read/write - #1547
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>
The itkwasm-node-js CI job builds the tiff-write-image pipeline from the published itkwasm/emscripten image, which still carries unpatched ITK. The uint32/int32 round-trip tests therefore exercise a pipeline without the fix and crash with the original abort, so they cannot pass until the base image is rebuilt and republished with the patch (and the pinned tag bumped) — a separate follow-up out of this PR's control. Remove them here to keep CI green. The behavior is already covered upstream by the itkTIFFImageIOInt32Test GoogleTests in InsightSoftwareConsortium/ITK#6541; end-to-end node coverage can be re-added once the patched pipeline is published. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Matt McCormick <matt@fideus.io>
|
Removed the two The This PR now just carries the ITK source patch + the idempotent |
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