Skip to content

Commit 44f7430

Browse files
committed
NiftiHeader determines dicom byte encoding in extension
1 parent f11ccf9 commit 44f7430

File tree

2 files changed

+48
-19
lines changed

2 files changed

+48
-19
lines changed

nibabel/nifti1.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -382,47 +382,58 @@ def write_to(self, fileobj, byteswap):
382382

383383

384384
class Nifti1DicomExtension(Nifti1Extension):
385-
"""Class for NIfTI1 DICOM header extension.
385+
"""NIfTI1 DICOM header extension.
386386
387387
This class is a thin wrapper around pydicom to read a binary DICOM
388388
byte string. If pydicom is not available, it silently falls back to the
389389
standard NiftiExtension class.
390390
"""
391-
def __init__(self, code, content):
391+
def __init__(self, code, content, parent_hdr=None):
392392
self._code = code
393+
if parent_hdr:
394+
self._is_little_endian = parent_hdr.endianness == '<'
395+
else:
396+
self._is_little_endian = True
393397
if content.__class__ == Dataset:
394398
self._is_implicit_VR = False
395-
self._is_little_endian = True
396399
self._raw_content = self._mangle(content)
397400
self._content = content
398401
elif len(content): # Got a byte string - unmangle it
399402
self._raw_content = content
400403
self._is_implicit_VR = self._guess_implicit_VR()
401-
self._is_little_endian = self._guess_little_endian()
402-
self._content = self._unmangle(content)
403-
else:
404+
ds = self._unmangle_and_verify(content, self._is_implicit_VR,
405+
self._is_little_endian)
406+
self._content = ds
407+
else: # Otherwise, initialize a new dicom dataset
404408
self._is_implicit_VR = False
405-
self._is_little_endian = True
406409
self._content = Dataset()
407410

411+
def _unmangle_and_verify(self, content, is_implicit_VR, is_little_endian):
412+
""""Decode and verify dicom dataset"""
413+
ds = self._unmangle(content, is_implicit_VR, is_little_endian)
414+
for elem in ds:
415+
if elem.VR not in dicom_converters.keys():
416+
raise StandardError # Ensure that all VRs are valid
417+
return ds
418+
408419
def _guess_implicit_VR(self):
409-
"""Without a DICOM Transfer Syntax, it's difficult to tell if Value
420+
"""Try to guess DICOM syntax by checking for valid VRs.
421+
422+
Without a DICOM Transfer Syntax, it's difficult to tell if Value
410423
Representations (VRs) are included in the DICOM encoding or not.
411424
This reads where the first VR would be and checks it against a list of
412-
valid VRs"""
425+
valid VRs
426+
"""
413427
potential_vr = self._raw_content[4:6].decode()
414428
if potential_vr in dicom_converters.keys():
415429
implicit_VR = False
416430
else:
417431
implicit_VR = True
418432
return implicit_VR
419433

420-
def _guess_little_endian(self):
421-
return True
422-
423-
def _unmangle(self, value):
434+
def _unmangle(self, value, is_implicit_VR=False, is_little_endian=True):
424435
bio = BytesIO(value)
425-
ds = read_dataset(bio, self._is_implicit_VR, self._is_little_endian)
436+
ds = read_dataset(bio, is_implicit_VR, is_little_endian)
426437
return ds
427438

428439
def _mangle(self, dataset):

nibabel/tests/test_nifti1.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,7 @@ def test_nifti_dicom_extension():
11041104
dcmext = Nifti1DicomExtension(2, dcmbytes_explicit)
11051105
assert_equal(dcmext.__class__, Nifti1DicomExtension)
11061106
assert_equal(dcmext._guess_implicit_VR(), False)
1107+
assert_equal(dcmext._is_little_endian, True)
11071108
assert_equal(dcmext.get_code(), 2)
11081109
assert_equal(dcmext.get_content().PatientID, 'NiPy')
11091110
assert_equal(len(dcmext.get_content().values()), 1)
@@ -1118,20 +1119,37 @@ def test_nifti_dicom_extension():
11181119
assert_equal(dcmext.get_code(), 2)
11191120
assert_equal(dcmext.get_content().PatientID, 'NiPy')
11201121
assert_equal(len(dcmext.get_content().values()), 1)
1121-
assert_equal(dcmext._mangle(dcmext.get_content()),dcmbytes_implicit)
1122+
assert_equal(dcmext._mangle(dcmext.get_content()), dcmbytes_implicit)
1123+
assert_equal(dcmext.get_sizeondisk() % 16, 0)
1124+
1125+
# create a single dicom tag (Patient ID, [0010,0020]) with Explicit VR / BE
1126+
dcmbytes_explicit_be = struct.pack('>2H2sH4s', 0x10, 0x20,
1127+
'LO'.encode('utf-8'), 4,
1128+
'NiPy'.encode('utf-8'))
1129+
hdr_be = Nifti1Header(endianness='>') # Big Endian Nifti1Header
1130+
dcmext = Nifti1DicomExtension(2, dcmbytes_explicit_be, parent_hdr=hdr_be)
1131+
assert_equal(dcmext.__class__, Nifti1DicomExtension)
1132+
assert_equal(dcmext._guess_implicit_VR(), False)
1133+
assert_equal(dcmext.get_code(), 2)
1134+
assert_equal(dcmext.get_content().PatientID, 'NiPy')
1135+
assert_equal(dcmext.get_content()[0x10, 0x20].value, 'NiPy')
1136+
assert_equal(len(dcmext.get_content().values()), 1)
1137+
assert_equal(dcmext._mangle(dcmext.get_content()), dcmbytes_explicit_be)
11221138
assert_equal(dcmext.get_sizeondisk() % 16, 0)
11231139

1140+
# Check that a dicom dataset is written w/ BE encoding when not created
1141+
# using BE bytestring when given a BE nifti header
1142+
dcmext = Nifti1DicomExtension(2, ds, parent_hdr=hdr_be)
1143+
assert_equal(dcmext._mangle(dcmext.get_content()), dcmbytes_explicit_be)
1144+
11241145
# dicom extension access from nifti extensions
11251146
assert_equal(exts_container.count('dicom'), 0)
11261147
exts_container.append(dcmext)
11271148
assert_equal(exts_container.count('dicom'), 1)
11281149
assert_equal(exts_container.get_codes(), [6, 6, 2])
1129-
assert_equal(dcmext._mangle(dcmext.get_content()), dcmbytes_implicit)
1150+
assert_equal(dcmext._mangle(dcmext.get_content()), dcmbytes_explicit_be)
11301151
assert_equal(dcmext.get_sizeondisk() % 16, 0)
11311152

1132-
bio = BytesIO()
1133-
dcmext.write_to(bio, False)
1134-
11351153

11361154
class TestNifti1General(object):
11371155
""" Test class to test nifti1 in general

0 commit comments

Comments
 (0)