DICOM is a file format used by MRI scanners to store MRIs and metadata.
DICOM servers which serve DICOM images over HTTP are expected to adhere to the WADO Specification for DICOM retrieval.
When I use requests with requests-toolbelt’s MultipartDecoder
I can successfully retrieve DICOMs with a streaming response.
When I use httpx
‘s streaming method, the parts received are invalid DICOMs.
Unfortunately, I could not find public access WADO server to help you test this, hopefully you can find one.
How do I fix this?
Here is the Python code to reproduce.
In the code, each part_
should be bytes for a single DICOM file.
from requests_toolbelt.multipart import decoder
logger = logging.getLogger(__name__)
async def async_wado(study_instance_uid, wado_request_url, wado_request_header):
with httpx.Client().stream(method="GET", url=wado_request_url, headers=wado_request_header) as response:
for part_ in response.iter_bytes():
dicom_slice_ = pydicom.dcmread(io.BytesIO(part_),)
# InvalidDicomError,Invalid DICOM header metadata or DICM Missing
def sync_wado(study_instance_uid, wado_request_url, wado_request_header):
wado_response = requests.get(wado_request_url, headers=wado_request_header)
mp_data = decoder.MultipartDecoder.from_response(wado_response)
for count, part_ in enumerate(mp_data.parts, start=1):
if 'application/dicom' in part_.headers[b'Content-Type'].decode(encoding='utf-8'):
dicom_slice_ = pydicom.read_file(io.BytesIO(part_.content))
# Works. .dcm file correctly read, can be saved to disk.
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
study_instance_uid = "<StudyInstanceUIS>"
wado_request_url = f"https://<hostname>:<port>/wado-rs/dicom_web/studies/{study_instance_uid}"
wado_request_header = { 'Accept': 'multipart/related; type=application/dicom' }
sync_wado(study_instance_uid, wado_request_url, wado_request_header)
asyncio.run(async_wado(study_instance_uid, wado_request_url, wado_request_header))
<code>
import asyncio
import io
import logging
import httpx
import pydicom
import requests
from requests_toolbelt.multipart import decoder
logger = logging.getLogger(__name__)
async def async_wado(study_instance_uid, wado_request_url, wado_request_header):
with httpx.Client().stream(method="GET", url=wado_request_url, headers=wado_request_header) as response:
for part_ in response.iter_bytes():
dicom_slice_ = pydicom.dcmread(io.BytesIO(part_),)
# InvalidDicomError,Invalid DICOM header metadata or DICM Missing
def sync_wado(study_instance_uid, wado_request_url, wado_request_header):
wado_response = requests.get(wado_request_url, headers=wado_request_header)
mp_data = decoder.MultipartDecoder.from_response(wado_response)
for count, part_ in enumerate(mp_data.parts, start=1):
if 'application/dicom' in part_.headers[b'Content-Type'].decode(encoding='utf-8'):
dicom_slice_ = pydicom.read_file(io.BytesIO(part_.content))
# Works. .dcm file correctly read, can be saved to disk.
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
study_instance_uid = "<StudyInstanceUIS>"
wado_request_url = f"https://<hostname>:<port>/wado-rs/dicom_web/studies/{study_instance_uid}"
wado_request_header = { 'Accept': 'multipart/related; type=application/dicom' }
sync_wado(study_instance_uid, wado_request_url, wado_request_header)
asyncio.run(async_wado(study_instance_uid, wado_request_url, wado_request_header))
</code>
import asyncio
import io
import logging
import httpx
import pydicom
import requests
from requests_toolbelt.multipart import decoder
logger = logging.getLogger(__name__)
async def async_wado(study_instance_uid, wado_request_url, wado_request_header):
with httpx.Client().stream(method="GET", url=wado_request_url, headers=wado_request_header) as response:
for part_ in response.iter_bytes():
dicom_slice_ = pydicom.dcmread(io.BytesIO(part_),)
# InvalidDicomError,Invalid DICOM header metadata or DICM Missing
def sync_wado(study_instance_uid, wado_request_url, wado_request_header):
wado_response = requests.get(wado_request_url, headers=wado_request_header)
mp_data = decoder.MultipartDecoder.from_response(wado_response)
for count, part_ in enumerate(mp_data.parts, start=1):
if 'application/dicom' in part_.headers[b'Content-Type'].decode(encoding='utf-8'):
dicom_slice_ = pydicom.read_file(io.BytesIO(part_.content))
# Works. .dcm file correctly read, can be saved to disk.
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
study_instance_uid = "<StudyInstanceUIS>"
wado_request_url = f"https://<hostname>:<port>/wado-rs/dicom_web/studies/{study_instance_uid}"
wado_request_header = { 'Accept': 'multipart/related; type=application/dicom' }
sync_wado(study_instance_uid, wado_request_url, wado_request_header)
asyncio.run(async_wado(study_instance_uid, wado_request_url, wado_request_header))