Skip to content

Commit aa1b452

Browse files
committed
ENH: Add VTK XML ImageData (.vti) read/write support to ITKIOVTKTestDriver
- Parse and emit Direction cosines (VTK 9+ row-major 3x3 attribute) - Canonicalize symmetric-tensor layout to VTK [XX,YY,ZZ,XY,YZ,XZ] convention - Fix byte-swap for LE-on-BE host; expose static SwapBufferForByteOrder for testing - Emit version="1.0" and UInt64 block headers matching ParaView 5.7+ - Reject files with DOCTYPE/ENTITY declarations (XXE/billion-laughs mitigation) - Add F-001..F-010 guard exceptions for deferred features with F-NNN tags - Add RGBA round-trip coverage - Add VTI fixture generator (Python stdlib) and synthetic round-trip fixtures - Add hand-crafted oblique-direction fixture with MHD oracle - Add unit tests: direction round-trip, SwapBufferForByteOrder, guard tests, fixture suite - Rewrite class Doxygen with supported features and deferred F-NNN items - Replace manual ExceptionObject with itkGenericExceptionMacro in static methods - Stream-parse XML via expat chunks; suspend at <AppendedData> to avoid loading binary payload into memory (large-file performance improvement) - Add appended-raw + vtkZLibDataCompressor writer via SetUseCompression(true); produces smallest on-disk files; matches ParaView's default write format Disable itkVTIImageIOReadWriteTestVHFColorZLib until ExternalData upload is restored (tracked at ITK#4340); equivalent ZLib code-path coverage provided by itkVTIImageIOGeneratedFixturesTest (vector3_f32_zlib_appended fixture).
1 parent 55f7af7 commit aa1b452

31 files changed

+1936
-180
lines changed

Modules/IO/VTK/include/itkVTIImageIO.h

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,50 @@ namespace itk
2727
/**
2828
* \class VTIImageIO
2929
*
30-
* \brief ImageIO class for reading and writing VTK XML ImageData (.vti) files.
30+
* \brief ImageIO class for reading and writing VTK XML ImageData (.vti)
31+
* files.
3132
*
32-
* Supports the VTK XML ImageData format (version 0.1 and 2.2), including
33-
* ASCII, binary (base64-encoded), and raw-appended data formats.
34-
* Scalar, vector (3-component), RGB, RGBA, and symmetric second rank tensor
35-
* pixel types are supported.
33+
* Supported on read (every encoding ParaView 5.x emits by default):
34+
* * <VTKFile> attributes: type="ImageData", any version, any byte_order
35+
* (LittleEndian / BigEndian), header_type in {UInt32, UInt64}.
36+
* * <ImageData> attributes: WholeExtent, Origin, Spacing, and
37+
* Direction (VTK 9+; defaults to identity when absent).
38+
* * Single-<Piece> images.
39+
* * <DataArray> format = "ascii" | "binary" (inline base64) |
40+
* "appended" (raw or base64 AppendedData).
41+
* * compressor = vtkZLibDataCompressor, or absent (uncompressed).
42+
* * Pixel types: Scalar, Vector (3-component), RGB (3), RGBA (4), and
43+
* symmetric second-rank tensor (6 components, VTK canonical
44+
* [XX, YY, ZZ, XY, YZ, XZ] layout remapped to ITK's internal
45+
* [e00, e01, e02, e11, e12, e22] on read).
3646
*
37-
* The XML structure is parsed using the expat XML library (provided by
38-
* ITKExpat / ITKIOXML), so the parser is robust to attribute ordering,
39-
* whitespace, comments, and CDATA sections. The raw appended data section
40-
* (which is XML-illegal binary content following an `_` marker) is read
41-
* directly from the file at the byte offset recorded by the parser when
42-
* it encountered the `<AppendedData>` element.
47+
* Supported on write:
48+
* * <VTKFile version="1.0" header_type="UInt64"> matching ParaView 5.7+.
49+
* * format = "ascii" and "binary" (inline base64) for every supported
50+
* pixel type except binary symmetric tensor (see deferred list).
51+
* * format = "appended" encoding="raw" + vtkZLibDataCompressor: enabled
52+
* by calling SetUseCompression(true); produces the smallest files on
53+
* disk and matches what ParaView emits by default for large images.
54+
* * Direction is always emitted as a row-major 3x3 Direction attribute,
55+
* padded with identity for images of dimension < 3.
56+
*
57+
* Deferred to the follow-up PR (each has a tagged guard exception so
58+
* `git grep F-NNN` locates the guard + test + commit):
59+
* * F-001 vtkLZ4DataCompressor read
60+
* * F-002 vtkLZMADataCompressor read
61+
* * F-005 multi-<Piece> images
62+
* * F-007 binary symmetric-tensor write
63+
* * F-009 MetaDataDictionary round-trip
64+
* * F-010 catch-all for unknown compressors
65+
*
66+
* Implementation notes:
67+
* * XML header parsing uses expat (ITKExpat); <!DOCTYPE>/<!ENTITY>
68+
* declarations are rejected up-front to mitigate billion-laughs
69+
* and XXE attacks.
70+
* * Expat is fed the file in chunks and suspended (XML_StopParser) at
71+
* the <AppendedData> start tag so binary bytes never enter the parser.
72+
* For large files this avoids a full in-memory copy of the binary
73+
* payload during ReadImageInformation().
4374
*
4475
* \ingroup IOFilters
4576
* \ingroup ITKIOVTK
@@ -94,6 +125,21 @@ class ITKIOVTK_EXPORT VTIImageIO : public ImageIOBase
94125
void
95126
Write(const void * buffer) override;
96127

128+
/** Byte-swap \a numComponents values of \a componentSize bytes each in
129+
* place when \a fileByteOrder differs from \a targetByteOrder. The
130+
* implementation reverses bytes within each component unconditionally
131+
* (via std::reverse) rather than going through ByteSwapper's
132+
* system-relative helpers, so it is deterministic on hosts of either
133+
* endianness and therefore unit-testable without a big-endian runner.
134+
* Public so that endianness behaviour can be exercised directly in
135+
* tests. */
136+
static void
137+
SwapBufferForByteOrder(void * buffer,
138+
std::size_t componentSize,
139+
std::size_t numComponents,
140+
IOByteOrderEnum fileByteOrder,
141+
IOByteOrderEnum targetByteOrder);
142+
97143
protected:
98144
VTIImageIO();
99145
~VTIImageIO() override;

0 commit comments

Comments
 (0)