# HG changeset patch # User Sebastien Jodogne # Date 1588958128 -7200 # Node ID 6ddad3e0b569fffbac54733cb23cec225d27f2c9 # Parent 7610af1532c384b803f2c2913ee447fff66559fd transcoding ZIP archive and media diff -r 7610af1532c3 -r 6ddad3e0b569 NEWS --- a/NEWS Fri May 08 13:43:50 2020 +0200 +++ b/NEWS Fri May 08 19:15:28 2020 +0200 @@ -12,7 +12,8 @@ - "/queries/.../answers/../retrieve": "TargetAet" not mandatory anymore (defaults to the local AET) * Changes: - - "/instances/.../modify": New option "Transcode" + - "/instances/.../modify", ".../archive", ".../media", + "/tools/create-media" and "/tools/create-archive": New option "Transcode" - "/ordered-slices": reverted the change introduced in 1.5.8 and go-back to 1.5.7 behaviour. diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 19:15:28 2020 +0200 @@ -134,8 +134,9 @@ DicomTransferSyntax sourceSyntax; bool hasSopInstanceUidChanged; - if (context.Transcode(transcoded, sourceSyntax, hasSopInstanceUidChanged, - *modified, targetSyntax, true)) + if (context.GetTranscoder().TranscodeParsedToBuffer( + transcoded, sourceSyntax, hasSopInstanceUidChanged, + modified->GetDcmtkObject(), targetSyntax, true)) { call.GetOutput().AnswerBuffer(transcoded, MimeType_Dicom); } diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/OrthancRestApi/OrthancRestArchive.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri May 08 19:15:28 2020 +0200 @@ -46,6 +46,7 @@ { static const char* const KEY_RESOURCES = "Resources"; static const char* const KEY_EXTENDED = "Extended"; + static const char* const KEY_TRANSCODE = "Transcode"; static void AddResourcesOfInterestFromArray(ArchiveJob& job, const Json::Value& resources) @@ -98,11 +99,28 @@ } - static void GetJobParameters(bool& synchronous, /* out */ - bool& extended, /* out */ - int& priority, /* out */ - const Json::Value& body, /* in */ - const bool defaultExtended /* in */) + static DicomTransferSyntax GetTransferSyntax(const std::string& value) + { + DicomTransferSyntax syntax; + if (LookupTransferSyntax(syntax, value)) + { + return syntax; + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Unknown transfer syntax: " + value); + } + } + + + static void GetJobParameters(bool& synchronous, /* out */ + bool& extended, /* out */ + bool& transcode, /* out */ + DicomTransferSyntax& syntax, /* out */ + int& priority, /* out */ + const Json::Value& body, /* in */ + const bool defaultExtended /* in */) { synchronous = OrthancRestApi::IsSynchronousJobRequest (true /* synchronous by default */, body); @@ -118,6 +136,17 @@ { extended = defaultExtended; } + + if (body.type() == Json::objectValue && + body.isMember(KEY_TRANSCODE)) + { + transcode = true; + syntax = GetTransferSyntax(SerializationToolbox::ReadString(body, KEY_TRANSCODE)); + } + else + { + transcode = false; + } } @@ -175,12 +204,20 @@ Json::Value body; if (call.ParseJsonRequest(body)) { - bool synchronous, extended; + bool synchronous, extended, transcode; + DicomTransferSyntax transferSyntax; int priority; - GetJobParameters(synchronous, extended, priority, body, DEFAULT_IS_EXTENDED); + GetJobParameters(synchronous, extended, transcode, transferSyntax, + priority, body, DEFAULT_IS_EXTENDED); std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); AddResourcesOfInterest(*job, body); + + if (transcode) + { + job->SetTranscode(transferSyntax); + } + SubmitJob(call.GetOutput(), context, job, priority, synchronous, "Archive.zip"); } else @@ -208,10 +245,16 @@ { extended = false; } - + std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); job->AddResource(id); + static const char* const TRANSCODE = "transcode"; + if (call.HasArgument(TRANSCODE)) + { + job->SetTranscode(GetTransferSyntax(call.GetArgument(TRANSCODE, ""))); + } + SubmitJob(call.GetOutput(), context, job, 0 /* priority */, true /* synchronous */, id + ".zip"); } @@ -228,12 +271,20 @@ Json::Value body; if (call.ParseJsonRequest(body)) { - bool synchronous, extended; + bool synchronous, extended, transcode; + DicomTransferSyntax transferSyntax; int priority; - GetJobParameters(synchronous, extended, priority, body, DEFAULT_IS_EXTENDED); + GetJobParameters(synchronous, extended, transcode, transferSyntax, + priority, body, DEFAULT_IS_EXTENDED); std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); job->AddResource(id); + + if (transcode) + { + job->SetTranscode(transferSyntax); + } + SubmitJob(call.GetOutput(), context, job, priority, synchronous, id + ".zip"); } else diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/ServerContext.cpp Fri May 08 19:15:28 2020 +0200 @@ -506,7 +506,8 @@ DicomInstanceToStore& dicom, StoreInstanceMode mode) { - const DicomTransferSyntax option = DicomTransferSyntax_JPEGProcess1; + //const DicomTransferSyntax option = DicomTransferSyntax_JPEGProcess1; + const DicomTransferSyntax option = DicomTransferSyntax_LittleEndianExplicit; if (1) { @@ -1214,17 +1215,4 @@ hasMoveOriginator, moveOriginatorAet, moveOriginatorId); } } - - - bool ServerContext::Transcode(std::string& target /* out */, - DicomTransferSyntax& sourceSyntax /* out */, - bool& hasSopInstanceUidChanged /* out */, - ParsedDicomFile& dicom, // Possibly modified - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid) - { - return GetTranscoder().TranscodeParsedToBuffer( - target, sourceSyntax, hasSopInstanceUidChanged, - dicom.GetDcmtkObject(), targetSyntax, allowNewSopInstanceUid); - } } diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/ServerContext.h --- a/OrthancServer/ServerContext.h Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/ServerContext.h Fri May 08 19:15:28 2020 +0200 @@ -229,8 +229,6 @@ bool transcodeDicomProtocol_; std::unique_ptr dcmtkTranscoder_; - IDicomTranscoder& GetTranscoder(); - StoreStatus StoreAfterTranscoding(std::string& resultPublicId, DicomInstanceToStore& dicom, StoreInstanceMode mode); @@ -469,13 +467,8 @@ const std::string& moveOriginatorAet, uint16_t moveOriginatorId); - // This method can be used even if the global option + // This accessor can be used even if the global option // "TranscodeDicomProtocol" is set to "false" - bool Transcode(std::string& target /* out */, - DicomTransferSyntax& sourceSyntax /* out */, - bool& hasSopInstanceUidChanged /* out */, - ParsedDicomFile& dicom, // Possibly modified - DicomTransferSyntax targetSyntax, - bool allowNewSopInstanceUid); + IDicomTranscoder& GetTranscoder(); }; } diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/ServerJobs/ArchiveJob.cpp --- a/OrthancServer/ServerJobs/ArchiveJob.cpp Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/ServerJobs/ArchiveJob.cpp Fri May 08 19:15:28 2020 +0200 @@ -37,6 +37,7 @@ #include "../../Core/Cache/SharedArchive.h" #include "../../Core/Compression/HierarchicalZipWriter.h" #include "../../Core/DicomParsing/DicomDirWriter.h" +#include "../../Core/DicomParsing/FromDcmtkBridge.h" #include "../../Core/Logging.h" #include "../../Core/OrthancException.h" #include "../OrthancConfiguration.h" @@ -55,6 +56,7 @@ static const char* const KEY_DESCRIPTION = "Description"; static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; +static const char* const KEY_TRANSCODE = "Transcode"; namespace Orthanc @@ -399,7 +401,9 @@ void Apply(HierarchicalZipWriter& writer, ServerContext& context, DicomDirWriter* dicomDir, - const std::string& dicomDirFolder) const + const std::string& dicomDirFolder, + bool transcode, + DicomTransferSyntax transferSyntax) const { switch (type_) { @@ -426,14 +430,65 @@ } //boost::this_thread::sleep(boost::posix_time::milliseconds(300)); - + writer.OpenFile(filename_.c_str()); - writer.Write(content); + + bool transcodeSuccess = false; + + std::unique_ptr parsed; + + if (transcode) + { + // 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.GetTranscoder().TranscodeToParsed( + parsed->GetDcmtkObject(), data, content.size(), + syntaxes, true /* allow new SOP instance UID */)); + + if (transcodedDicom.get() != NULL && + transcodedDicom->GetDicom().getDataset() != NULL) + { + std::string transcoded; + FromDcmtkBridge::SaveToMemoryBuffer( + transcoded, *transcodedDicom->GetDicom().getDataset()); + + writer.Write(transcoded); - if (dicomDir != NULL) + if (dicomDir != NULL) + { + std::unique_ptr tmp( + ParsedDicomFile::AcquireDcmtkObject(transcodedDicom->ReleaseDicom())); + dicomDir->Add(dicomDirFolder, filename_, *tmp); + } + + transcodeSuccess = true; + } + else + { + LOG(INFO) << "Cannot transcode instance " << instanceId_ + << " to transfer syntax: " << GetTransferSyntaxUid(transferSyntax); + } + } + + if (!transcodeSuccess) { - ParsedDicomFile parsed(content); - dicomDir->Add(dicomDirFolder, filename_, parsed); + writer.Write(content); + + if (dicomDir != NULL) + { + if (parsed.get() == NULL) + { + parsed.reset(new ParsedDicomFile(content)); + } + + dicomDir->Add(dicomDirFolder, filename_, *parsed); + } } break; @@ -454,14 +509,16 @@ ServerContext& context, size_t index, DicomDirWriter* dicomDir, - const std::string& dicomDirFolder) const + const std::string& dicomDirFolder, + bool transcode, + DicomTransferSyntax transferSyntax) const { if (index >= commands_.size()) { throw OrthancException(ErrorCode_ParameterOutOfRange); } - commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder); + commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder, transcode, transferSyntax); } public: @@ -496,20 +553,26 @@ return uncompressedSize_; } + // "media" flavor (with DICOMDIR) void Apply(HierarchicalZipWriter& writer, ServerContext& context, size_t index, DicomDirWriter& dicomDir, - const std::string& dicomDirFolder) const + const std::string& dicomDirFolder, + bool transcode, + DicomTransferSyntax transferSyntax) const { - ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder); + ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder, transcode, transferSyntax); } + // "archive" flavor (without DICOMDIR) void Apply(HierarchicalZipWriter& writer, ServerContext& context, - size_t index) const + size_t index, + bool transcode, + DicomTransferSyntax transferSyntax) const { - ApplyInternal(writer, context, index, NULL, ""); + ApplyInternal(writer, context, index, NULL, "", transcode, transferSyntax); } void AddOpenDirectory(const std::string& filename) @@ -740,7 +803,9 @@ return commands_.GetSize() + 1; } - void RunStep(size_t index) + void RunStep(size_t index, + bool transcode, + DicomTransferSyntax transferSyntax) { if (index > commands_.GetSize()) { @@ -764,12 +829,13 @@ if (isMedia_) { assert(dicomDir_.get() != NULL); - commands_.Apply(*zip_, context_, index, *dicomDir_, MEDIA_IMAGES_FOLDER); + commands_.Apply(*zip_, context_, index, *dicomDir_, + MEDIA_IMAGES_FOLDER, transcode, transferSyntax); } else { assert(dicomDir_.get() == NULL); - commands_.Apply(*zip_, context_, index); + commands_.Apply(*zip_, context_, index, transcode, transferSyntax); } } } @@ -795,7 +861,9 @@ enableExtendedSopClass_(enableExtendedSopClass), currentStep_(0), instancesCount_(0), - uncompressedSize_(0) + uncompressedSize_(0), + transcode_(false), + transferSyntax_(DicomTransferSyntax_LittleEndianImplicit) { } @@ -854,6 +922,20 @@ } } + + void ArchiveJob::SetTranscode(DicomTransferSyntax transferSyntax) + { + if (writer_.get() != NULL) // Already started + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + transcode_ = true; + transferSyntax_ = transferSyntax; + } + } + void ArchiveJob::Reset() { @@ -954,7 +1036,7 @@ } else { - writer_->RunStep(currentStep_); + writer_->RunStep(currentStep_, transcode_, transferSyntax_); currentStep_ ++; @@ -1006,6 +1088,11 @@ value[KEY_INSTANCES_COUNT] = instancesCount_; value[KEY_UNCOMPRESSED_SIZE_MB] = static_cast(uncompressedSize_ / MEGA_BYTES); + + if (transcode_) + { + value[KEY_TRANSCODE] = GetTransferSyntaxUid(transferSyntax_); + } } diff -r 7610af1532c3 -r 6ddad3e0b569 OrthancServer/ServerJobs/ArchiveJob.h --- a/OrthancServer/ServerJobs/ArchiveJob.h Fri May 08 13:43:50 2020 +0200 +++ b/OrthancServer/ServerJobs/ArchiveJob.h Fri May 08 19:15:28 2020 +0200 @@ -69,6 +69,10 @@ uint64_t uncompressedSize_; std::string mediaArchiveId_; + // New in Orthanc 1.7.0 + bool transcode_; + DicomTransferSyntax transferSyntax_; + void FinalizeTarget(); public: @@ -89,6 +93,8 @@ void AddResource(const std::string& publicId); + void SetTranscode(DicomTransferSyntax transferSyntax); + virtual void Reset() ORTHANC_OVERRIDE; virtual void Start() ORTHANC_OVERRIDE;