# HG changeset patch # User Sebastien Jodogne # Date 1589880240 -7200 # Node ID 0b3256c3ee14fe72f52608a57f3b0692e1976dfe # Parent aae045f802f4507425610b687b65c5c735cb80e2 simplified IDicomTranscoder diff -r aae045f802f4 -r 0b3256c3ee14 Core/Compression/HierarchicalZipWriter.h --- a/Core/Compression/HierarchicalZipWriter.h Tue May 19 10:17:06 2020 +0200 +++ b/Core/Compression/HierarchicalZipWriter.h Tue May 19 11:24:00 2020 +0200 @@ -140,7 +140,7 @@ return indexer_.GetCurrentDirectoryPath(); } - void Write(const char* data, size_t length) + void Write(const void* data, size_t length) { writer_.Write(data, length); } diff -r aae045f802f4 -r 0b3256c3ee14 Core/Compression/ZipWriter.cpp --- a/Core/Compression/ZipWriter.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Core/Compression/ZipWriter.cpp Tue May 19 11:24:00 2020 +0200 @@ -227,7 +227,7 @@ } - void ZipWriter::Write(const char* data, size_t length) + void ZipWriter::Write(const void* data, size_t length) { if (!hasFileInZip_) { @@ -236,17 +236,19 @@ const size_t maxBytesInAStep = std::numeric_limits::max(); + const char* p = reinterpret_cast(data); + while (length > 0) { int bytes = static_cast(length <= maxBytesInAStep ? length : maxBytesInAStep); - if (zipWriteInFileInZip(pimpl_->file_, data, bytes)) + if (zipWriteInFileInZip(pimpl_->file_, p, bytes)) { throw OrthancException(ErrorCode_CannotWriteFile, "Cannot write data to ZIP archive: " + path_); } - data += bytes; + p += bytes; length -= bytes; } } diff -r aae045f802f4 -r 0b3256c3ee14 Core/Compression/ZipWriter.h --- a/Core/Compression/ZipWriter.h Tue May 19 10:17:06 2020 +0200 +++ b/Core/Compression/ZipWriter.h Tue May 19 11:24:00 2020 +0200 @@ -101,7 +101,7 @@ void OpenFile(const char* path); - void Write(const char* data, size_t length); + void Write(const void* data, size_t length); void Write(const std::string& data); }; diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomNetworking/DicomStoreUserConnection.cpp --- a/Core/DicomNetworking/DicomStoreUserConnection.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomNetworking/DicomStoreUserConnection.cpp Tue May 19 11:24:00 2020 +0200 @@ -491,40 +491,34 @@ uncompressedSyntaxes.insert(DicomTransferSyntax_BigEndianExplicit); } - std::unique_ptr transcoded( - transcoder.TranscodeToParsed(*dicom, buffer, size, uncompressedSyntaxes, false)); - - // WARNING: Below this point, "transcoded->GetDicom()" is possibly - // a reference to "*dicom", if the DCMTK transcoder was used + IDicomTranscoder::DicomImage source; + source.AcquireParsed(dicom.release()); + source.SetExternalBuffer(buffer, size); - if (transcoded.get() == NULL || - transcoded->GetDicom().getDataset() == NULL) + IDicomTranscoder::DicomImage transcoded; + bool hasSopInstanceUidChanged; + if (transcoder.Transcode(transcoded, hasSopInstanceUidChanged, source, uncompressedSyntaxes, false)) { - throw OrthancException( - ErrorCode_NotImplemented, - "Cannot transcode from \"" + std::string(GetTransferSyntaxUid(inputSyntax)) + - "\" 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->GetDicom()) || - accepted.find(transcodedSyntax) == accepted.end()) + if (hasSopInstanceUidChanged) { - throw OrthancException(ErrorCode_InternalError); + throw OrthancException(ErrorCode_Plugin, "The transcoder has changed the SOP " + "instance UID while transcoding to an uncompressed transfer syntax"); } else { - Store(sopClassUid, sopInstanceUid, transcoded->GetDicom(), - hasMoveOriginator, moveOriginatorAET, moveOriginatorID); + DicomTransferSyntax transcodedSyntax; + + // Sanity check + if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, transcoded.GetParsed()) || + accepted.find(transcodedSyntax) == accepted.end()) + { + throw OrthancException(ErrorCode_InternalError); + } + else + { + Store(sopClassUid, sopInstanceUid, transcoded.GetParsed(), + hasMoveOriginator, moveOriginatorAET, moveOriginatorID); + } } } } diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/DcmtkTranscoder.cpp --- a/Core/DicomParsing/DcmtkTranscoder.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/DcmtkTranscoder.cpp Tue May 19 11:24:00 2020 +0200 @@ -328,78 +328,6 @@ } - - bool DcmtkTranscoder::TranscodeParsedToBuffer( - std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - std::set tmp; - tmp.insert(targetSyntax); - - if (InplaceTranscode(hasSopInstanceUidChanged, dicom, tmp, allowNewSopInstanceUid)) - { - DicomTransferSyntax targetSyntax2; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax2, dicom) && - targetSyntax == targetSyntax2 && - dicom.getDataset() != NULL) - { - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom.getDataset()); - return true; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - return false; - } - } - - - IDicomTranscoder::TranscodedDicom* DcmtkTranscoder::TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& 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; - } - } - - bool DcmtkTranscoder::Transcode(DicomImage& target, bool& hasSopInstanceUidChanged /* out */, DicomImage& source /* in, "GetParsed()" possibly modified */, diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/DcmtkTranscoder.h --- a/Core/DicomParsing/DcmtkTranscoder.h Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/DcmtkTranscoder.h Tue May 19 11:24:00 2020 +0200 @@ -50,6 +50,11 @@ private: unsigned int lossyQuality_; + bool InplaceTranscode(bool& hasSopInstanceUidChanged /* out */, + DcmFileFormat& dicom, + const std::set& allowedSyntaxes, + bool allowNewSopInstanceUid); + public: DcmtkTranscoder() : lossyQuality_(90) @@ -63,26 +68,8 @@ return lossyQuality_; } - bool InplaceTranscode(bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid); - static bool IsSupported(DicomTransferSyntax syntax); - virtual bool TranscodeParsedToBuffer(std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - - virtual TranscodedDicom* TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - virtual bool Transcode(DicomImage& target, bool& hasSopInstanceUidChanged /* out */, DicomImage& source /* in, "GetParsed()" possibly modified */, diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/IDicomTranscoder.cpp --- a/Core/DicomParsing/IDicomTranscoder.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/IDicomTranscoder.cpp Tue May 19 11:24:00 2020 +0200 @@ -44,28 +44,50 @@ { void IDicomTranscoder::DicomImage::Parse() { - if (parsed_.get() != NULL || - buffer_.get() == NULL) + if (parsed_.get() != NULL) { + // Already parsed throw OrthancException(ErrorCode_BadSequenceOfCalls); } - else + else if (buffer_.get() != NULL) { - parsed_.reset(FromDcmtkBridge::LoadFromMemoryBuffer( - buffer_->empty() ? NULL : buffer_->c_str(), buffer_->size())); - + if (isExternalBuffer_) + { + throw OrthancException(ErrorCode_InternalError); + } + else + { + parsed_.reset(FromDcmtkBridge::LoadFromMemoryBuffer( + buffer_->empty() ? NULL : buffer_->c_str(), buffer_->size())); + + if (parsed_.get() == NULL) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + } + else if (isExternalBuffer_) + { + parsed_.reset(FromDcmtkBridge::LoadFromMemoryBuffer(externalBuffer_, externalSize_)); + if (parsed_.get() == NULL) { throw OrthancException(ErrorCode_BadFileFormat); } } + else + { + // No buffer is available + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } } void IDicomTranscoder::DicomImage::Serialize() { if (parsed_.get() == NULL || - buffer_.get() != NULL) + buffer_.get() != NULL || + isExternalBuffer_) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } @@ -81,10 +103,17 @@ } + IDicomTranscoder::DicomImage::DicomImage() : + isExternalBuffer_(false) + { + } + + void IDicomTranscoder::DicomImage::Clear() { parsed_.reset(NULL); buffer_.reset(NULL); + isExternalBuffer_ = false; } @@ -100,14 +129,14 @@ { throw OrthancException(ErrorCode_NullPointer); } + else if (parsed->getDataset() == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } else if (parsed_.get() != NULL) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } - else if (parsed->getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } else { parsed_.reset(parsed); @@ -123,7 +152,8 @@ void IDicomTranscoder::DicomImage::AcquireBuffer(std::string& buffer /* will be swapped */) { - if (buffer_.get() != NULL) + if (buffer_.get() != NULL || + isExternalBuffer_) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } @@ -137,36 +167,69 @@ void IDicomTranscoder::DicomImage::AcquireBuffer(DicomImage& other) { - if (buffer_.get() != NULL) + if (buffer_.get() != NULL || + isExternalBuffer_) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } - else if (other.buffer_.get() == NULL) + else if (other.isExternalBuffer_) { - buffer_.reset(NULL); + assert(other.buffer_.get() == NULL); + isExternalBuffer_ = true; + externalBuffer_ = other.externalBuffer_; + externalSize_ = other.externalSize_; + } + else if (other.buffer_.get() != NULL) + { + buffer_.reset(other.buffer_.release()); } else { - buffer_.reset(other.buffer_.release()); + buffer_.reset(NULL); } } + void IDicomTranscoder::DicomImage::SetExternalBuffer(const void* buffer, + size_t size) + { + if (buffer_.get() != NULL || + isExternalBuffer_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + isExternalBuffer_ = true; + externalBuffer_ = buffer; + externalSize_ = size; + } + } + + + void IDicomTranscoder::DicomImage::SetExternalBuffer(const std::string& buffer) + { + SetExternalBuffer(buffer.empty() ? NULL : buffer.c_str(), buffer.size()); + } + + DcmFileFormat& IDicomTranscoder::DicomImage::GetParsed() { if (parsed_.get() != NULL) { return *parsed_; } - else if (buffer_.get() != NULL) + else if (buffer_.get() != NULL || + isExternalBuffer_) { Parse(); return *parsed_; } else { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "AcquireParsed() or AcquireBuffer() should have been called"); + throw OrthancException( + ErrorCode_BadSequenceOfCalls, + "AcquireParsed(), AcquireBuffer() or SetExternalBuffer() should have been called"); } } @@ -178,7 +241,8 @@ buffer_.reset(NULL); return parsed_.release(); } - else if (buffer_.get() != NULL) + else if (buffer_.get() != NULL || + isExternalBuffer_) { Parse(); buffer_.reset(NULL); @@ -186,102 +250,55 @@ } else { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "AcquireParsed() or AcquireBuffer() should have been called"); + throw OrthancException( + ErrorCode_BadSequenceOfCalls, + "AcquireParsed(), AcquireBuffer() or SetExternalBuffer() should have been called"); } } + + ParsedDicomFile* IDicomTranscoder::DicomImage::ReleaseAsParsedDicomFile() + { + return ParsedDicomFile::AcquireDcmtkObject(ReleaseParsed()); + } + const void* IDicomTranscoder::DicomImage::GetBufferData() { - if (buffer_.get() == NULL) + if (isExternalBuffer_) { - Serialize(); + assert(buffer_.get() == NULL); + return externalBuffer_; } + else + { + if (buffer_.get() == NULL) + { + Serialize(); + } - assert(buffer_.get() != NULL); - return buffer_->empty() ? NULL : buffer_->c_str(); + assert(buffer_.get() != NULL); + return buffer_->empty() ? NULL : buffer_->c_str(); + } } size_t IDicomTranscoder::DicomImage::GetBufferSize() { - if (buffer_.get() == NULL) + if (isExternalBuffer_) { - Serialize(); - } - - assert(buffer_.get() != NULL); - return buffer_->size(); - } - - - IDicomTranscoder::TranscodedDicom::TranscodedDicom(bool hasSopInstanceUidChanged) : - external_(NULL), - hasSopInstanceUidChanged_(hasSopInstanceUidChanged) - { - } - - - IDicomTranscoder::TranscodedDicom* - IDicomTranscoder::TranscodedDicom::CreateFromExternal(DcmFileFormat& dicom, - bool hasSopInstanceUidChanged) - { - std::unique_ptr 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); + assert(buffer_.get() == NULL); + return externalSize_; } else - { - std::unique_ptr transcoded(new TranscodedDicom(hasSopInstanceUidChanged)); - transcoded->internal_.reset(dicom); - return transcoded.release(); + { + if (buffer_.get() == NULL) + { + Serialize(); + } + + assert(buffer_.get() != NULL); + return buffer_->size(); } } - - - DcmFileFormat& IDicomTranscoder::TranscodedDicom::GetDicom() const - { - if (internal_.get() != NULL) - { - return *internal_.get(); - } - else if (external_ != NULL) - { - return *external_; - } - else - { - // Probably results from a call to "ReleaseDicom()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - DcmFileFormat* IDicomTranscoder::TranscodedDicom::ReleaseDicom() - { - if (internal_.get() != NULL) - { - return internal_.release(); - } - else if (external_ != NULL) - { - return new DcmFileFormat(*external_); // Clone - } - else - { - // Probably results from a call to "ReleaseDicom()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } } diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/IDicomTranscoder.h --- a/Core/DicomParsing/IDicomTranscoder.h Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/IDicomTranscoder.h Tue May 19 11:24:00 2020 +0200 @@ -58,6 +58,9 @@ private: std::unique_ptr parsed_; std::unique_ptr buffer_; + bool isExternalBuffer_; + const void* externalBuffer_; + size_t externalSize_; void Parse(); @@ -66,6 +69,8 @@ DcmFileFormat* ReleaseParsed(); public: + DicomImage(); + void Clear(); // Calling this method will invalidate the "ParsedDicomFile" object @@ -79,8 +84,15 @@ void AcquireBuffer(DicomImage& other); + void SetExternalBuffer(const void* buffer, + size_t size); + + void SetExternalBuffer(const std::string& buffer); + DcmFileFormat& GetParsed(); + ParsedDicomFile* ReleaseAsParsedDicomFile(); + const void* GetBufferData(); size_t GetBufferSize(); @@ -97,54 +109,5 @@ DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set& allowedSyntaxes, bool allowNewSopInstanceUid) = 0; - - - - virtual bool TranscodeParsedToBuffer(std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) = 0; - - - class TranscodedDicom : public boost::noncopyable - { - private: - std::unique_ptr 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; - - DcmFileFormat* ReleaseDicom(); - }; - - /** - * Transcoding flavor that creates a new parsed DICOM file. A - * "std::set<>" is used to give the possible plugin the - * possibility to do a single parsing for all the possible - * transfer syntaxes. This flavor is used by C-STORE. - **/ - virtual TranscodedDicom* TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; }; } diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/MemoryBufferTranscoder.cpp --- a/Core/DicomParsing/MemoryBufferTranscoder.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/MemoryBufferTranscoder.cpp Tue May 19 11:24:00 2020 +0200 @@ -66,65 +66,6 @@ } - bool MemoryBufferTranscoder::TranscodeParsedToBuffer( - std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - 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(); - - std::set allowedSyntaxes; - allowedSyntaxes.insert(targetSyntax); - - if (TranscodeBuffer(target, hasSopInstanceUidChanged, - data, source.size(), allowedSyntaxes, allowNewSopInstanceUid)) - { - CheckTargetSyntax(target, allowedSyntaxes); - return true; - } - else - { - return false; - } - } - - - IDicomTranscoder::TranscodedDicom* MemoryBufferTranscoder::TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - bool hasSopInstanceUidChanged; - - std::string target; - if (TranscodeBuffer(target, hasSopInstanceUidChanged, - buffer, size, allowedSyntaxes, allowNewSopInstanceUid)) - { - CheckTargetSyntax(target, allowedSyntaxes); - - const void* data = target.empty() ? NULL : target.c_str(); - return IDicomTranscoder::TranscodedDicom::CreateFromInternal( - FromDcmtkBridge::LoadFromMemoryBuffer(data, target.size()), hasSopInstanceUidChanged); - } - else - { - return NULL; - } - } - - bool MemoryBufferTranscoder::Transcode(DicomImage& target, bool& hasSopInstanceUidChanged /* out */, DicomImage& source, diff -r aae045f802f4 -r 0b3256c3ee14 Core/DicomParsing/MemoryBufferTranscoder.h --- a/Core/DicomParsing/MemoryBufferTranscoder.h Tue May 19 10:17:06 2020 +0200 +++ b/Core/DicomParsing/MemoryBufferTranscoder.h Tue May 19 11:24:00 2020 +0200 @@ -49,19 +49,6 @@ bool allowNewSopInstanceUid) = 0; public: - virtual bool TranscodeParsedToBuffer(std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - - virtual TranscodedDicom* TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - virtual bool Transcode(DicomImage& target /* out */, bool& hasSopInstanceUidChanged /* out */, DicomImage& source, diff -r aae045f802f4 -r 0b3256c3ee14 OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Tue May 19 10:17:06 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Tue May 19 11:24:00 2020 +0200 @@ -130,13 +130,19 @@ if (transcode) { - std::string transcoded; + IDicomTranscoder::DicomImage source; + source.AcquireParsed(*modified); // "modified" is invalid below this point + + IDicomTranscoder::DicomImage transcoded; bool hasSopInstanceUidChanged; - if (context.TranscodeParsedToBuffer(transcoded, hasSopInstanceUidChanged, - modified->GetDcmtkObject(), targetSyntax, true)) + std::set s; + s.insert(targetSyntax); + + if (context.Transcode(transcoded, hasSopInstanceUidChanged, source, s, true)) { - call.GetOutput().AnswerBuffer(transcoded, MimeType_Dicom); + call.GetOutput().AnswerBuffer(transcoded.GetBufferData(), + transcoded.GetBufferSize(), MimeType_Dicom); } else { diff -r aae045f802f4 -r 0b3256c3ee14 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Tue May 19 10:17:06 2020 +0200 +++ b/OrthancServer/ServerContext.cpp Tue May 19 11:24:00 2020 +0200 @@ -551,7 +551,7 @@ else { // Automated transcoding of incoming DICOM files - + DicomTransferSyntax sourceSyntax; if (!FromDcmtkBridge::LookupOrthancTransferSyntax( sourceSyntax, dicom.GetParsedDicomFile().GetDcmtkObject()) || @@ -565,21 +565,16 @@ std::set syntaxes; syntaxes.insert(ingestTransferSyntax_); - std::unique_ptr transcoded( - TranscodeToParsed(dicom.GetParsedDicomFile().GetDcmtkObject(), - dicom.GetBufferData(), dicom.GetBufferSize(), - syntaxes, true /* allow new SOP instance UID */)); - - if (transcoded.get() == NULL) + IDicomTranscoder::DicomImage source; + source.SetExternalBuffer(dicom.GetBufferData(), dicom.GetBufferSize()); + + IDicomTranscoder::DicomImage transcoded; + bool hasSopInstanceUidChanged; + if (Transcode(transcoded, hasSopInstanceUidChanged, + source, syntaxes, true /* allow new SOP instance UID */)) { - // Cannot transcode => store the original file - return StoreAfterTranscoding(resultPublicId, dicom, mode); - } - else - { - std::unique_ptr tmp( - ParsedDicomFile::AcquireDcmtkObject(transcoded->ReleaseDicom())); - + std::unique_ptr tmp(transcoded.ReleaseAsParsedDicomFile()); + DicomInstanceToStore toStore; toStore.SetParsedDicomFile(*tmp); toStore.SetOrigin(dicom.GetOrigin()); @@ -589,6 +584,11 @@ return ok; } + else + { + // Cannot transcode => store the original file + return StoreAfterTranscoding(resultPublicId, dicom, mode); + } } } } @@ -1322,99 +1322,6 @@ } - bool ServerContext::TranscodeParsedToBuffer(std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) - { - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) - { - if (dcmtkTranscoder_->TranscodeParsedToBuffer(target, hasSopInstanceUidChanged, dicom, - targetSyntax, allowNewSopInstanceUid)) - { - return true; - } - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins() && - GetPlugins().HasCustomTranscoder()) - { - if (GetPlugins().TranscodeParsedToBuffer(target, hasSopInstanceUidChanged, dicom, - targetSyntax, allowNewSopInstanceUid)) - { - return true; - } - else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - LOG(INFO) << "The installed transcoding plugins cannot handle an image, " - << "fallback to the built-in DCMTK transcoder"; - } - } -#endif - - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - return dcmtkTranscoder_->TranscodeParsedToBuffer(target, hasSopInstanceUidChanged, dicom, - targetSyntax, allowNewSopInstanceUid); - } - else - { - return false; - } - } - - - IDicomTranscoder::TranscodedDicom* - ServerContext::TranscodeToParsed(DcmFileFormat& dicom, - const void* buffer, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) - { - std::unique_ptr transcoded( - dcmtkTranscoder_->TranscodeToParsed(dicom, buffer, size, allowedSyntaxes, - allowNewSopInstanceUid)); - if (transcoded.get() != NULL) - { - return transcoded.release(); - } - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins() && - GetPlugins().HasCustomTranscoder()) - { - std::unique_ptr transcoded( - GetPlugins().TranscodeToParsed(dicom, buffer, size, allowedSyntaxes, allowNewSopInstanceUid)); - - if (transcoded.get() != NULL) - { - return transcoded.release(); - } - else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - LOG(INFO) << "The installed transcoding plugins cannot handle an image, " - << "fallback to the built-in DCMTK transcoder"; - } - } -#endif - - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - return dcmtkTranscoder_->TranscodeToParsed( - dicom, buffer, size, allowedSyntaxes, allowNewSopInstanceUid); - } - else - { - return NULL; - } - } - - bool ServerContext::Transcode(DicomImage& target, bool& hasSopInstanceUidChanged /* out */, DicomImage& source /* in, "GetParsed()" possibly modified */, diff -r aae045f802f4 -r 0b3256c3ee14 OrthancServer/ServerContext.h --- a/OrthancServer/ServerContext.h Tue May 19 10:17:06 2020 +0200 +++ b/OrthancServer/ServerContext.h Tue May 19 11:24:00 2020 +0200 @@ -479,21 +479,6 @@ // This method can be used even if the global option // "TranscodeDicomProtocol" is set to "false" - virtual bool TranscodeParsedToBuffer(std::string& target /* out */, - bool& hasSopInstanceUidChanged /* out */, - DcmFileFormat& dicom /* in, possibly modified */, - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - - // This method can be used even if the global option - // "TranscodeDicomProtocol" is set to "false" - virtual IDicomTranscoder::TranscodedDicom* TranscodeToParsed( - DcmFileFormat& dicom /* in, possibly modified */, - const void* buffer /* in, same DICOM file as "dicom" */, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - virtual bool Transcode(DicomImage& target, bool& hasSopInstanceUidChanged /* out */, DicomImage& source /* in, "GetParsed()" possibly modified */, diff -r aae045f802f4 -r 0b3256c3ee14 OrthancServer/ServerJobs/ArchiveJob.cpp --- a/OrthancServer/ServerJobs/ArchiveJob.cpp Tue May 19 10:17:06 2020 +0200 +++ b/OrthancServer/ServerJobs/ArchiveJob.cpp Tue May 19 11:24:00 2020 +0200 @@ -442,27 +442,19 @@ // New in Orthanc 1.7.0 std::set syntaxes; syntaxes.insert(transferSyntax); - - parsed.reset(new ParsedDicomFile(content)); - const char* data = content.empty() ? NULL : content.c_str(); - - std::unique_ptr transcodedDicom( - context.TranscodeToParsed(parsed->GetDcmtkObject(), data, content.size(), - syntaxes, true /* allow new SOP instance UID */)); + + IDicomTranscoder::DicomImage source, transcoded; + source.SetExternalBuffer(content); - if (transcodedDicom.get() != NULL && - transcodedDicom->GetDicom().getDataset() != NULL) + bool hasSopInstanceChanged; + if (context.Transcode(transcoded, hasSopInstanceChanged, source, + syntaxes, true /* allow new SOP instance UID */)) { - std::string transcoded; - FromDcmtkBridge::SaveToMemoryBuffer( - transcoded, *transcodedDicom->GetDicom().getDataset()); - - writer.Write(transcoded); + writer.Write(transcoded.GetBufferData(), transcoded.GetBufferSize()); if (dicomDir != NULL) { - std::unique_ptr tmp( - ParsedDicomFile::AcquireDcmtkObject(transcodedDicom->ReleaseDicom())); + std::unique_ptr tmp(transcoded.ReleaseAsParsedDicomFile()); dicomDir->Add(dicomDirFolder, filename_, *tmp); } diff -r aae045f802f4 -r 0b3256c3ee14 OrthancServer/ServerJobs/ResourceModificationJob.cpp --- a/OrthancServer/ServerJobs/ResourceModificationJob.cpp Tue May 19 10:17:06 2020 +0200 +++ b/OrthancServer/ServerJobs/ResourceModificationJob.cpp Tue May 19 11:24:00 2020 +0200 @@ -177,19 +177,20 @@ { std::set syntaxes; syntaxes.insert(transferSyntax_); + + IDicomTranscoder::DicomImage source; + source.AcquireParsed(*modified); // "modified" is invalid below this point - std::string s; - modified->SaveToMemoryBuffer(s); // TODO - AVOID THIS SERIALIZATION IF NO PLUGIN - - std::unique_ptr transcoded; - transcoded.reset(GetContext().TranscodeToParsed(modified->GetDcmtkObject(), s.empty() ? NULL : s.c_str(), s.size(), syntaxes, true)); - if (transcoded.get() == NULL) + IDicomTranscoder::DicomImage transcoded; + bool hasSopInstanceUidChanged; + if (GetContext().Transcode(transcoded, hasSopInstanceUidChanged, source, syntaxes, true)) { - LOG(WARNING) << "Cannot transcode instance, keeping original transfer syntax: " << instance; + modified.reset(transcoded.ReleaseAsParsedDicomFile()); } else { - modified.reset(ParsedDicomFile::AcquireDcmtkObject(transcoded->ReleaseDicom())); + LOG(WARNING) << "Cannot transcode instance, keeping original transfer syntax: " << instance; + modified.reset(source.ReleaseAsParsedDicomFile()); } } diff -r aae045f802f4 -r 0b3256c3ee14 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Tue May 19 10:17:06 2020 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Tue May 19 11:24:00 2020 +0200 @@ -1896,8 +1896,8 @@ DicomInstanceToStore instance_; public: - DicomInstanceFromTranscoded(IDicomTranscoder::TranscodedDicom& transcoded) : - parsed_(ParsedDicomFile::AcquireDcmtkObject(transcoded.ReleaseDicom())) + DicomInstanceFromTranscoded(IDicomTranscoder::DicomImage& transcoded) : + parsed_(transcoded.ReleaseAsParsedDicomFile()) { instance_.SetParsedDicomFile(*parsed_); instance_.SetOrigin(DicomInstanceOrigin::FromPlugins()); @@ -4369,29 +4369,30 @@ } else { - ParsedDicomFile dicom(p.buffer, p.size); - std::set syntaxes; syntaxes.insert(transferSyntax); - - std::unique_ptr transcoded; + + IDicomTranscoder::DicomImage source; + source.SetExternalBuffer(p.buffer, p.size); + + IDicomTranscoder::DicomImage transcoded; + bool success, hasSopInstanceChanged; { PImpl::ServerContextLock lock(*pimpl_); - transcoded.reset(lock.GetContext().TranscodeToParsed( - dicom.GetDcmtkObject(), p.buffer, p.size, - syntaxes, true /* allow new sop */)); + success = lock.GetContext().Transcode(transcoded, hasSopInstanceChanged, source, + syntaxes, true /* allow new sop */); } - if (transcoded.get() == NULL) + if (success) { - throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode image"); + *(p.target) = reinterpret_cast( + new DicomInstanceFromTranscoded(transcoded)); + return true; } else { - *(p.target) = reinterpret_cast( - new DicomInstanceFromTranscoded(*transcoded)); - return true; + throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode image"); } } } diff -r aae045f802f4 -r 0b3256c3ee14 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Tue May 19 10:17:06 2020 +0200 +++ b/UnitTestsSources/FromDcmtkTests.cpp Tue May 19 11:24:00 2020 +0200 @@ -1987,13 +1987,18 @@ for (int i = 0; i <= DicomTransferSyntax_XML; i++) { DicomTransferSyntax a = (DicomTransferSyntax) i; + + std::set s; + s.insert(a); std::string t; bool hasSopInstanceUidChanged; - std::unique_ptr cloned(dynamic_cast(toto->clone())); - if (!transcoder.TranscodeParsedToBuffer(t, hasSopInstanceUidChanged, *cloned, a, true)) + IDicomTranscoder::DicomImage source, target; + source.AcquireParsed(dynamic_cast(toto->clone())); + + if (!transcoder.Transcode(target, hasSopInstanceUidChanged, source, s, true)) { printf("**************** CANNOT: [%s] => [%s]\n", GetTransferSyntaxUid(sourceSyntax), GetTransferSyntaxUid(a)); @@ -2001,7 +2006,7 @@ else { DicomTransferSyntax targetSyntax; - ASSERT_TRUE(FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, *cloned)); + ASSERT_TRUE(FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, target.GetParsed())); ASSERT_EQ(targetSyntax, a); bool lossy = (a == DicomTransferSyntax_JPEGProcess1 ||