Mercurial > hg > orthanc
changeset 3906:f0dd5ded8927 transcoding
refactoring using IDicomTranscoder::TranscodedDicom
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 08 May 2020 11:16:16 +0200 |
parents | 061f3d031b5d |
children | 1555feda39e2 |
files | Core/DicomNetworking/DicomStoreUserConnection.cpp Core/DicomParsing/DcmtkTranscoder.cpp Core/DicomParsing/DcmtkTranscoder.h Core/DicomParsing/IDicomTranscoder.cpp Core/DicomParsing/IDicomTranscoder.h Core/DicomParsing/MemoryBufferTranscoder.cpp Core/DicomParsing/MemoryBufferTranscoder.h OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Resources/CMake/OrthancFrameworkConfiguration.cmake |
diffstat | 13 files changed, 358 insertions(+), 68 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/DicomNetworking/DicomStoreUserConnection.cpp Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomNetworking/DicomStoreUserConnection.cpp Fri May 08 11:16:16 2020 +0200 @@ -491,35 +491,14 @@ uncompressedSyntaxes.insert(DicomTransferSyntax_BigEndianExplicit); } - std::unique_ptr<DcmFileFormat> transcoded; + std::unique_ptr<IDicomTranscoder::TranscodedDicom> transcoded( + transcoder.TranscodeToParsed2(*dicom, buffer, size, uncompressedSyntaxes, false)); - bool hasSopInstanceUidChanged; + // WARNING: Below this point, "transcoded->GetDicom()" is possibly + // a reference to "*dicom", if the DCMTK transcoder was used - if (transcoder.HasInplaceTranscode(inputSyntax, uncompressedSyntaxes)) - { - if (transcoder.InplaceTranscode(hasSopInstanceUidChanged, *dicom, uncompressedSyntaxes, false)) - { - // In-place transcoding is supported and has succeeded - transcoded.reset(dicom.release()); - } - } - else - { - transcoded.reset(transcoder.TranscodeToParsed(hasSopInstanceUidChanged, buffer, size, uncompressedSyntaxes, false)); - } - - if (hasSopInstanceUidChanged) - { - throw OrthancException(ErrorCode_Plugin, "The transcoder has changed the SOP " - "instance UID while transcoding to an uncompressed transfer syntax"); - } - - // WARNING: The "dicom" variable must not be used below this - // point. The "sopInstanceUid" might also have changed (if - // using lossy compression). - - if (transcoded == NULL || - transcoded->getDataset() == NULL) + if (transcoded.get() == NULL || + transcoded->GetDicom().getDataset() == NULL) { throw OrthancException( ErrorCode_NotImplemented, @@ -527,19 +506,24 @@ "\" to an uncompressed syntax for modality: " + GetParameters().GetRemoteModality().GetApplicationEntityTitle()); } + else if (transcoded->HasSopInstanceUidChanged()) + { + throw OrthancException(ErrorCode_Plugin, "The transcoder has changed the SOP " + "instance UID while transcoding to an uncompressed transfer syntax"); + } else { DicomTransferSyntax transcodedSyntax; // Sanity check - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, *transcoded) || + if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, transcoded->GetDicom()) || accepted.find(transcodedSyntax) == accepted.end()) { throw OrthancException(ErrorCode_InternalError); } else { - Store(sopClassUid, sopInstanceUid, *transcoded, + Store(sopClassUid, sopInstanceUid, transcoded->GetDicom(), hasMoveOriginator, moveOriginatorAET, moveOriginatorID); } }
--- a/Core/DicomParsing/DcmtkTranscoder.cpp Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomParsing/DcmtkTranscoder.cpp Fri May 08 11:16:16 2020 +0200 @@ -371,4 +371,80 @@ return false; } + + + + bool DcmtkTranscoder::TranscodeParsedToBuffer( + std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom /* in, possibly modified */, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) + { + if (dicom.getDataset() == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + + if (!FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, dicom)) + { + LOG(ERROR) << "Unsupport transfer syntax for transcoding"; + return false; + } + + if (InplaceTranscode(hasSopInstanceUidChanged, dicom, allowedSyntaxes, allowNewSopInstanceUid)) + { + if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, dicom) && + allowedSyntaxes.find(targetSyntax) != allowedSyntaxes.end() && + dicom.getDataset() != NULL) + { + FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom.getDataset()); + return true; + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + } + else + { + return false; + } + } + + + IDicomTranscoder::TranscodedDicom* DcmtkTranscoder::TranscodeToParsed2( + DcmFileFormat& dicom /* in, possibly modified */, + const void* buffer /* in, same DICOM file as "dicom" */, + size_t size, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) + { + DicomTransferSyntax sourceSyntax; + if (!FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, dicom)) + { + LOG(ERROR) << "Unsupport transfer syntax for transcoding"; + return NULL; + } + + bool hasSopInstanceUidChanged; + + if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end()) + { + // No transcoding is needed + return TranscodedDicom::CreateFromExternal(dicom, false /* no change in UID */); + } + else if (InplaceTranscode(hasSopInstanceUidChanged, dicom, + allowedSyntaxes, allowNewSopInstanceUid)) + { + return TranscodedDicom::CreateFromExternal(dicom, hasSopInstanceUidChanged); + } + else + { + // Cannot transcode + return NULL; + } + } }
--- a/Core/DicomParsing/DcmtkTranscoder.h Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomParsing/DcmtkTranscoder.h Fri May 08 11:16:16 2020 +0200 @@ -88,5 +88,21 @@ bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; static bool IsSupported(DicomTransferSyntax syntax); + + + virtual bool TranscodeParsedToBuffer(std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom /* in, possibly modified */, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; + + virtual TranscodedDicom* TranscodeToParsed2( + DcmFileFormat& dicom /* in, possibly modified */, + const void* buffer /* in, same DICOM file as "dicom" */, + size_t size, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/DicomParsing/IDicomTranscoder.cpp Fri May 08 11:16:16 2020 +0200 @@ -0,0 +1,92 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "IDicomTranscoder.h" + +#include "../OrthancException.h" + +#include <dcmtk/dcmdata/dcfilefo.h> + +namespace Orthanc +{ + IDicomTranscoder::TranscodedDicom::TranscodedDicom(bool hasSopInstanceUidChanged) : + external_(NULL), + hasSopInstanceUidChanged_(hasSopInstanceUidChanged) + { + } + + + IDicomTranscoder::TranscodedDicom* + IDicomTranscoder::TranscodedDicom::CreateFromExternal(DcmFileFormat& dicom, + bool hasSopInstanceUidChanged) + { + std::unique_ptr<TranscodedDicom> transcoded(new TranscodedDicom(hasSopInstanceUidChanged)); + transcoded->external_ = &dicom; + return transcoded.release(); + } + + + IDicomTranscoder::TranscodedDicom* + IDicomTranscoder::TranscodedDicom::CreateFromInternal(DcmFileFormat* dicom, + bool hasSopInstanceUidChanged) + { + if (dicom == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + std::unique_ptr<TranscodedDicom> transcoded(new TranscodedDicom(hasSopInstanceUidChanged)); + transcoded->internal_.reset(dicom); + return transcoded.release(); + } + } + + + DcmFileFormat& IDicomTranscoder::TranscodedDicom::GetDicom() const + { + if (internal_.get() != NULL) + { + return *internal_.get(); + } + else if (external_ != NULL) + { + return *external_; + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + } +}
--- a/Core/DicomParsing/IDicomTranscoder.h Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomParsing/IDicomTranscoder.h Fri May 08 11:16:16 2020 +0200 @@ -33,6 +33,7 @@ #pragma once +#include "../Compatibility.h" #include "../Enumerations.h" #include <boost/noncopyable.hpp> @@ -83,5 +84,51 @@ DcmFileFormat& dicom, const std::set<DicomTransferSyntax>& allowedSyntaxes, bool allowNewSopInstanceUid) = 0; + + + + virtual bool TranscodeParsedToBuffer(std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom /* in, possibly modified */, + const std::set<DicomTransferSyntax>& allowedSyntaxes, // TODO => is a set needed? + bool allowNewSopInstanceUid) = 0; + + + class TranscodedDicom : public boost::noncopyable + { + private: + std::unique_ptr<DcmFileFormat> internal_; + DcmFileFormat* external_; + bool hasSopInstanceUidChanged_; + + TranscodedDicom(bool hasSopInstanceUidChanged); + + public: + static TranscodedDicom* CreateFromExternal(DcmFileFormat& dicom, + bool hasSopInstanceUidChanged); + + static TranscodedDicom* CreateFromInternal(DcmFileFormat* dicom, + bool hasSopInstanceUidChanged); + + // TODO - Is this information used somewhere? + bool HasSopInstanceUidChanged() const + { + return hasSopInstanceUidChanged_; + } + + DcmFileFormat& GetDicom() const; + }; + + /** + * This flavor is used by C-STORE. + **/ + virtual TranscodedDicom* TranscodeToParsed2( + DcmFileFormat& dicom /* in, possibly modified */, + const void* buffer /* in, same DICOM file as "dicom" */, + size_t size, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) = 0; }; }
--- a/Core/DicomParsing/MemoryBufferTranscoder.cpp Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomParsing/MemoryBufferTranscoder.cpp Fri May 08 11:16:16 2020 +0200 @@ -81,7 +81,8 @@ } #endif - return Transcode(target, hasSopInstanceUidChanged, buffer, size, + DicomTransferSyntax sourceSyntax, targetSyntax; + return Transcode(target, sourceSyntax, targetSyntax, hasSopInstanceUidChanged, buffer, size, allowedSyntaxes, allowNewSopInstanceUid); } @@ -106,7 +107,9 @@ #endif std::string transcoded; - if (Transcode(transcoded, hasSopInstanceUidChanged, buffer, size, allowedSyntaxes, allowNewSopInstanceUid)) + DicomTransferSyntax sourceSyntax, targetSyntax; + if (Transcode(transcoded, sourceSyntax, targetSyntax, hasSopInstanceUidChanged, + buffer, size, allowedSyntaxes, allowNewSopInstanceUid)) { return FromDcmtkBridge::LoadFromMemoryBuffer( transcoded.empty() ? NULL : transcoded.c_str(), transcoded.size()); @@ -176,4 +179,73 @@ throw OrthancException(ErrorCode_BadSequenceOfCalls); } } + + + + + bool MemoryBufferTranscoder::TranscodeParsedToBuffer( + std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom /* in, possibly modified */, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) + { + if (dicom.getDataset() == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + + std::string source; + FromDcmtkBridge::SaveToMemoryBuffer(source, *dicom.getDataset()); + + const void* data = source.empty() ? NULL : source.c_str(); + + bool success = Transcode(target, sourceSyntax, targetSyntax, hasSopInstanceUidChanged, + data, source.size(), allowedSyntaxes, allowNewSopInstanceUid); + +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + if (useDcmtk_ && + dcmtk_.TranscodeParsedToBuffer( + target, sourceSyntax, targetSyntax,hasSopInstanceUidChanged, + dicom, allowedSyntaxes, allowNewSopInstanceUid)) + { + success = true; + } +#endif + + return success; + } + + + IDicomTranscoder::TranscodedDicom* MemoryBufferTranscoder::TranscodeToParsed2( + DcmFileFormat& dicom /* in, possibly modified */, + const void* buffer /* in, same DICOM file as "dicom" */, + size_t size, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) + { + DicomTransferSyntax sourceSyntax, targetSyntax; + bool hasSopInstanceUidChanged; + + std::string target; + if (Transcode(target, sourceSyntax, targetSyntax, hasSopInstanceUidChanged, + buffer, size, allowedSyntaxes, allowNewSopInstanceUid)) + { + const void* data = target.empty() ? NULL : target.c_str(); + return IDicomTranscoder::TranscodedDicom::CreateFromInternal( + FromDcmtkBridge::LoadFromMemoryBuffer(data, target.size()), hasSopInstanceUidChanged); + } +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + else if (useDcmtk_) + { + return dcmtk_.TranscodeToParsed2(dicom, buffer, size, allowedSyntaxes, allowNewSopInstanceUid); + } +#endif + else + { + return NULL; + } + } }
--- a/Core/DicomParsing/MemoryBufferTranscoder.h Fri May 08 08:27:18 2020 +0200 +++ b/Core/DicomParsing/MemoryBufferTranscoder.h Fri May 08 11:16:16 2020 +0200 @@ -55,6 +55,8 @@ protected: virtual bool Transcode(std::string& target, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, bool& hasSopInstanceUidChanged /* out */, const void* buffer, size_t size, @@ -96,5 +98,22 @@ DcmFileFormat& dicom, const std::set<DicomTransferSyntax>& allowedSyntaxes, bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; + + + + virtual bool TranscodeParsedToBuffer(std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom /* in, possibly modified */, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; + + virtual TranscodedDicom* TranscodeToParsed2( + DcmFileFormat& dicom /* in, possibly modified */, + const void* buffer /* in, same DICOM file as "dicom" */, + size_t size, + const std::set<DicomTransferSyntax>& allowedSyntaxes, + bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 08:27:18 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 11:16:16 2020 +0200 @@ -134,9 +134,11 @@ ts.insert(targetSyntax); std::string transcoded; + DicomTransferSyntax sourceSyntax, targetSyntax; bool hasSopInstanceUidChanged; - if (context.Transcode(transcoded, hasSopInstanceUidChanged, *modified, ts, true)) + if (context.Transcode(transcoded, sourceSyntax, targetSyntax, + hasSopInstanceUidChanged, *modified, ts, true)) { call.GetOutput().AnswerBuffer(transcoded, MimeType_Dicom); }
--- a/OrthancServer/ServerContext.cpp Fri May 08 08:27:18 2020 +0200 +++ b/OrthancServer/ServerContext.cpp Fri May 08 11:16:16 2020 +0200 @@ -1155,19 +1155,14 @@ } - bool ServerContext::Transcode(std::string& target, - bool& hasSopInstanceUidChanged, + bool ServerContext::Transcode(std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, ParsedDicomFile& dicom, // Possibly modified const std::set<DicomTransferSyntax>& allowedSyntaxes, bool allowNewSopInstanceUid) { - DicomTransferSyntax inputSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(inputSyntax, dicom.GetDcmtkObject())) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the source transfer syntax during transcoding"); - } - IDicomTranscoder* transcoder = dcmtkTranscoder_.get(); #if ORTHANC_ENABLE_PLUGINS == 1 @@ -1181,29 +1176,9 @@ { throw OrthancException(ErrorCode_InternalError); } - else if (transcoder->HasInplaceTranscode(inputSyntax, allowedSyntaxes)) - { - if (transcoder->InplaceTranscode(hasSopInstanceUidChanged, dicom.GetDcmtkObject(), - allowedSyntaxes, allowNewSopInstanceUid)) - { - // In-place transcoding is supported and has succeeded - dicom.SaveToMemoryBuffer(target); - return true; - } - else - { - return false; - } - } - else - { - std::string source; - dicom.SaveToMemoryBuffer(source); - - const char* data = source.empty() ? NULL : source.c_str(); - - return transcoder->TranscodeToBuffer( - target, hasSopInstanceUidChanged, data, source.size(), allowedSyntaxes, allowNewSopInstanceUid); - } + + return transcoder->TranscodeParsedToBuffer( + target, sourceSyntax, targetSyntax, hasSopInstanceUidChanged, + dicom.GetDcmtkObject(), allowedSyntaxes, allowNewSopInstanceUid); } }
--- a/OrthancServer/ServerContext.h Fri May 08 08:27:18 2020 +0200 +++ b/OrthancServer/ServerContext.h Fri May 08 11:16:16 2020 +0200 @@ -465,9 +465,11 @@ // This method can be used even if the global option // "TranscodingEnabled" is set to "false" - bool Transcode(std::string& target, - bool& hasSopInstanceUidChanged, - ParsedDicomFile& dicom, // Can possibly be modified + bool Transcode(std::string& target /* out */, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, + bool& hasSopInstanceUidChanged /* out */, + ParsedDicomFile& dicom, // Possibly modified const std::set<DicomTransferSyntax>& allowedSyntaxes, bool allowNewSopInstanceUid); };
--- a/Plugins/Engine/OrthancPlugins.cpp Fri May 08 08:27:18 2020 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Fri May 08 11:16:16 2020 +0200 @@ -4796,6 +4796,8 @@ bool OrthancPlugins::Transcode(std::string& target, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, bool& hasSopInstanceUidChanged /* out */, const void* buffer, size_t size,
--- a/Plugins/Engine/OrthancPlugins.h Fri May 08 08:27:18 2020 +0200 +++ b/Plugins/Engine/OrthancPlugins.h Fri May 08 11:16:16 2020 +0200 @@ -228,6 +228,8 @@ protected: // From "MemoryBufferTranscoder" virtual bool Transcode(std::string& target, + DicomTransferSyntax& sourceSyntax /* out */, + DicomTransferSyntax& targetSyntax /* out */, bool& hasSopInstanceUidChanged /* out */, const void* buffer, size_t size,
--- a/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri May 08 08:27:18 2020 +0200 +++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri May 08 11:16:16 2020 +0200 @@ -503,6 +503,7 @@ add_definitions(-DORTHANC_ENABLE_DCMTK_TRANSCODING=1) list(APPEND ORTHANC_DICOM_SOURCES_INTERNAL ${ORTHANC_ROOT}/Core/DicomParsing/DcmtkTranscoder.cpp + ${ORTHANC_ROOT}/Core/DicomParsing/IDicomTranscoder.cpp ${ORTHANC_ROOT}/Core/DicomParsing/MemoryBufferTranscoder.cpp ) else()