Mercurial > hg > orthanc
changeset 3939:c205f670098e transcoding
new configuration options: BuiltinDecoderTranscoderOrder and IngestTranscoding
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 18 May 2020 17:15:16 +0200 |
parents | 54dbebbcc032 |
children | 3661e2a72482 |
files | Core/DicomParsing/DcmtkTranscoder.cpp NEWS OrthancServer/OrthancConfiguration.cpp OrthancServer/OrthancConfiguration.h OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h Resources/Configuration.json |
diffstat | 7 files changed, 115 insertions(+), 40 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/DicomParsing/DcmtkTranscoder.cpp Mon May 18 15:59:50 2020 +0200 +++ b/Core/DicomParsing/DcmtkTranscoder.cpp Mon May 18 17:15:16 2020 +0200 @@ -120,10 +120,14 @@ if (quality <= 0 || quality > 100) { - throw OrthancException(ErrorCode_ParameterOutOfRange); + throw OrthancException( + ErrorCode_ParameterOutOfRange, + "The quality for lossy transcoding must be an integer between 1 and 100, received: " + + boost::lexical_cast<std::string>(quality)); } else { + LOG(INFO) << "Quality for lossy transcoding using DCMTK is set to: " << quality; lossyQuality_ = quality; } }
--- a/NEWS Mon May 18 15:59:50 2020 +0200 +++ b/NEWS Mon May 18 17:15:16 2020 +0200 @@ -7,8 +7,9 @@ * DICOM transcoding over the REST API * Transcoding from compressed to uncompressed transfer syntaxes over DICOM C-STORE SCU (if the remote modality doesn't support compressed syntaxes) -* New configuration options: "TranscodeDicomProtocol" and - "BuiltinDecoderTranscoderOrder" +* New configuration options related to transcoding: + "TranscodeDicomProtocol", "BuiltinDecoderTranscoderOrder", + "IngestTranscoding" and "DicomLossyTranscodingQuality" REST API --------
--- a/OrthancServer/OrthancConfiguration.cpp Mon May 18 15:59:50 2020 +0200 +++ b/OrthancServer/OrthancConfiguration.cpp Mon May 18 17:15:16 2020 +0200 @@ -422,8 +422,8 @@ } - std::string OrthancConfiguration::GetStringParameter(const std::string& parameter, - const std::string& defaultValue) const + bool OrthancConfiguration::LookupStringParameter(std::string& target, + const std::string& parameter) const { if (json_.isMember(parameter)) { @@ -434,11 +434,27 @@ } else { - return json_[parameter].asString(); + target = json_[parameter].asString(); + return true; } } else { + return false; + } + } + + + std::string OrthancConfiguration::GetStringParameter(const std::string& parameter, + const std::string& defaultValue) const + { + std::string value; + if (LookupStringParameter(value, parameter)) + { + return value; + } + else + { return defaultValue; } }
--- a/OrthancServer/OrthancConfiguration.h Mon May 18 15:59:50 2020 +0200 +++ b/OrthancServer/OrthancConfiguration.h Mon May 18 17:15:16 2020 +0200 @@ -163,6 +163,9 @@ fontRegistry_.AddFromResource(resource); } + bool LookupStringParameter(std::string& target, + const std::string& parameter) const; + std::string GetStringParameter(const std::string& parameter, const std::string& defaultValue) const;
--- a/OrthancServer/ServerContext.cpp Mon May 18 15:59:50 2020 +0200 +++ b/OrthancServer/ServerContext.cpp Mon May 18 17:15:16 2020 +0200 @@ -246,37 +246,72 @@ isHttpServerSecure_(true), isExecuteLuaEnabled_(false), overwriteInstances_(false), - dcmtkTranscoder_(new DcmtkTranscoder) + dcmtkTranscoder_(new DcmtkTranscoder), + isIngestTranscoding_(false) { + try { - OrthancConfiguration::ReaderLock lock; + unsigned int lossyQuality; + + { + OrthancConfiguration::ReaderLock lock; - queryRetrieveArchive_.reset( - new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("QueryRetrieveSize", 100))); - mediaArchive_.reset( - new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("MediaArchiveSize", 1))); - defaultLocalAet_ = lock.GetConfiguration().GetStringParameter("DicomAet", "ORTHANC"); - jobsEngine_.SetWorkersCount(lock.GetConfiguration().GetUnsignedIntegerParameter("ConcurrentJobs", 2)); - saveJobs_ = lock.GetConfiguration().GetBooleanParameter("SaveJobs", true); - metricsRegistry_->SetEnabled(lock.GetConfiguration().GetBooleanParameter("MetricsEnabled", true)); + queryRetrieveArchive_.reset( + new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("QueryRetrieveSize", 100))); + mediaArchive_.reset( + new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("MediaArchiveSize", 1))); + defaultLocalAet_ = lock.GetConfiguration().GetStringParameter("DicomAet", "ORTHANC"); + jobsEngine_.SetWorkersCount(lock.GetConfiguration().GetUnsignedIntegerParameter("ConcurrentJobs", 2)); + saveJobs_ = lock.GetConfiguration().GetBooleanParameter("SaveJobs", true); + metricsRegistry_->SetEnabled(lock.GetConfiguration().GetBooleanParameter("MetricsEnabled", true)); + + // New configuration options in Orthanc 1.5.1 + findStorageAccessMode_ = StringToFindStorageAccessMode(lock.GetConfiguration().GetStringParameter("StorageAccessOnFind", "Always")); + limitFindInstances_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindInstances", 0); + limitFindResults_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindResults", 0); + + // New configuration option in Orthanc 1.6.0 + storageCommitmentReports_.reset(new StorageCommitmentReports(lock.GetConfiguration().GetUnsignedIntegerParameter("StorageCommitmentReportsSize", 100))); + + // New options in Orthanc 1.7.0 + transcodeDicomProtocol_ = lock.GetConfiguration().GetBooleanParameter("TranscodeDicomProtocol", true); + builtinDecoderTranscoderOrder_ = StringToBuiltinDecoderTranscoderOrder(lock.GetConfiguration().GetStringParameter("BuiltinDecoderTranscoderOrder", "After")); + lossyQuality = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomLossyTranscodingQuality", 90); - // New configuration options in Orthanc 1.5.1 - findStorageAccessMode_ = StringToFindStorageAccessMode(lock.GetConfiguration().GetStringParameter("StorageAccessOnFind", "Always")); - limitFindInstances_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindInstances", 0); - limitFindResults_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindResults", 0); - - // New configuration option in Orthanc 1.6.0 - storageCommitmentReports_.reset(new StorageCommitmentReports(lock.GetConfiguration().GetUnsignedIntegerParameter("StorageCommitmentReportsSize", 100))); + std::string s; + if (lock.GetConfiguration().LookupStringParameter(s, "IngestTranscoding")) + { + if (LookupTransferSyntax(ingestTransferSyntax_, s)) + { + isIngestTranscoding_ = true; + LOG(WARNING) << "Incoming DICOM instances will automatically be transcoded to " + << "transfer syntax: " << GetTransferSyntaxUid(ingestTransferSyntax_); + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Unknown transfer syntax for ingest transcoding: " + s); + } + } + else + { + isIngestTranscoding_ = true; + LOG(INFO) << "Automated transcoding of incoming DICOM instances is disabled"; + } + } - // New options in Orthanc 1.7.0 - transcodeDicomProtocol_ = lock.GetConfiguration().GetBooleanParameter("TranscodeDicomProtocol", true); - builtinDecoderTranscoderOrder_ = StringToBuiltinDecoderTranscoderOrder(lock.GetConfiguration().GetStringParameter("BuiltinDecoderTranscoderOrder", "After")); - } + jobsEngine_.SetThreadSleep(unitTesting ? 20 : 200); - jobsEngine_.SetThreadSleep(unitTesting ? 20 : 200); - - listeners_.push_back(ServerListener(luaListener_, "Lua")); - changeThread_ = boost::thread(ChangeThread, this, (unitTesting ? 20 : 100)); + listeners_.push_back(ServerListener(luaListener_, "Lua")); + changeThread_ = boost::thread(ChangeThread, this, (unitTesting ? 20 : 100)); + + dynamic_cast<DcmtkTranscoder&>(*dcmtkTranscoder_).SetLossyQuality(lossyQuality); + } + catch (OrthancException&) + { + Stop(); + throw; + } } @@ -508,22 +543,19 @@ DicomInstanceToStore& dicom, StoreInstanceMode mode) { - const DicomTransferSyntax option = DicomTransferSyntax_JPEGProcess1; - //const DicomTransferSyntax option = DicomTransferSyntax_JPEGProcess14SV1; - //const DicomTransferSyntax option = DicomTransferSyntax_LittleEndianExplicit; - - if (1) + if (!isIngestTranscoding_) { + // No automated transcoding return StoreAfterTranscoding(resultPublicId, dicom, mode); } else { - // TODO => Automated transcoding of incoming DICOM files + // Automated transcoding of incoming DICOM files DicomTransferSyntax sourceSyntax; if (!FromDcmtkBridge::LookupOrthancTransferSyntax( sourceSyntax, dicom.GetParsedDicomFile().GetDcmtkObject()) || - sourceSyntax == option) + sourceSyntax == ingestTransferSyntax_) { // No transcoding return StoreAfterTranscoding(resultPublicId, dicom, mode); @@ -531,7 +563,7 @@ else { std::set<DicomTransferSyntax> syntaxes; - syntaxes.insert(option); + syntaxes.insert(ingestTransferSyntax_); std::unique_ptr<IDicomTranscoder::TranscodedDicom> transcoded( TranscodeToParsed(dicom.GetParsedDicomFile().GetDcmtkObject(),
--- a/OrthancServer/ServerContext.h Mon May 18 15:59:50 2020 +0200 +++ b/OrthancServer/ServerContext.h Mon May 18 17:15:16 2020 +0200 @@ -230,6 +230,8 @@ bool transcodeDicomProtocol_; std::unique_ptr<IDicomTranscoder> dcmtkTranscoder_; BuiltinDecoderTranscoderOrder builtinDecoderTranscoderOrder_; + bool isIngestTranscoding_; + DicomTransferSyntax ingestTransferSyntax_; StoreStatus StoreAfterTranscoding(std::string& resultPublicId, DicomInstanceToStore& dicom,
--- a/Resources/Configuration.json Mon May 18 15:59:50 2020 +0200 +++ b/Resources/Configuration.json Mon May 18 17:15:16 2020 +0200 @@ -554,5 +554,22 @@ // or is not applied at all (new in Orthanc 1.7.0). The allowed // values for this option are "After" (default value, corresponding // to the behavior of Orthanc <= 1.6.1), "Before", or "Disabled". - "BuiltinDecoderTranscoderOrder" : "After" + "BuiltinDecoderTranscoderOrder" : "After", + + // If this option is set, Orthanc will transparently transcode any + // incoming DICOM instance to the given transfer syntax before + // storing it into its database. Beware that this might result in + // high CPU usage (if transcoding to some compressed transfer + // syntax), or in higher disk consumption (if transcoding to an + // uncompressed syntax). Also, beware that transcoding to a transfer + // syntax with lossy compression (notably JPEG) will change the + // "SOPInstanceUID" DICOM tag, and thus the Orthanc identifier at + // the instance level, which might break external workflow. + /** + "IngestTranscoding" : "1.2.840.10008.1.2", + **/ + + // The compression level that is used when transcoding to one of the + // lossy/JPEG transfer syntaxes (integer between 1 and 100). + "DicomLossyTranscodingQuality" : 90 }