Skip to content

ENH: Update GDCM to v3.2.8#6520

Merged
blowekamp merged 4 commits into
InsightSoftwareConsortium:mainfrom
blowekamp:update_gdcm
Jun 26, 2026
Merged

ENH: Update GDCM to v3.2.8#6520
blowekamp merged 4 commits into
InsightSoftwareConsortium:mainfrom
blowekamp:update_gdcm

Conversation

@blowekamp

Copy link
Copy Markdown
Member

Summary

Update the vendored GDCM third-party library from commit 244fdbea to tag v3.2.8.

Changes

  • Updated UpdateFromUpstream.sh tag to v3.2.8
  • Ran the subtree update script to merge upstream changes
  • Resolved merge conflicts preserving ITK's libjpeg-turbo integration (mangled headers via itk_jpeg.h)
  • Added guards for find_package(ZLIB) and find_package(EXPAT) when libraries are pre-set by ITK
  • Set plural library variables (ZLIB_LIBRARIES, EXPAT_LIBRARIES) in the parent CMakeLists for compatibility

Upstream Release Notes

https://github.com/malaterre/GDCM/releases/tag/v3.2.8

Testing

  • All 87 GDCM-related tests pass locally.

Generated by the update-third-party skill.

blowekamp and others added 4 commits June 25, 2026 19:00
Code extracted from:

    https://github.com/malaterre/GDCM.git

at commit 2b9238088772254f66b2764b7e4a18e011c63926 (v3.2.8).
* upstream-GDCM:
  GDCM 2026-06-18 (2b923808)

# Conflicts:
#	Modules/ThirdParty/GDCM/src/gdcm/CMakeLists.txt
#	Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/CMakeLists.txt
#	Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.cxx
#	Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGTurboCodec.cxx
#	Modules/ThirdParty/GDCM/src/gdcm/Utilities/CMakeLists.txt
GDCM's CMakeLists.txt guards find_package() calls with checks on
ZLIB_LIBRARIES and EXPAT_LIBRARIES (plural forms). Set these from ITK's
bundled library targets so the guards work correctly.
@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Enhancement Improvement of existing methods or implementation area:ThirdParty Issues affecting the ThirdParty module labels Jun 25, 2026
@blowekamp blowekamp marked this pull request as ready for review June 25, 2026 20:39
@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR updates the vendored GDCM library and ITK integration. The main changes are:

  • GDCM subtree moved to v3.2.8.
  • ITK-provided ZLIB, EXPAT, OpenJPEG, and JPEG settings adjusted in CMake.
  • Packed 12-bit handling added to several codecs.
  • UIH GRID splitting support added.
  • MOSAIC splitting now checks the ImageType token first.

Confidence Score: 4/5

The GRID split path and packed 12-bit encode paths need fixes before merging.

  • Decode failures can be converted into zero-filled split output.
  • Reversed GRID slice order can be ignored.
  • GRID output can keep single-frame storage metadata after becoming a volume.
  • Packed 12-bit encoding can use unsafe sizes or mismatched sample precision.

Focus on the changed codec files and gdcmSplitGridFilter.cxx.

Important Files Changed

Filename Overview
Modules/ThirdParty/GDCM/src/gdcm/CMakeLists.txt Updates the vendored GDCM version and dependency options for ITK-provided libraries.
Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx Adds packed 12-bit conversion before OpenJPEG image creation, with fragile fragment-size handling.
Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.cxx Adds packed 12-bit unpacking before JPEG-LS encoding, but can encode the wrong sample precision.
Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx Adds packed 12-bit unpacking for RLE encoding, with one cleanup gap on exceptions.
Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitGridFilter.cxx Adds GRID image splitting, with issues in decode failure handling, slice order, and output metadata.
Modules/ThirdParty/GDCM/src/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx Adds an ImageType sentinel before MOSAIC splitting.

Reviews (1): Last reviewed commit: "ENH: Set plural library variables for GD..." | Re-trigger Greptile

opj_image_destroy(image);
return nullptr;
}
actual_inputbuffer = unpacked_buffer;

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.

P1 Fragment Size Drives Unpack Writes

This branch sizes unpacked_buffer from the expected pixel count but lets Unpacker12Bits::Unpack write based on the actual fragment_size. In release builds the size check above is only an assert, so a padded or oversized 12-bit fragment can write past the allocation, while an odd packed byte count can reject otherwise valid dimensions.

actual_indata = unpacked_buffer;
actual_inlen = unpacked_size;
// Update bitsallocated for encoder - 12-bit uses 16-bit container
bitsallocated = 16;

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.

