Skip to content

Commit 32fd4b1

Browse files
committed
Read full datasets (with TransferSyntax)
1 parent a2719d3 commit 32fd4b1

File tree

2 files changed

+83
-17
lines changed

2 files changed

+83
-17
lines changed

nibabel/nifti1.py

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,52 @@ class Nifti1DicomExtension(Nifti1Extension):
390390
def __init__(self, code, content):
391391
self._code = code
392392
self._raw_content = content
393-
self._is_implicit_VR = self._guess_implicit_VR()
393+
self._bio = BytesIO(content)
394394
self._content = self._unmangle(content)
395395

396+
def _check_encoding(self):
397+
"""DICOM Data can be stored in the header either as a valid DICOM
398+
object, with a preamble, meta info, transfer syntax etc., or as a
399+
set of naked tags. Check for meta info and transfer synatx here
400+
and fall back to heuristics if metainfo is missing."""
401+
self._bio.seek(0)
402+
self._preamble = read_preamble(self._bio,True) # Attempt to read preamble,
403+
# skip if missing w/o error
404+
405+
if self._preamble:
406+
self._meta,_is_implicit_VR,_is_little_endian = self._check_meta()
407+
else:
408+
self._meta = None
409+
_is_implicit_VR = self._guess_implicit_VR()
410+
_is_little_endian = self._guess_little_endian()
411+
return _is_implicit_VR,_is_little_endian
412+
413+
414+
def _check_meta(self):
415+
"""Check the DICOM Transfer Syntax and set encoding appropriately.
416+
Extracted from dicom.filereader.read_partial, see there for detail"""
417+
file_meta_dataset = _read_file_meta_info(self._bio)
418+
transfer_syntax = file_meta_dataset.TransferSyntaxUID
419+
if transfer_syntax == dicom.UID.ImplicitVRLittleEndian:
420+
is_implicit_VR = True
421+
is_little_endian = True
422+
elif transfer_syntax == dicom.UID.ExplicitVRLittleEndian:
423+
is_implicit_VR = False
424+
is_little_endian = True
425+
elif transfer_syntax == dicom.UID.ExplicitVRBigEndian:
426+
is_implicit_VR = False
427+
is_little_endian = False
428+
elif transfer_syntax == dicom.UID.DeflatedExplicitVRLittleEndian:
429+
zipped = fileobj.read()
430+
unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
431+
self._bio = BytesIO(unzipped) # a file-like object
432+
is_implicit_VR = False
433+
is_little_endian = True
434+
else:
435+
is_implicit_VR = False
436+
is_little_endian = True
437+
return file_meta_dataset, is_implicit_VR, is_little_endian
438+
396439
def _guess_implicit_VR(self):
397440
"""Without a DICOM Transfer Syntax, it's difficult to tell if Value
398441
Representations (VRs) are included in the DICOM encoding or not.
@@ -405,28 +448,30 @@ def _guess_implicit_VR(self):
405448
implicit_VR=True
406449
return implicit_VR
407450

408-
def _is_little_endian(self):
451+
def _guess_little_endian(self):
409452
return True
410453

411454
def _unmangle(self,value):
412-
raw_io=BytesIO(value)
413-
ds=read_dataset(raw_io,self._is_implicit_VR,self._is_little_endian)
414-
return ds
455+
self._is_implicit_VR, self._is_little_endian = self._check_encoding()
456+
457+
ds=read_dataset(self._bio,self._is_implicit_VR,self._is_little_endian)
458+
content = FileDataset(
459+
self._bio,ds,self._preamble,self._meta,self._is_implicit_VR,self._is_little_endian
460+
)
461+
return content
415462

416463
def _mangle(self, value):
417-
raw_io=BytesIO()
418-
dio=DicomFileLike(raw_io)
419-
dio.is_implicit_VR = self._is_implicit_VR
420-
dio.is_little_endian = self._is_little_endian
421-
ds_len=write_dataset(dio,value)
422-
dio.seek(0)
423-
return dio.read(ds_len)
464+
bio=BytesIO()
465+
write_file(bio,value)
466+
bio.seek(0)
467+
return bio.read()
424468

425469
try:
426-
from dicom.filereader import read_dataset
427-
from dicom.filewriter import write_dataset
428-
from dicom.filebase import DicomFileLike
470+
from dicom.dataset import FileDataset
471+
from dicom.filereader import read_dataset,read_preamble,_read_file_meta_info
472+
from dicom.filewriter import write_file
429473
from dicom.values import converters as dicom_converters
474+
import dicom.UID
430475
from io import BytesIO
431476
except ImportError:
432477
"""Fall back to standard reader if pydicom unavailable."""

nibabel/tests/test_nifti1.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
header_file = os.path.join(data_path, 'nifti1.hdr')
4242
image_file = os.path.join(data_path, 'example4d.nii.gz')
43+
dicom_file = os.path.join(data_path, '0.dcm')
4344

4445
try:
4546
import dicom
@@ -1093,6 +1094,8 @@ def test_nifti_dicom_extension():
10931094
dcmext = Nifti1DicomExtension(2,dcmbytes_explicit)
10941095
assert_equal(dcmext.__class__, Nifti1DicomExtension)
10951096
assert_equal(dcmext._guess_implicit_VR(),False)
1097+
assert_equal(dcmext._is_implicit_VR,False)
1098+
assert_equal(dcmext._is_little_endian,True)
10961099
assert_equal(dcmext.get_code(),2)
10971100
assert_equal(dcmext.get_content().PatientID, 'NiPy')
10981101
assert_equal(len(dcmext.get_content().values()), 1)
@@ -1103,6 +1106,8 @@ def test_nifti_dicom_extension():
11031106
dcmbytes_implicit = struct.pack('<HHL4s',0x10,0x20,4,'NiPy'.encode('utf-8'))
11041107
dcmext = Nifti1DicomExtension(2,dcmbytes_implicit)
11051108
assert_equal(dcmext._guess_implicit_VR(),True)
1109+
assert_equal(dcmext._is_implicit_VR,True)
1110+
assert_equal(dcmext._is_little_endian,True)
11061111
assert_equal(dcmext.get_code(),2)
11071112
assert_equal(dcmext.get_content().PatientID, 'NiPy')
11081113
assert_equal(len(dcmext.get_content().values()), 1)
@@ -1117,8 +1122,24 @@ def test_nifti_dicom_extension():
11171122
assert_equal(dcmext._mangle(dcmext.get_content()),dcmbytes_implicit)
11181123
assert_equal(dcmext.get_sizeondisk() % 16, 0)
11191124

1120-
raw_io = BytesIO()
1121-
dcmext.write_to(raw_io,False)
1125+
# Use a full dicom file with metadata as a header
1126+
with open(dicom_file,'rb') as dim:
1127+
dcmbytes_full = dim.read()
1128+
dcmext = Nifti1DicomExtension(2,dcmbytes_full)
1129+
assert_equal(dcmext._is_implicit_VR,True)
1130+
assert_equal(dcmext._is_little_endian,True)
1131+
assert_equal(dcmext.get_code(),2)
1132+
assert_equal(dcmext.get_content().PatientID, '1234')
1133+
assert_equal(len(dcmext.get_content().values()), 139)
1134+
# assert_equal(
1135+
# dcmext.get_content().file_meta,
1136+
# dicom.filereader.read_file_meta_info(dicom_file))
1137+
assert_equal(dcmext.get_sizeondisk() % 16, 0)
1138+
1139+
# make it round-tripable
1140+
assert_equal(dcmext._mangle(dcmext.get_content()),dcmbytes_full)
1141+
1142+
dcmext.write_to(BytesIO(),False)
11221143

11231144
class TestNifti1General(object):
11241145
""" Test class to test nifti1 in general

0 commit comments

Comments
 (0)