Mercurial > hg > orthanc
changeset 3912:7610af1532c3 transcoding
prototyping automated transcoding of incoming DICOM files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 08 May 2020 13:43:50 +0200 |
parents | 0ef7f4528be2 |
children | 6ddad3e0b569 |
files | Core/DicomParsing/IDicomTranscoder.cpp Core/DicomParsing/IDicomTranscoder.h Core/DicomParsing/ParsedDicomFile.cpp Core/DicomParsing/ParsedDicomFile.h OrthancServer/DicomInstanceToStore.cpp OrthancServer/DicomInstanceToStore.h OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/OrthancRestApi/OrthancRestApi.cpp OrthancServer/OrthancRestApi/OrthancRestApi.h OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h |
diffstat | 11 files changed, 148 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/DicomParsing/IDicomTranscoder.cpp Fri May 08 12:10:04 2020 +0200 +++ b/Core/DicomParsing/IDicomTranscoder.cpp Fri May 08 13:43:50 2020 +0200 @@ -86,7 +86,26 @@ } else { - throw OrthancException(ErrorCode_InternalError); + // 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); + } + } }
--- a/Core/DicomParsing/IDicomTranscoder.h Fri May 08 12:10:04 2020 +0200 +++ b/Core/DicomParsing/IDicomTranscoder.h Fri May 08 13:43:50 2020 +0200 @@ -85,7 +85,9 @@ return hasSopInstanceUidChanged_; } - DcmFileFormat& GetDicom() const; + DcmFileFormat& GetDicom() const; + + DcmFileFormat* ReleaseDicom(); }; /**
--- a/Core/DicomParsing/ParsedDicomFile.cpp Fri May 08 12:10:04 2020 +0200 +++ b/Core/DicomParsing/ParsedDicomFile.cpp Fri May 08 13:43:50 2020 +0200 @@ -1113,6 +1113,12 @@ } + ParsedDicomFile::ParsedDicomFile(DcmFileFormat* dicom) : pimpl_(new PImpl) + { + pimpl_->file_.reset(dicom); // No cloning + } + + DcmFileFormat& ParsedDicomFile::GetDcmtkObject() const { return *pimpl_->file_.get();
--- a/Core/DicomParsing/ParsedDicomFile.h Fri May 08 12:10:04 2020 +0200 +++ b/Core/DicomParsing/ParsedDicomFile.h Fri May 08 13:43:50 2020 +0200 @@ -102,6 +102,8 @@ bool EmbedContentInternal(const std::string& dataUriScheme); + ParsedDicomFile(DcmFileFormat* dicom); // This takes ownership (no clone) + public: ParsedDicomFile(bool createIdentifiers); // Create a minimal DICOM instance @@ -114,9 +116,14 @@ ParsedDicomFile(const std::string& content); - ParsedDicomFile(DcmDataset& dicom); + ParsedDicomFile(DcmDataset& dicom); // This clones the DCMTK object + + ParsedDicomFile(DcmFileFormat& dicom); // This clones the DCMTK object - ParsedDicomFile(DcmFileFormat& dicom); + static ParsedDicomFile* AcquireDcmtkObject(DcmFileFormat* dicom) // No clone here + { + return new ParsedDicomFile(dicom); + } DcmFileFormat& GetDcmtkObject() const;
--- a/OrthancServer/DicomInstanceToStore.cpp Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/DicomInstanceToStore.cpp Fri May 08 13:43:50 2020 +0200 @@ -381,14 +381,14 @@ } - bool HasPixelData() + ParsedDicomFile& GetParsedDicomFile() { ComputeMissingInformation(); ParseDicomFile(); if (parsed_.HasContent()) { - return parsed_.GetContent().HasTag(DICOM_TAG_PIXEL_DATA); + return parsed_.GetContent(); } else { @@ -498,6 +498,11 @@ bool DicomInstanceToStore::HasPixelData() const { - return const_cast<PImpl&>(*pimpl_).HasPixelData(); + return const_cast<PImpl&>(*pimpl_).GetParsedDicomFile().HasTag(DICOM_TAG_PIXEL_DATA); + } + + ParsedDicomFile& DicomInstanceToStore::GetParsedDicomFile() const + { + return const_cast<PImpl&>(*pimpl_).GetParsedDicomFile(); } }
--- a/OrthancServer/DicomInstanceToStore.h Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/DicomInstanceToStore.h Fri May 08 13:43:50 2020 +0200 @@ -92,5 +92,7 @@ DicomInstanceHasher& GetHasher(); bool HasPixelData() const; + + ParsedDicomFile& GetParsedDicomFile() const; }; }
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri May 08 13:43:50 2020 +0200 @@ -280,7 +280,7 @@ if (sendAnswer) { - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status); + OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, id); } }
--- a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Fri May 08 13:43:50 2020 +0200 @@ -63,11 +63,11 @@ void OrthancRestApi::AnswerStoredInstance(RestApiPostCall& call, DicomInstanceToStore& instance, - StoreStatus status) const + StoreStatus status, + const std::string& instanceId) const { Json::Value result; - SetupResourceAnswer(result, instance.GetHasher().HashInstance(), - ResourceType_Instance, status); + SetupResourceAnswer(result, instanceId, ResourceType_Instance, status); result["ParentPatient"] = instance.GetHasher().HashPatient(); result["ParentStudy"] = instance.GetHasher().HashStudy(); @@ -142,7 +142,7 @@ std::string publicId; StoreStatus status = context.Store(publicId, toStore, StoreInstanceMode_Default); - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status); + OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, publicId); }
--- a/OrthancServer/OrthancRestApi/OrthancRestApi.h Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.h Fri May 08 13:43:50 2020 +0200 @@ -107,9 +107,12 @@ static ServerIndex& GetIndex(RestApiCall& call); + // WARNING: "instanceId" can be different from + // "instance.GetHasher().HashInstance()" if transcoding is enabled void AnswerStoredInstance(RestApiPostCall& call, DicomInstanceToStore& instance, - StoreStatus status) const; + StoreStatus status, + const std::string& instanceId) const; void AnswerStoredResource(RestApiPostCall& call, const std::string& publicId,
--- a/OrthancServer/ServerContext.cpp Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/ServerContext.cpp Fri May 08 13:43:50 2020 +0200 @@ -344,9 +344,9 @@ } - StoreStatus ServerContext::Store(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode) + StoreStatus ServerContext::StoreAfterTranscoding(std::string& resultPublicId, + DicomInstanceToStore& dicom, + StoreInstanceMode mode) { bool overwrite; switch (mode) @@ -502,6 +502,61 @@ } + StoreStatus ServerContext::Store(std::string& resultPublicId, + DicomInstanceToStore& dicom, + StoreInstanceMode mode) + { + const DicomTransferSyntax option = DicomTransferSyntax_JPEGProcess1; + + if (1) + { + return StoreAfterTranscoding(resultPublicId, dicom, mode); + } + else + { + // TODO => Automated transcoding of incoming DICOM files + + DicomTransferSyntax sourceSyntax; + if (!FromDcmtkBridge::LookupOrthancTransferSyntax( + sourceSyntax, dicom.GetParsedDicomFile().GetDcmtkObject()) || + sourceSyntax == option) + { + // No transcoding + return StoreAfterTranscoding(resultPublicId, dicom, mode); + } + else + { + std::set<DicomTransferSyntax> syntaxes; + syntaxes.insert(option); + + std::unique_ptr<IDicomTranscoder::TranscodedDicom> transcoded( + GetTranscoder().TranscodeToParsed(dicom.GetParsedDicomFile().GetDcmtkObject(), + dicom.GetBufferData(), dicom.GetBufferSize(), + syntaxes, true /* allow new SOP instance UID */)); + + if (transcoded.get() == NULL) + { + // Cannot transcode => store the original file + return StoreAfterTranscoding(resultPublicId, dicom, mode); + } + else + { + std::unique_ptr<ParsedDicomFile> tmp( + ParsedDicomFile::AcquireDcmtkObject(transcoded->ReleaseDicom())); + + DicomInstanceToStore toStore; + toStore.SetParsedDicomFile(*tmp); + toStore.SetOrigin(dicom.GetOrigin()); + + StoreStatus ok = StoreAfterTranscoding(resultPublicId, toStore, mode); + printf(">> %s\n", resultPublicId.c_str()); + return ok; + } + } + } + } + + void ServerContext::AnswerAttachment(RestApiOutput& output, const std::string& resourceId, FileContentType content) @@ -1115,6 +1170,28 @@ } + IDicomTranscoder& ServerContext::GetTranscoder() + { + IDicomTranscoder* transcoder = dcmtkTranscoder_.get(); + +#if ORTHANC_ENABLE_PLUGINS == 1 + if (HasPlugins()) + { + transcoder = &GetPlugins(); + } +#endif + + if (transcoder == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + else + { + return *transcoder; + } + } + + void ServerContext::StoreWithTranscoding(std::string& sopClassUid, std::string& sopInstanceUid, DicomStoreUserConnection& connection, @@ -1133,24 +1210,8 @@ } else { - IDicomTranscoder* transcoder = dcmtkTranscoder_.get(); - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins()) - { - transcoder = &GetPlugins(); - } -#endif - - if (transcoder == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - connection.Transcode(sopClassUid, sopInstanceUid, *transcoder, data, dicom.size(), - hasMoveOriginator, moveOriginatorAet, moveOriginatorId); - } + connection.Transcode(sopClassUid, sopInstanceUid, GetTranscoder(), data, dicom.size(), + hasMoveOriginator, moveOriginatorAet, moveOriginatorId); } } @@ -1162,24 +1223,8 @@ DicomTransferSyntax targetSyntax, bool allowNewSopInstanceUid) { - IDicomTranscoder* transcoder = dcmtkTranscoder_.get(); - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins()) - { - transcoder = &GetPlugins(); - } -#endif - - if (transcoder == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - return transcoder->TranscodeParsedToBuffer( - target, sourceSyntax, hasSopInstanceUidChanged, - dicom.GetDcmtkObject(), targetSyntax, allowNewSopInstanceUid); - } + return GetTranscoder().TranscodeParsedToBuffer( + target, sourceSyntax, hasSopInstanceUidChanged, + dicom.GetDcmtkObject(), targetSyntax, allowNewSopInstanceUid); } }
--- a/OrthancServer/ServerContext.h Fri May 08 12:10:04 2020 +0200 +++ b/OrthancServer/ServerContext.h Fri May 08 13:43:50 2020 +0200 @@ -229,6 +229,12 @@ bool transcodeDicomProtocol_; std::unique_ptr<IDicomTranscoder> dcmtkTranscoder_; + IDicomTranscoder& GetTranscoder(); + + StoreStatus StoreAfterTranscoding(std::string& resultPublicId, + DicomInstanceToStore& dicom, + StoreInstanceMode mode); + public: class DicomCacheLocker : public boost::noncopyable {