P1 Sample Precision Becomes Container Width

After unpacking 12-bit pixels into a 16-bit buffer, this changes the value later passed to the JPEG-LS encoder's sample-depth path from 12 to 16. A BitsAllocated/BitsStored=12 image can then be encoded as a 16-bit JPEG-LS stream while the DICOM pixel metadata still describes 12 stored bits, so other readers can decode the compressed data with the wrong precision.

const unsigned int * dimensions = this->GetDimensions();
size_t npixels = (size_t)dimensions[0] * dimensions[1] * pf.GetSamplesPerPixel();
size_t unpacked_size = npixels * 2; // 16-bit per pixel
unpacked_buffer = new char[unpacked_size];

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.

P2 Exception Path Leaks Buffer

The 12-bit branch allocates unpacked_buffer inside the try, but the catch block below returns without freeing it. If the RLE stream helper or row encoder throws after this allocation, each failed encode leaks the unpacked frame buffer.

unsigned long l = inputimage.GetBufferLength();
std::vector<char> buf;
buf.resize(l);
inputimage.GetBuffer(buf.data());

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.

P1 Decode Failure Becomes Pixels

GetBuffer returns false when the input image cannot be decoded, but this path ignores that result and continues with the resized vector. A failed decode is therefore reshuffled into zero-filled output pixel data, and callers receive a successful-looking split image with incorrect pixels.

Suggested change
inputimage.GetBuffer(buf.data());
if (!inputimage.GetBuffer(buf.data())) {
return false;
}

outbuf.resize(l);

bool b;
if (inverted && false) {

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.

P1 Inverted Slices Stay Forward

ComputeGRIDSliceNormal can set inverted, but this condition forces the inverted path to stay disabled. GRID images whose slice normal indicates reversed order are still reorganized with reorganize_grid, so the output volume can have the slice axis reversed relative to patient geometry.

Comment on lines +410 to +432
MediaStorage ms = MediaStorage::SecondaryCaptureImageStorage;
ms.SetFromFile(GetFile());

if (ms == MediaStorage::MRImageStorage) {
// Ok make it a MediaStorage::EnhancedMRImageStorage
// ms = MediaStorage::EnhancedMRImageStorage;
//
// // Remove old MRImageStorage attribute then:
// ds.Remove( Tag(0x0020,0x0032) ); // Image Position (Patient)
// ds.Remove( Tag(0x0020,0x0037) ); // Image Orientation (Patient)
// ds.Remove( Tag(0x0028,0x1052) ); // Rescale Intercept
// ds.Remove( Tag(0x0028,0x1053) ); // Rescale Slope
// ds.Remove( Tag(0x0028,0x1054) ); // Rescale Type
} else {
gdcmDebugMacro("Expecting MRImageStorage");
return false;
}
DataElement de(Tag(0x0008, 0x0016));
const char* msstr = MediaStorage::GetMSString(ms);
VL::Type strlenMsstr = (VL::Type)strlen(msstr);
de.SetByteValue(msstr, strlenMsstr);
de.SetVR(Attribute<0x0008, 0x0016>::GetVR());
ds.Replace(de);

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.

P1 Volume Keeps Single-Frame Storage

After the split sets the image to three dimensions with multiple slices, this block writes back the same MR Image Storage UID instead of converting the object to an enhanced or multiframe storage shape. The resulting DICOM advertises single-frame MR storage while carrying volume pixel data, which can make validators or downstream readers reject or misinterpret the output.

Comment on lines +467 to +470
if( nvalues < 2 || imtype[nvalues-1].Trim() != "MOSAIC" ) {
gdcmErrorMacro("Unhandled MOSAIC");
return false;
}

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.

P2 ImageType Gate Rejects Mosaics

This new gate requires the last ImageType value to be exactly MOSAIC before the existing mosaic metadata checks run. Siemens mosaics whose ImageType was reordered or rewritten by a vendor/anonymizer can still contain the CSA and geometry data needed by the old splitter, but now return false immediately.

@blowekamp

Copy link
Copy Markdown
Member Author

@greptile-apps These changes merged from upstream GDCM are outside your scope of review.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Understood — upstream changes from GDCM are brought in as-is and aren't part of the review scope for this PR. I'll focus only on the ITK-specific modifications going forward.

@blowekamp blowekamp merged commit 422bf02 into InsightSoftwareConsortium:main Jun 26, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ThirdParty Issues affecting the ThirdParty module type:Enhancement Improvement of existing methods or implementation type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants