@@ -29,31 +29,95 @@ else:
2929 loads = dask_deserialize.dispatch(np.ndarray)
3030 return NDArrayITKBase(loads(header, frames))
3131
32+ # Module-level constant — built once at import time.
33+ # Composite pixel types (RGB, Vector, etc.) are decomposed to their
34+ # scalar component type before reaching _get_buffer_formatstring(),
35+ # so only scalar codes appear here.
36+ # Platform aliases (ST/IT/OT) resolve to UL/SL at the wrapping level.
37+ import os as _os
38+ _BUFFER_FORMAT_MAP = {
39+ # --- integer types ---
40+ "B": "?", # bool
41+ "UC": "B", # unsigned char -> uint8
42+ "US": "H", # unsigned short -> uint16
43+ "UI": "I", # unsigned int -> uint32
44+ "UL": "L", # unsigned long -> platform (8 bytes Linux/macOS, 4 bytes Windows)
45+ "ULL": "Q", # unsigned long long -> uint64
46+ "SC": "b", # signed char -> int8
47+ "SS": "h", # signed short -> int16
48+ "SI": "i", # signed int -> int32
49+ "SL": "l", # signed long -> platform
50+ "SLL": "q", # signed long long -> int64
51+ # --- floating point types ---
52+ "F": "f", # float -> float32
53+ "D": "d", # double -> float64
54+ # "LD" (long double) intentionally omitted: sizeof(long double)
55+ # is 16 bytes on Linux/macOS x86-64 but struct "d" is 8 bytes.
56+ # Casting would silently corrupt the buffer.
57+ }
58+
59+ def _get_buffer_formatstring(itk_pixel_code: str) -> str:
60+ """Return the struct format character for an ITK pixel type code.
61+
62+ Used by the PEP 688 ``__buffer__`` protocol implementation on
63+ ``itk.Image`` to describe the element type of the exported
64+ memoryview. Format characters follow Python's ``struct`` module
65+ specification.
66+
67+ Parameters
68+ ----------
69+ itk_pixel_code : str
70+ Short name of the ITK component type, e.g. ``"UC"``, ``"F"``.
71+
72+ Returns
73+ -------
74+ str
75+ Single-character ``struct`` format string.
76+
77+ Raises
78+ ------
79+ KeyError
80+ If ``itk_pixel_code`` is not a supported scalar type.
81+ """
82+ try:
83+ return _BUFFER_FORMAT_MAP[itk_pixel_code]
84+ except KeyError:
85+ raise KeyError(
86+ f"Unsupported ITK pixel type code {itk_pixel_code!r} for "
87+ f"buffer export. Supported codes: "
88+ f"{sorted(_BUFFER_FORMAT_MAP)}"
89+ ) from None
90+ if _os.name == 'nt':
91+ # On Windows, C ``long`` is 32-bit
92+ _BUFFER_FORMAT_MAP['UL'] = 'I'
93+ _BUFFER_FORMAT_MAP['SL'] = 'i'
94+
95+
3296def _get_numpy_pixelid(itk_Image_type) -> np.dtype:
3397 """Returns a ITK PixelID given a numpy array."""
3498
35- # This is a Mapping from numpy array types to itk pixel types.
36- _np_itk = {"UC":np.dtype(np.uint8),
37- "US":np.dtype(np.uint16),
38- "UI":np.dtype(np.uint32),
39- "UL":np.dtype(np.uint64),
40- "ULL": np.dtype(np.uint64 ),
41- "SC": np.dtype(np.int8 ),
42- "SS": np.dtype(np.int16 ),
43- "SI": np.dtype(np.int32 ),
44- "SL": np.dtype(np.int64 ),
45- "SLL": np.dtype(np.int64 ),
46- "F": np.dtype(np.float32 ),
47- "D": np.dtype(np.float64 ),
48- "PF2": np.dtype(np.float32 ),
49- "PF3": np.dtype(np.float32 ),
50- }
51- import os
52- if os.name == 'nt':
53- _np_itk['UL'] = np.dtype(np.uint32)
54- _np_itk['SL'] = np.dtype(np.int32)
55- try:
56- return _np_itk[itk_Image_type]
57- except KeyError as e:
58- raise e
99+ return _NUMPY_PIXELID_MAP[itk_Image_type]
100+
101+
102+ # Module-level constant — built once at import time.
103+ _NUMPY_PIXELID_MAP = {
104+ "B": np.dtype(np.bool_ ),
105+ "UC": np.dtype(np.uint8 ),
106+ "US": np.dtype(np.uint16 ),
107+ "UI": np.dtype(np.uint32 ),
108+ "UL": np.dtype(np.uint64 ),
109+ "ULL": np.dtype(np.uint64 ),
110+ "SC": np.dtype(np.int8 ),
111+ "SS": np.dtype(np.int16 ),
112+ "SI": np.dtype(np.int32 ),
113+ "SL": np.dtype(np.int64 ),
114+ "SLL": np.dtype(np.int64),
115+ "F": np.dtype(np.float32),
116+ "D": np.dtype(np.float64),
117+ "PF2": np.dtype(np.float32),
118+ "PF3": np.dtype(np.float32),
119+ }
120+ if _os.name == 'nt':
121+ _NUMPY_PIXELID_MAP['UL'] = np.dtype(np.uint32)
122+ _NUMPY_PIXELID_MAP['SL'] = np.dtype(np.int32)
59123%}
0 commit comments