# HG changeset patch # User Sebastien Jodogne # Date 1481291311 -3600 # Node ID 90ea60bee5ff7cec9d7bf02fac9282419d18115e # Parent 6dc3bdb4088bdc37fca95d6ee85311a381000fdf New metadata automatically computed at the instance level: "SopClassUid" diff -r 6dc3bdb4088b -r 90ea60bee5ff NEWS --- a/NEWS Fri Dec 09 11:24:04 2016 +0100 +++ b/NEWS Fri Dec 09 14:48:31 2016 +0100 @@ -6,7 +6,7 @@ * Handling of private tags/creators in the "Dictionary" configuration option * New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout" -* New metadata automatically computed at the instance level: "TransferSyntax" +* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid" REST API -------- diff -r 6dc3bdb4088b -r 90ea60bee5ff OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Fri Dec 09 11:24:04 2016 +0100 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Fri Dec 09 14:48:31 2016 +0100 @@ -107,10 +107,34 @@ } - static void ExtractTagFromInstances(std::set& target, - ServerContext& context, - const DicomTag& tag, - const std::list& instances) + static bool ExtractMetadata(std::set& target, + ServerIndex& index, + MetadataType metadata, + const std::list& resources) + { + for (std::list::const_iterator + it = resources.begin(); it != resources.end(); ++it) + { + std::string value; + if (index.LookupMetadata(value, *it, metadata)) + { + target.insert(value); + } + else + { + // This metadata is unavailable for some resource, give up + return false; + } + } + + return true; + } + + + static void ExtractTagFromInstancesOnDisk(std::set& target, + ServerContext& context, + const DicomTag& tag, + const std::list& instances) { // WARNING: This function is slow, as it reads the JSON file // summarizing each instance of interest from the hard drive. @@ -226,10 +250,16 @@ if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY)) { - if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false)) + std::set values; + + if (ExtractMetadata(values, index, MetadataType_Instance_SopClassUid, instances)) { - std::set values; - ExtractTagFromInstances(values, context, DICOM_TAG_SOP_CLASS_UID, instances); + // The metadata "SopClassUid" is available for each of these instances + StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values); + } + else if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false)) + { + ExtractTagFromInstancesOnDisk(values, context, DICOM_TAG_SOP_CLASS_UID, instances); StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values); } else diff -r 6dc3bdb4088b -r 90ea60bee5ff OrthancServer/ServerEnumerations.cpp --- a/OrthancServer/ServerEnumerations.cpp Fri Dec 09 11:24:04 2016 +0100 +++ b/OrthancServer/ServerEnumerations.cpp Fri Dec 09 14:48:31 2016 +0100 @@ -65,6 +65,7 @@ dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate"); dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin"); dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax"); + dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid"); dictContentType_.Add(FileContentType_Dicom, "dicom"); dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json"); diff -r 6dc3bdb4088b -r 90ea60bee5ff OrthancServer/ServerEnumerations.h --- a/OrthancServer/ServerEnumerations.h Fri Dec 09 11:24:04 2016 +0100 +++ b/OrthancServer/ServerEnumerations.h Fri Dec 09 14:48:31 2016 +0100 @@ -159,6 +159,7 @@ MetadataType_LastUpdate = 7, MetadataType_Instance_Origin = 8, // New in Orthanc 0.9.5 MetadataType_Instance_TransferSyntax = 9, // New in Orthanc 1.2.0 + MetadataType_Instance_SopClassUid = 10, // New in Orthanc 1.2.0 // Make sure that the value "65535" can be stored into this enumeration MetadataType_StartUser = 1024, diff -r 6dc3bdb4088b -r 90ea60bee5ff OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Fri Dec 09 11:24:04 2016 +0100 +++ b/OrthancServer/ServerIndex.cpp Fri Dec 09 14:48:31 2016 +0100 @@ -787,6 +787,13 @@ } const DicomValue* value; + if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && + !value->IsNull() && + !value->IsBinary()) + { + SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent()); + } + if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) { diff -r 6dc3bdb4088b -r 90ea60bee5ff Resources/Configuration.json --- a/Resources/Configuration.json Fri Dec 09 11:24:04 2016 +0100 +++ b/Resources/Configuration.json Fri Dec 09 14:48:31 2016 +0100 @@ -314,9 +314,12 @@ } **/ - // If set to "true", Orthanc will handle "SOP Classes in Study" - // (0008,0062) in C-FIND requests. This option is turned off by - // default, as it requires intensive accesses to the hard drive. + // If set to "true", Orthanc will still handle "SOP Classes in + // Study" (0008,0062) in C-FIND requests, even if the "SOP Class + // UID" metadata is not available in the database (which is the case + // if the DB was previously used by Orthanc <= 1.1.0). This option + // is turned off by default, as it requires intensive accesses to + // the hard drive. "AllowFindSopClassesInStudy" : false, // If set to "false", Orthanc will not load its default dictionary diff -r 6dc3bdb4088b -r 90ea60bee5ff TODO --- a/TODO Fri Dec 09 11:24:04 2016 +0100 +++ b/TODO Fri Dec 09 14:48:31 2016 +0100 @@ -105,7 +105,7 @@ Orthanc Book ============ -* Document C-FIND filters +* Document Lua C-FIND filters (cf. "IncomingFindRequestFilter()") ================ diff -r 6dc3bdb4088b -r 90ea60bee5ff UnitTestsSources/ServerIndexTests.cpp --- a/UnitTestsSources/ServerIndexTests.cpp Fri Dec 09 11:24:04 2016 +0100 +++ b/UnitTestsSources/ServerIndexTests.cpp Fri Dec 09 14:48:31 2016 +0100 @@ -793,19 +793,23 @@ instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id, false); instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id, false); instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id, false); + instance.SetValue(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false); // CR image std::map instanceMetadata; DicomInstanceToStore toStore; toStore.SetSummary(instance); ASSERT_EQ(StoreStatus_Success, index.Store(instanceMetadata, toStore, attachments)); - ASSERT_EQ(4u, instanceMetadata.size()); + ASSERT_EQ(5u, instanceMetadata.size()); ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_RemoteAet) != instanceMetadata.end()); ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_ReceptionDate) != instanceMetadata.end()); ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_TransferSyntax) != instanceMetadata.end()); + ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_SopClassUid) != instanceMetadata.end()); // By default, an Explicit VR Little Endian is used by Orthanc ASSERT_EQ("1.2.840.10008.1.2.1", instanceMetadata[MetadataType_Instance_TransferSyntax]); + ASSERT_EQ("1.2.840.10008.5.1.4.1.1.1", instanceMetadata[MetadataType_Instance_SopClassUid]); + DicomInstanceHasher hasher(instance); ids.push_back(hasher.HashPatient()); ids.push_back(hasher.HashStudy());