# HG changeset patch # User Sebastien Jodogne # Date 1481300421 -3600 # Node ID e3fd5bc429a2349db1462c4c606e222273e85099 # Parent 90ea60bee5ff7cec9d7bf02fac9282419d18115e URI to reconstruct the main DICOM tags, the JSON summary and the metadata diff -r 90ea60bee5ff -r e3fd5bc429a2 NEWS --- a/NEWS Fri Dec 09 14:48:31 2016 +0100 +++ b/NEWS Fri Dec 09 17:20:21 2016 +0100 @@ -17,15 +17,18 @@ * "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store" to avoid waiting for the completion of image transfers * Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries + (useful if "Dictionary" has changed) * "Keep" option for modifications to keep original DICOM identifiers (advanced feature) * "/tools/default-encoding" to get or temporarily change the default encoding +* "/{resource}/{id}/reconstruct" to reconstruct the main DICOM tags, the JSON summary and + the metadata of a resource (useful to compute new metadata, or if using "Keep" above) Plugins ------- * New function: "OrthancPluginRegisterPrivateDictionaryTag()" to register private tags * More control over client cache in the ServeFolders plugin -* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets +* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets from REST API Maintenance ----------- diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/DicomModification.cpp --- a/OrthancServer/DicomModification.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/DicomModification.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -149,8 +149,7 @@ level_(ResourceType_Instance), allowManualIdentifiers_(true), keepStudyInstanceUid_(false), - keepSeriesInstanceUid_(false), - keepSopInstanceUid_(false) + keepSeriesInstanceUid_(false) { } @@ -179,11 +178,6 @@ keepSeriesInstanceUid_ = true; } - if (tag == DICOM_TAG_SOP_INSTANCE_UID) - { - keepSopInstanceUid_ = true; - } - MarkNotOrthancAnonymization(); } @@ -510,14 +504,7 @@ if (level_ <= ResourceType_Instance && // Always true !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) { - if (keepSopInstanceUid_) - { - LOG(WARNING) << "Modifying an instance while keeping its original SOPInstanceUID: This should be avoided!"; - } - else - { - MapDicomIdentifier(toModify, ResourceType_Instance); - } + MapDicomIdentifier(toModify, ResourceType_Instance); } } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/DicomModification.h --- a/OrthancServer/DicomModification.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/DicomModification.h Fri Dec 09 17:20:21 2016 +0100 @@ -59,7 +59,6 @@ bool allowManualIdentifiers_; bool keepStudyInstanceUid_; bool keepSeriesInstanceUid_; - bool keepSopInstanceUid_; void MapDicomIdentifier(ParsedDicomFile& dicom, ResourceType level); diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -1943,4 +1943,23 @@ } } } + + + bool FromDcmtkBridge::LookupTransferSyntax(std::string& result, + DcmFileFormat& dicom) + { + const char* value = NULL; + + if (dicom.getMetaInfo() != NULL && + dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() && + value != NULL) + { + result.assign(value); + return true; + } + else + { + return false; + } + } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/FromDcmtkBridge.h Fri Dec 09 17:20:21 2016 +0100 @@ -199,5 +199,8 @@ static void FromJson(DicomMap& values, const Json::Value& result); + + static bool LookupTransferSyntax(std::string& result, + DcmFileFormat& dicom); }; } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/OrthancInitialization.h --- a/OrthancServer/OrthancInitialization.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/OrthancInitialization.h Fri Dec 09 17:20:21 2016 +0100 @@ -142,7 +142,6 @@ static bool HasConfigurationChanged(); - static void ExtractDicomSummary(DicomMap& target, DcmItem& dataset); diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -1381,6 +1381,15 @@ } + template + static void ReconstructResource(RestApiPostCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + ServerToolbox::ReconstructResource(context, call.GetUriComponent("id", "")); + call.GetOutput().AnswerBuffer("", "text/plain"); + } + + void OrthancRestApi::RegisterResources() { Register("/instances", ListResources); @@ -1480,5 +1489,10 @@ Register("/instances/{id}/content/*", GetRawContent); Register("/series/{id}/ordered-slices", OrderSlices); + + Register("/patients/{id}/reconstruct", ReconstructResource); + Register("/studies/{id}/reconstruct", ReconstructResource); + Register("/series/{id}/reconstruct", ReconstructResource); + Register("/instances/{id}/reconstruct", ReconstructResource); } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ParsedDicomFile.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -1300,12 +1300,6 @@ } - void ParsedDicomFile::Convert(DicomMap& tags) - { - Configuration::ExtractDicomSummary(tags, *pimpl_->file_->getDataset()); - } - - ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json, DicomFromJsonFlags flags) { @@ -1396,4 +1390,22 @@ FromDcmtkBridge::ChangeStringEncoding(*pimpl_->file_->getDataset(), source, target); } } + + + void ParsedDicomFile::ExtractDicomSummary(DicomMap& target) const + { + Configuration::ExtractDicomSummary(target, *pimpl_->file_->getDataset()); + } + + + void ParsedDicomFile::ExtractDicomAsJson(Json::Value& target) const + { + Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset()); + } + + + bool ParsedDicomFile::LookupTransferSyntax(std::string& result) + { + return FromDcmtkBridge::LookupTransferSyntax(result, *pimpl_->file_); + } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ParsedDicomFile.h --- a/OrthancServer/ParsedDicomFile.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ParsedDicomFile.h Fri Dec 09 17:20:21 2016 +0100 @@ -166,8 +166,6 @@ bool ExtractPdf(std::string& pdf); - void Convert(DicomMap& tags); - void GetRawFrame(std::string& target, // OUT std::string& mime, // OUT unsigned int frameId); // IN @@ -178,5 +176,11 @@ DicomFromJsonFlags flags); void ChangeEncoding(Encoding target); + + void ExtractDicomSummary(DicomMap& target) const; + + void ExtractDicomAsJson(Json::Value& target) const; + + bool LookupTransferSyntax(std::string& result); }; } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/QueryRetrieveHandler.cpp --- a/OrthancServer/QueryRetrieveHandler.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/QueryRetrieveHandler.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -100,7 +100,7 @@ size_t i) { Run(); - answers_.GetAnswer(i).Convert(target); + answers_.GetAnswer(i).ExtractDicomSummary(target); } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ServerIndex.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -40,6 +40,7 @@ #include "ServerIndexChange.h" #include "EmbeddedResources.h" #include "OrthancInitialization.h" +#include "ParsedDicomFile.h" #include "ServerToolbox.h" #include "../Core/Toolbox.h" #include "../Core/Logging.h" @@ -2236,4 +2237,67 @@ target = db_.GetPublicId(id); return true; } + + + void ServerIndex::ReconstructInstance(ParsedDicomFile& dicom) + { + DicomMap summary; + dicom.ExtractDicomSummary(summary); + + DicomInstanceHasher hasher(summary); + + boost::mutex::scoped_lock lock(mutex_); + + try + { + Transaction t(*this); + + int64_t patient = -1, study = -1, series = -1, instance = -1; + + ResourceType dummy; + if (!db_.LookupResource(patient, dummy, hasher.HashPatient()) || + !db_.LookupResource(study, dummy, hasher.HashStudy()) || + !db_.LookupResource(series, dummy, hasher.HashSeries()) || + !db_.LookupResource(instance, dummy, hasher.HashInstance()) || + patient == -1 || + study == -1 || + series == -1 || + instance == -1) + { + throw OrthancException(ErrorCode_InternalError); + } + + db_.ClearMainDicomTags(patient); + db_.ClearMainDicomTags(study); + db_.ClearMainDicomTags(series); + db_.ClearMainDicomTags(instance); + + ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, summary); + ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, summary); + ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, summary); + ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, summary); + + { + std::string s; + if (dicom.LookupTransferSyntax(s)) + { + db_.SetMetadata(instance, MetadataType_Instance_TransferSyntax, s); + } + } + + const DicomValue* value; + if ((value = summary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && + !value->IsNull() && + !value->IsBinary()) + { + db_.SetMetadata(instance, MetadataType_Instance_SopClassUid, value->GetContent()); + } + + t.Commit(0); // No change in the DB size + } + catch (OrthancException& e) + { + LOG(ERROR) << "EXCEPTION [" << e.What() << "]"; + } + } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ServerIndex.h --- a/OrthancServer/ServerIndex.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ServerIndex.h Fri Dec 09 17:20:21 2016 +0100 @@ -47,6 +47,7 @@ class LookupResource; class ServerContext; class DicomInstanceToStore; + class ParsedDicomFile; class ServerIndex : public boost::noncopyable { @@ -273,5 +274,7 @@ bool LookupParent(std::string& target, const std::string& publicId, ResourceType parentType); + + void ReconstructInstance(ParsedDicomFile& dicom); }; } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ServerToolbox.cpp --- a/OrthancServer/ServerToolbox.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ServerToolbox.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -37,7 +37,6 @@ #include "../Core/FileStorage/StorageAccessor.h" #include "../Core/Logging.h" #include "../Core/OrthancException.h" -#include "ParsedDicomFile.h" #include @@ -406,7 +405,7 @@ // Update the tags of this resource DicomMap dicomSummary; - dicom.Convert(dicomSummary); + dicom.ExtractDicomSummary(dicomSummary); database.ClearMainDicomTags(resource); StoreMainDicomTags(database, resource, level, dicomSummary); @@ -497,5 +496,29 @@ return false; } + + + void ReconstructResource(ServerContext& context, + const std::string& resource) + { + LOG(WARNING) << "Reconstructing resource " << resource; + + std::list instances; + context.GetIndex().GetChildInstances(instances, resource); + + for (std::list::const_iterator + it = instances.begin(); it != instances.end(); ++it) + { + ServerContext::DicomCacheLocker locker(context, *it); + + Json::Value dicomAsJson; + locker.GetDicom().ExtractDicomAsJson(dicomAsJson); + + std::string s = dicomAsJson.toStyledString(); + context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size()); + + context.GetIndex().ReconstructInstance(locker.GetDicom()); + } + } } } diff -r 90ea60bee5ff -r e3fd5bc429a2 OrthancServer/ServerToolbox.h --- a/OrthancServer/ServerToolbox.h Fri Dec 09 14:48:31 2016 +0100 +++ b/OrthancServer/ServerToolbox.h Fri Dec 09 17:20:21 2016 +0100 @@ -32,8 +32,7 @@ #pragma once -#include "../Core/DicomFormat/DicomMap.h" -#include "IDatabaseWrapper.h" +#include "ServerContext.h" #include @@ -69,5 +68,8 @@ ResourceType level); std::string NormalizeIdentifier(const std::string& value); + + void ReconstructResource(ServerContext& context, + const std::string& resource); } } diff -r 90ea60bee5ff -r e3fd5bc429a2 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Fri Dec 09 14:48:31 2016 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Fri Dec 09 17:20:21 2016 +0100 @@ -469,6 +469,7 @@ f.ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, "Tata"); // (**) std::string s; + ASSERT_FALSE(f.LookupTransferSyntax(s)); ASSERT_THROW(f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"), false, DicomReplaceMode_ThrowIfAbsent), OrthancException);