Mercurial > hg > orthanc-dicomweb
changeset 488:b0e9d55ee247
Fix compliance with DICOM >= 2016c: WADO-RS Retrieve transcodes to Little Endian Explicit by default
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 18 Jan 2021 16:46:17 +0100 |
parents | 327acd0232d8 |
children | 4cb232b42168 |
files | NEWS Plugin/WadoRs.cpp |
diffstat | 2 files changed, 76 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Wed Jan 06 17:35:27 2021 +0100 +++ b/NEWS Mon Jan 18 16:46:17 2021 +0100 @@ -1,6 +1,9 @@ Pending changes in the mainline =============================== +* Fix compliance with DICOM >= 2016c: If no "transfer-syntax" is provided in WADO-RS + Retrieve Instance/Series/Study, DICOM shall be transcoded to Little Endian Explicit + Version 1.4 (2020-12-18) ========================
--- a/Plugin/WadoRs.cpp Wed Jan 06 17:35:27 2021 +0100 +++ b/Plugin/WadoRs.cpp Mon Jan 18 16:46:17 2021 +0100 @@ -57,16 +57,41 @@ -static bool AcceptMultipartDicom(bool& transcode, +static void AcceptMultipartDicom(bool& transcode, Orthanc::DicomTransferSyntax& targetSyntax /* only if transcoding */, const OrthancPluginHttpRequest* request) { - transcode = false; + /** + * Up to release 1.4 of the DICOMweb plugin, WADO-RS + * RetrieveInstance, RetrieveSeries and RetrieveStudy did *NOT* + * transcode if no transer syntax was explicitly provided. This was + * because the DICOM standard didn't specify a behavior in this case + * up to DICOM 2016b: + * http://dicom.nema.org/medical/dicom/2016b/output/chtml/part18/sect_6.5.3.html + * + * However, starting with DICOM 2016c, it is explicitly stated that + * "If transfer-syntax is not specified in the dcm-parameters the + * origin server shall use the Explicit VR Little Endian Transfer + * Syntax "1.2.840.10008.1.2.1" for each Instance": + * http://dicom.nema.org/medical/dicom/2016c/output/chtml/part18/sect_6.5.3.html + * + * As a consequence, starting with release 1.5 of the DICOMweb + * plugin, transcoding to "Little Endian Explicit" takes place by + * default. If this transcoding is not desirable, the "Accept" HTTP + * header can be set to + * "multipart/related;type=application/dicom;transfer-syntax=*" (not + * the asterisk "*") in order to prevent transcoding. The same + * convention is used by the Google Cloud Platform: + * https://cloud.google.com/healthcare/docs/dicom + **/ + transcode = true; + targetSyntax = Orthanc::DicomTransferSyntax_LittleEndianExplicit; + std::string accept; if (!OrthancPlugins::LookupHttpHeader(accept, request, "accept")) { - return true; // By default, return "multipart/related; type=application/dicom;" + return; // By default, return "multipart/related; type=application/dicom;" } std::string application; @@ -116,8 +141,6 @@ } } } - - return true; } @@ -274,15 +297,41 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); } - + for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++) { - std::string uri = "/instances/" + instances[i]["ID"].asString() + "/file"; + const std::string uri = "/instances/" + instances[i]["ID"].asString(); + bool transcodeThisInstance; + + std::string sourceTransferSyntax; + if (!transcode) + { + transcodeThisInstance = false; + } + else if (OrthancPlugins::RestApiGetString(sourceTransferSyntax, uri + "/metadata/TransferSyntax", false)) + { + // Avoid transcoding if the source file already uses the expected transfer syntax + Orthanc::DicomTransferSyntax syntax; + if (Orthanc::LookupTransferSyntax(syntax, sourceTransferSyntax)) + { + transcodeThisInstance = (syntax != targetSyntax); + } + else + { + transcodeThisInstance = true; + } + } + else + { + // The transfer syntax of the source file is unknown, transcode it to be sure + transcodeThisInstance = true; + } + OrthancPlugins::MemoryBuffer dicom; - if (dicom.RestApiGet(uri, false)) + if (dicom.RestApiGet(uri + "/file", false)) { - if (transcode) + if (transcodeThisInstance) { std::unique_ptr<OrthancPlugins::DicomInstance> transcoded( OrthancPlugins::DicomInstance::Transcode( @@ -907,18 +956,13 @@ { bool transcode; Orthanc::DicomTransferSyntax targetSyntax; + + AcceptMultipartDicom(transcode, targetSyntax, request); - if (!AcceptMultipartDicom(transcode, targetSyntax, request)) + std::string orthancId, studyInstanceUid; + if (LocateStudy(output, orthancId, studyInstanceUid, request)) { - OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */); - } - else - { - std::string orthancId, studyInstanceUid; - if (LocateStudy(output, orthancId, studyInstanceUid, request)) - { - AnswerListOfDicomInstances(output, Orthanc::ResourceType_Study, orthancId, transcode, targetSyntax); - } + AnswerListOfDicomInstances(output, Orthanc::ResourceType_Study, orthancId, transcode, targetSyntax); } } @@ -930,17 +974,12 @@ bool transcode; Orthanc::DicomTransferSyntax targetSyntax; - if (!AcceptMultipartDicom(transcode, targetSyntax, request)) - { - OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */); - } - else + AcceptMultipartDicom(transcode, targetSyntax, request); + + std::string orthancId, studyInstanceUid, seriesInstanceUid; + if (LocateSeries(output, orthancId, studyInstanceUid, seriesInstanceUid, request)) { - std::string orthancId, studyInstanceUid, seriesInstanceUid; - if (LocateSeries(output, orthancId, studyInstanceUid, seriesInstanceUid, request)) - { - AnswerListOfDicomInstances(output, Orthanc::ResourceType_Series, orthancId, transcode, targetSyntax); - } + AnswerListOfDicomInstances(output, Orthanc::ResourceType_Series, orthancId, transcode, targetSyntax); } } @@ -953,17 +992,12 @@ bool transcode; Orthanc::DicomTransferSyntax targetSyntax; - if (!AcceptMultipartDicom(transcode, targetSyntax, request)) - { - OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */); - } - else + AcceptMultipartDicom(transcode, targetSyntax, request); + + std::string orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid; + if (LocateInstance(output, orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, request)) { - std::string orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid; - if (LocateInstance(output, orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, request)) - { - AnswerListOfDicomInstances(output, Orthanc::ResourceType_Instance, orthancId, transcode, targetSyntax); - } + AnswerListOfDicomInstances(output, Orthanc::ResourceType_Instance, orthancId, transcode, targetSyntax); } }