# HG changeset patch # User Alain Mazy # Date 1646899404 -3600 # Node ID 94a7b681b340d4fc17a17f2f42c872c1190fbf1e # Parent 312c6f4da88844cc2dd29557b96b607772469802 added configuration for extra main dicom tags + save signature in metadata + show warning if inconsistent main dicom tags diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Resources/Configuration.json --- a/OrthancServer/Resources/Configuration.json Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Resources/Configuration.json Thu Mar 10 09:03:24 2022 +0100 @@ -858,5 +858,36 @@ // (default behaviour). A value > 1 is meaningful only if the storage // is a distributed network storage (e.g object storage plugin). // (new experimental feature in Orthanc 1.10.0) - "ZipLoaderThreads": 0 + "ZipLoaderThreads": 0, + + // Extra Main Dicom tags that are stored in DB together with all default + // Main Dicom tags that are already stored (TODO: see book new page). + // (new in Orthanc 1.11.0) + /** + "ExtraMainDicomTags" : { + "Instance" : [ + "Rows", + "Columns", + "ImageType", + "SOPClassUID", + "ContentDate", + "ContentTime", + "FrameOfReferenceUID", + "PixelSpacing", + "SpecificCharacterSet", + "BitsAllocated" + ], + "Series" : [], + "Study": [], + "Patient": [] + }, + */ + + // Enables/disables a warning notifying you when you try to access a + // resource that has been saved with a different version of the + // ExtraMainDicomTags list + // TODO: see book new page + // (new in Orthanc 1.11.0) + "EnableLogsForInconsistentMainDicomTags": true + } diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Thu Mar 10 09:03:24 2022 +0100 @@ -941,6 +941,20 @@ throw OrthancException(ErrorCode_InternalError); } + // check the main dicom tags list has not changed since the resource was stored + std::string resourceMainDicomTagsSignature = DicomMap::GetDefaultMainDicomTagsSignature(type); + LookupStringMetadata(resourceMainDicomTagsSignature, metadata, MetadataType_MainDicomTagsSignature); + + if (resourceMainDicomTagsSignature != DicomMap::GetMainDicomTagsSignature(type)) + { + OrthancConfiguration::ReaderLock lock; + if (lock.GetConfiguration().IsInconsistentDicomTagsLogsEnabled()) + { + LOG(WARNING) << Orthanc::GetResourceTypeText(type, false , false) << " has been stored with another version of Main Dicom Tags list, you should POST to /" << Orthanc::GetResourceTypeText(type, true, false) << "/" << tuple.get<2>() << "/reconstruct to update the list of tags saved in DB. Some tags might be missing from this answer."; + } + } + + // Record the remaining information target["ID"] = tuple.get<2>(); MainDicomTagsToJson(transaction, target, internalId, type, tuple.get<4>()); @@ -2700,7 +2714,13 @@ content.AddResource(study, ResourceType_Study, summary_); content.AddResource(series, ResourceType_Series, summary_); content.AddResource(instance, ResourceType_Instance, summary_); + transaction.SetResourcesContent(content); + + ReplaceMetadata(transaction, patient, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 + ReplaceMetadata(transaction, study, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 + ReplaceMetadata(transaction, series, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 + ReplaceMetadata(transaction, instance, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 } if (hasTransferSyntax_) @@ -2715,6 +2735,7 @@ { ReplaceMetadata(transaction, instance, MetadataType_Instance_SopClassUid, value->GetContent()); } + } }; @@ -3081,25 +3102,28 @@ // Populate the tags of the newly-created resources content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); + content.AddMetadata(instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 if (status.isNewSeries_) { content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); + content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 } if (status.isNewStudy_) { content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); + content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 } if (status.isNewPatient_) { content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); + content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 } // Attach the user-specified metadata - // MORE_TAGS: TODO store the mainDicomTags list in metadata for (MetadataMap::const_iterator it = metadata_.begin(); it != metadata_.end(); ++it) diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/OrthancConfiguration.cpp --- a/OrthancServer/Sources/OrthancConfiguration.cpp Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/OrthancConfiguration.cpp Thu Mar 10 09:03:24 2022 +0100 @@ -1055,6 +1055,10 @@ } } + bool OrthancConfiguration::IsInconsistentDicomTagsLogsEnabled() const + { + return GetBooleanParameter("EnableLogsForInconsistentMainDicomTags", true); + } void OrthancConfiguration::DefaultExtractDicomSummary(DicomMap& target, const ParsedDicomFile& dicom) diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/OrthancConfiguration.h --- a/OrthancServer/Sources/OrthancConfiguration.h Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/OrthancConfiguration.h Thu Mar 10 09:03:24 2022 +0100 @@ -242,6 +242,8 @@ std::string GetDatabaseServerIdentifier() const; + bool IsInconsistentDicomTagsLogsEnabled() const; + static void DefaultExtractDicomSummary(DicomMap& target, const ParsedDicomFile& dicom); diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/OrthancInitialization.cpp --- a/OrthancServer/Sources/OrthancInitialization.cpp Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/OrthancInitialization.cpp Thu Mar 10 09:03:24 2022 +0100 @@ -200,6 +200,64 @@ } } + static void LoadMainDicomTags(const Json::Value& configuration) + { + static const char* const EXTRA_MAIN_DICOM_TAGS = "ExtraMainDicomTags"; + + if (configuration.type() != Json::objectValue || + !configuration.isMember(EXTRA_MAIN_DICOM_TAGS) || + configuration[EXTRA_MAIN_DICOM_TAGS].type() != Json::objectValue) + { + return; + } + + Json::Value::Members levels(configuration[EXTRA_MAIN_DICOM_TAGS].getMemberNames()); + + for (Json::Value::ArrayIndex i = 0; i < levels.size(); i++) + { + ResourceType level; + if (levels[i] == "Patient") + { + level = ResourceType_Patient; + } + else if (levels[i] == "Study") + { + level = ResourceType_Study; + } + else if (levels[i] == "Series") + { + level = ResourceType_Series; + } + else if (levels[i] == "Instance") + { + level = ResourceType_Instance; + } + else + { + throw OrthancException(ErrorCode_BadFileFormat, "Unknown entry '" + levels[i] + "' in ExtraMainDicomTags."); + } + + const Json::Value& content = configuration[EXTRA_MAIN_DICOM_TAGS][levels[i]]; + + if (content.type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadFileFormat, "The definition of the '" + levels[i] + "' ExtraMainDicomTags entry is invalid (not an array)."); + } + + if (content.size() > 0) + { + LOG(INFO) << "Configured Extra Main Dicom Tags for " << levels[i] << ":"; + + for (Json::Value::ArrayIndex t = 0; t < content.size(); t++) + { + const std::string& tagName = content[t].asString(); + DicomTag tag(FromDcmtkBridge::ParseTag(tagName)); + DicomMap::AddMainDicomTag(tag, tagName, level); + LOG(INFO) << " - " << tagName; + } + } + } + } static void ConfigurePkcs11(const Json::Value& config) { @@ -299,6 +357,8 @@ LoadExternalDictionaries(lock.GetJson()); // New in Orthanc 1.9.4 LoadCustomDictionary(lock.GetJson()); + LoadMainDicomTags(lock.GetJson()); // New in Orthanc 1.11.0 + lock.GetConfiguration().RegisterFont(ServerResources::FONT_UBUNTU_MONO_BOLD_16); #if HAVE_MALLOPT == 1 diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/ServerEnumerations.cpp --- a/OrthancServer/Sources/ServerEnumerations.cpp Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/ServerEnumerations.cpp Thu Mar 10 09:03:24 2022 +0100 @@ -60,6 +60,7 @@ dictMetadataType_.Add(MetadataType_Instance_CalledAet, "CalledAET"); dictMetadataType_.Add(MetadataType_Instance_HttpUsername, "HttpUsername"); dictMetadataType_.Add(MetadataType_Instance_PixelDataOffset, "PixelDataOffset"); + dictMetadataType_.Add(MetadataType_MainDicomTagsSignature, "MainDicomTagsSignature"); dictContentType_.Add(FileContentType_Dicom, "dicom"); dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json"); diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/ServerEnumerations.h --- a/OrthancServer/Sources/ServerEnumerations.h Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/ServerEnumerations.h Thu Mar 10 09:03:24 2022 +0100 @@ -151,7 +151,8 @@ MetadataType_Instance_CalledAet = 12, // New in Orthanc 1.4.0 MetadataType_Instance_HttpUsername = 13, // New in Orthanc 1.4.0 MetadataType_Instance_PixelDataOffset = 14, // New in Orthanc 1.9.0 - + MetadataType_MainDicomTagsSignature = 15, // New in Orthanc 1.11.0 + // Make sure that the value "65535" can be stored into this enumeration MetadataType_StartUser = 1024, MetadataType_EndUser = 65535 diff -r 312c6f4da888 -r 94a7b681b340 OrthancServer/Sources/ServerToolbox.cpp --- a/OrthancServer/Sources/ServerToolbox.cpp Wed Mar 09 12:16:45 2022 +0100 +++ b/OrthancServer/Sources/ServerToolbox.cpp Thu Mar 10 09:03:24 2022 +0100 @@ -107,29 +107,7 @@ // example). Take this improvement into consideration for the // next upgrade of the database schema. - const char* plural = NULL; - - switch (level) - { - case ResourceType_Patient: - plural = "patients"; - break; - - case ResourceType_Study: - plural = "studies"; - break; - - case ResourceType_Series: - plural = "series"; - break; - - case ResourceType_Instance: - plural = "instances"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } + const char* plural = Orthanc::GetResourceTypeText(level, true, true); LOG(WARNING) << "Upgrade: Reconstructing the main DICOM tags of all the " << plural << "..."; @@ -181,8 +159,11 @@ transaction.ClearMainDicomTags(resource); ResourcesContent tags(false /* prevent the setting of metadata */); - tags.AddResource(resource, level, dicomSummary); // MORE_TAGS: re-set the dicomMainTagsList metadata + tags.AddResource(resource, level, dicomSummary); transaction.SetResourcesContent(tags); + + transaction.DeleteMetadata(resource, MetadataType_MainDicomTagsSignature); + transaction.SetMetadata(resource, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(level), 0); } catch (OrthancException&) {