Mercurial > hg > orthanc
changeset 3651:46cb00e4adbb
DicomMap::DumpMainDicomTags() and DicomMap::ParseMainDicomTags()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 05 Feb 2020 13:22:02 +0100 |
parents | e5811a9f8df0 |
children | 335611d2b6cd 468181e2f090 |
files | Core/DicomFormat/DicomArray.cpp Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomMap.h Core/DicomFormat/DicomTag.cpp Core/DicomFormat/DicomTag.h Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h Core/DicomParsing/ParsedDicomFile.cpp OrthancServer/OrthancRestApi/OrthancRestModalities.cpp UnitTestsSources/DicomMapTests.cpp UnitTestsSources/ImageProcessingTests.cpp |
diffstat | 11 files changed, 325 insertions(+), 224 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/DicomFormat/DicomArray.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomFormat/DicomArray.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -40,10 +40,10 @@ { DicomArray::DicomArray(const DicomMap& map) { - elements_.reserve(map.map_.size()); + elements_.reserve(map.content_.size()); - for (DicomMap::Map::const_iterator it = - map.map_.begin(); it != map.map_.end(); ++it) + for (DicomMap::Content::const_iterator it = + map.content_.begin(); it != map.content_.end(); ++it) { elements_.push_back(new DicomElement(it->first, *it->second)); }
--- a/Core/DicomFormat/DicomMap.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomFormat/DicomMap.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -46,72 +46,87 @@ namespace Orthanc { - static DicomTag patientTags[] = + namespace { - //DicomTag(0x0010, 0x1010), // PatientAge - //DicomTag(0x0010, 0x1040) // PatientAddress - DicomTag(0x0010, 0x0010), // PatientName - DicomTag(0x0010, 0x0030), // PatientBirthDate - DicomTag(0x0010, 0x0040), // PatientSex - DicomTag(0x0010, 0x1000), // OtherPatientIDs - DICOM_TAG_PATIENT_ID - }; + struct MainDicomTag + { + const DicomTag tag_; + const char* name_; + }; + } - static DicomTag studyTags[] = + static const MainDicomTag PATIENT_MAIN_DICOM_TAGS[] = { - //DicomTag(0x0010, 0x1020), // PatientSize - //DicomTag(0x0010, 0x1030) // PatientWeight - DICOM_TAG_STUDY_DATE, - DicomTag(0x0008, 0x0030), // StudyTime - DicomTag(0x0020, 0x0010), // StudyID - DICOM_TAG_STUDY_DESCRIPTION, - DICOM_TAG_ACCESSION_NUMBER, - DICOM_TAG_STUDY_INSTANCE_UID, - DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, // New in db v6 - DICOM_TAG_INSTITUTION_NAME, // New in db v6 - DICOM_TAG_REQUESTING_PHYSICIAN, // New in db v6 - DICOM_TAG_REFERRING_PHYSICIAN_NAME // New in db v6 + // { DicomTag(0x0010, 0x1010), "PatientAge" }, + // { DicomTag(0x0010, 0x1040), "PatientAddress" }, + { DicomTag(0x0010, 0x0010), "PatientName" }, + { DicomTag(0x0010, 0x0030), "PatientBirthDate" }, + { DicomTag(0x0010, 0x0040), "PatientSex" }, + { DicomTag(0x0010, 0x1000), "OtherPatientIDs" }, + { DICOM_TAG_PATIENT_ID, "PatientID" } }; + + static const MainDicomTag STUDY_MAIN_DICOM_TAGS[] = + { + // { DicomTag(0x0010, 0x1020), "PatientSize" }, + // { DicomTag(0x0010, 0x1030), "PatientWeight" }, + { DICOM_TAG_STUDY_DATE, "StudyDate" }, + { DicomTag(0x0008, 0x0030), "StudyTime" }, + { DicomTag(0x0020, 0x0010), "StudyID" }, + { DICOM_TAG_STUDY_DESCRIPTION, "StudyDescription" }, + { DICOM_TAG_ACCESSION_NUMBER, "AccessionNumber" }, + { DICOM_TAG_STUDY_INSTANCE_UID, "StudyInstanceUID" }, - static DicomTag seriesTags[] = + // New in db v6 + { DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, "RequestedProcedureDescription" }, + { DICOM_TAG_INSTITUTION_NAME, "InstitutionName" }, + { DICOM_TAG_REQUESTING_PHYSICIAN, "RequestingPhysician" }, + { DICOM_TAG_REFERRING_PHYSICIAN_NAME, "ReferringPhysicianName" } + }; + + static const MainDicomTag SERIES_MAIN_DICOM_TAGS[] = { - //DicomTag(0x0010, 0x1080), // MilitaryRank - DicomTag(0x0008, 0x0021), // SeriesDate - DicomTag(0x0008, 0x0031), // SeriesTime - DICOM_TAG_MODALITY, - DicomTag(0x0008, 0x0070), // Manufacturer - DicomTag(0x0008, 0x1010), // StationName - DICOM_TAG_SERIES_DESCRIPTION, - DicomTag(0x0018, 0x0015), // BodyPartExamined - DicomTag(0x0018, 0x0024), // SequenceName - DicomTag(0x0018, 0x1030), // ProtocolName - DicomTag(0x0020, 0x0011), // SeriesNumber - DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, - DICOM_TAG_IMAGES_IN_ACQUISITION, - DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, - DICOM_TAG_NUMBER_OF_SLICES, - DICOM_TAG_NUMBER_OF_TIME_SLICES, - DICOM_TAG_SERIES_INSTANCE_UID, - DICOM_TAG_IMAGE_ORIENTATION_PATIENT, // New in db v6 - DICOM_TAG_SERIES_TYPE, // New in db v6 - DICOM_TAG_OPERATOR_NAME, // New in db v6 - DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, // New in db v6 - DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, // New in db v6 - DICOM_TAG_CONTRAST_BOLUS_AGENT // New in db v6 + // { DicomTag(0x0010, 0x1080), "MilitaryRank" }, + { DicomTag(0x0008, 0x0021), "SeriesDate" }, + { DicomTag(0x0008, 0x0031), "SeriesTime" }, + { DICOM_TAG_MODALITY, "Modality" }, + { DicomTag(0x0008, 0x0070), "Manufacturer" }, + { DicomTag(0x0008, 0x1010), "StationName" }, + { DICOM_TAG_SERIES_DESCRIPTION, "SeriesDescription" }, + { DicomTag(0x0018, 0x0015), "BodyPartExamined" }, + { DicomTag(0x0018, 0x0024), "SequenceName" }, + { DicomTag(0x0018, 0x1030), "ProtocolName" }, + { DicomTag(0x0020, 0x0011), "SeriesNumber" }, + { DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, "CardiacNumberOfImages" }, + { DICOM_TAG_IMAGES_IN_ACQUISITION, "ImagesInAcquisition" }, + { DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "NumberOfTemporalPositions" }, + { DICOM_TAG_NUMBER_OF_SLICES, "NumberOfSlices" }, + { DICOM_TAG_NUMBER_OF_TIME_SLICES, "NumberOfTimeSlices" }, + { DICOM_TAG_SERIES_INSTANCE_UID, "SeriesInstanceUID" }, + + // New in db v6 + { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" }, + { DICOM_TAG_SERIES_TYPE, "SeriesType" }, + { DICOM_TAG_OPERATOR_NAME, "OperatorsName" }, + { DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "PerformedProcedureStepDescription" }, + { DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, "AcquisitionDeviceProcessingDescription" }, + { DICOM_TAG_CONTRAST_BOLUS_AGENT, "ContrastBolusAgent" } }; - - static DicomTag instanceTags[] = + + static const MainDicomTag INSTANCE_MAIN_DICOM_TAGS[] = { - DicomTag(0x0008, 0x0012), // InstanceCreationDate - DicomTag(0x0008, 0x0013), // InstanceCreationTime - DicomTag(0x0020, 0x0012), // AcquisitionNumber - DICOM_TAG_IMAGE_INDEX, - DICOM_TAG_INSTANCE_NUMBER, - DICOM_TAG_NUMBER_OF_FRAMES, - DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, - DICOM_TAG_SOP_INSTANCE_UID, - DICOM_TAG_IMAGE_POSITION_PATIENT, // New in db v6 - DICOM_TAG_IMAGE_COMMENTS, // New in db v6 + { DicomTag(0x0008, 0x0012), "InstanceCreationDate" }, + { DicomTag(0x0008, 0x0013), "InstanceCreationTime" }, + { DicomTag(0x0020, 0x0012), "AcquisitionNumber" }, + { DICOM_TAG_IMAGE_INDEX, "ImageIndex" }, + { DICOM_TAG_INSTANCE_NUMBER, "InstanceNumber" }, + { DICOM_TAG_NUMBER_OF_FRAMES, "NumberOfFrames" }, + { DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, "TemporalPositionIdentifier" }, + { DICOM_TAG_SOP_INSTANCE_UID, "SOPInstanceUID" }, + + // New in db v6 + { DICOM_TAG_IMAGE_POSITION_PATIENT, "ImagePositionPatient" }, + { DICOM_TAG_IMAGE_COMMENTS, "ImageComments" }, /** * Main DICOM tags that are not part of any release of the @@ -120,34 +135,34 @@ * access these tags if the corresponding DICOM files where * indexed in the database by an older version of Orthanc. **/ - DICOM_TAG_IMAGE_ORIENTATION_PATIENT // New in Orthanc 1.4.2 + { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" } // New in Orthanc 1.4.2 }; - static void LoadMainDicomTags(const DicomTag*& tags, + static void LoadMainDicomTags(const MainDicomTag*& tags, size_t& size, ResourceType level) { switch (level) { case ResourceType_Patient: - tags = patientTags; - size = sizeof(patientTags) / sizeof(DicomTag); + tags = PATIENT_MAIN_DICOM_TAGS; + size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); break; case ResourceType_Study: - tags = studyTags; - size = sizeof(studyTags) / sizeof(DicomTag); + tags = STUDY_MAIN_DICOM_TAGS; + size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); break; case ResourceType_Series: - tags = seriesTags; - size = sizeof(seriesTags) / sizeof(DicomTag); + tags = SERIES_MAIN_DICOM_TAGS; + size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); break; case ResourceType_Instance: - tags = instanceTags; - size = sizeof(instanceTags) / sizeof(DicomTag); + tags = INSTANCE_MAIN_DICOM_TAGS; + size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); break; default: @@ -156,55 +171,106 @@ } - void DicomMap::SetValue(uint16_t group, - uint16_t element, - DicomValue* value) + static void LoadMainDicomTags(std::map<DicomTag, std::string>& target, + ResourceType level) + { + const MainDicomTag* tags = NULL; + size_t size; + LoadMainDicomTags(tags, size, level); + + assert(tags != NULL && + size != 0); + + for (size_t i = 0; i < size; i++) + { + assert(target.find(tags[i].tag_) == target.end()); + + target[tags[i].tag_] = tags[i].name_; + } + } + + + namespace + { + class DicomTag2 : public DicomTag + { + public: + DicomTag2() : + DicomTag(0, 0) // To make std::map<> happy + { + } + + DicomTag2(const DicomTag& tag) : + DicomTag(tag) + { + } + }; + } + + + static void LoadMainDicomTags(std::map<std::string, DicomTag2>& target, + ResourceType level) + { + const MainDicomTag* tags = NULL; + size_t size; + LoadMainDicomTags(tags, size, level); + + assert(tags != NULL && + size != 0); + + for (size_t i = 0; i < size; i++) + { + assert(target.find(tags[i].name_) == target.end()); + + target[tags[i].name_] = tags[i].tag_; + } + } + + + void DicomMap::SetValueInternal(uint16_t group, + uint16_t element, + DicomValue* value) { DicomTag tag(group, element); - Map::iterator it = map_.find(tag); + Content::iterator it = content_.find(tag); - if (it != map_.end()) + if (it != content_.end()) { delete it->second; it->second = value; } else { - map_.insert(std::make_pair(tag, value)); + content_.insert(std::make_pair(tag, value)); } } - void DicomMap::SetValue(DicomTag tag, - DicomValue* value) - { - SetValue(tag.GetGroup(), tag.GetElement(), value); - } - void DicomMap::Clear() { - for (Map::iterator it = map_.begin(); it != map_.end(); ++it) + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) { assert(it->second != NULL); delete it->second; } - map_.clear(); + content_.clear(); } - void DicomMap::ExtractTags(DicomMap& result, - const DicomTag* tags, - size_t count) const + static void ExtractTags(DicomMap& result, + const DicomMap::Content& source, + const MainDicomTag* tags, + size_t count) { result.Clear(); for (unsigned int i = 0; i < count; i++) { - Map::const_iterator it = map_.find(tags[i]); - if (it != map_.end()) + DicomMap::Content::const_iterator it = source.find(tags[i].tag_); + if (it != source.end()) { - result.SetValue(it->first, it->second->Clone()); + result.SetValue(it->first, *it->second /* value will be cloned */); } } } @@ -212,22 +278,22 @@ void DicomMap::ExtractPatientInformation(DicomMap& result) const { - ExtractTags(result, patientTags, sizeof(patientTags) / sizeof(DicomTag)); + ExtractTags(result, content_, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); } void DicomMap::ExtractStudyInformation(DicomMap& result) const { - ExtractTags(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); + ExtractTags(result, content_, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); } void DicomMap::ExtractSeriesInformation(DicomMap& result) const { - ExtractTags(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); + ExtractTags(result, content_, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); } void DicomMap::ExtractInstanceInformation(DicomMap& result) const { - ExtractTags(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); + ExtractTags(result, content_, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); } @@ -236,9 +302,9 @@ { std::auto_ptr<DicomMap> result(new DicomMap); - for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) { - result->map_.insert(std::make_pair(it->first, it->second->Clone())); + result->content_.insert(std::make_pair(it->first, it->second->Clone())); } return result.release(); @@ -249,9 +315,9 @@ { Clear(); - for (Map::const_iterator it = other.map_.begin(); it != other.map_.end(); ++it) + for (Content::const_iterator it = other.content_.begin(); it != other.content_.end(); ++it) { - map_.insert(std::make_pair(it->first, it->second->Clone())); + content_.insert(std::make_pair(it->first, it->second->Clone())); } } @@ -273,9 +339,9 @@ const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const { - Map::const_iterator it = map_.find(tag); + Content::const_iterator it = content_.find(tag); - if (it == map_.end()) + if (it == content_.end()) { return NULL; } @@ -288,35 +354,35 @@ void DicomMap::Remove(const DicomTag& tag) { - Map::iterator it = map_.find(tag); - if (it != map_.end()) + Content::iterator it = content_.find(tag); + if (it != content_.end()) { delete it->second; - map_.erase(it); + content_.erase(it); } } static void SetupFindTemplate(DicomMap& result, - const DicomTag* tags, + const MainDicomTag* tags, size_t count) { result.Clear(); for (size_t i = 0; i < count; i++) { - result.SetValue(tags[i], "", false); + result.SetValue(tags[i].tag_, "", false); } } void DicomMap::SetupFindPatientTemplate(DicomMap& result) { - SetupFindTemplate(result, patientTags, sizeof(patientTags) / sizeof(DicomTag)); + SetupFindTemplate(result, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); } void DicomMap::SetupFindStudyTemplate(DicomMap& result) { - SetupFindTemplate(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); + SetupFindTemplate(result, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); result.SetValue(DICOM_TAG_PATIENT_ID, "", false); @@ -329,7 +395,7 @@ void DicomMap::SetupFindSeriesTemplate(DicomMap& result) { - SetupFindTemplate(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); + SetupFindTemplate(result, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); @@ -351,7 +417,7 @@ void DicomMap::SetupFindInstanceTemplate(DicomMap& result) { - SetupFindTemplate(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); + SetupFindTemplate(result, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); @@ -371,38 +437,13 @@ bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level) { - DicomTag *tags = NULL; + const MainDicomTag *tags = NULL; size_t size; - - switch (level) - { - case ResourceType_Patient: - tags = patientTags; - size = sizeof(patientTags) / sizeof(DicomTag); - break; - - case ResourceType_Study: - tags = studyTags; - size = sizeof(studyTags) / sizeof(DicomTag); - break; - - case ResourceType_Series: - tags = seriesTags; - size = sizeof(seriesTags) / sizeof(DicomTag); - break; - - case ResourceType_Instance: - tags = instanceTags; - size = sizeof(instanceTags) / sizeof(DicomTag); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } + LoadMainDicomTags(tags, size, level); for (size_t i = 0; i < size; i++) { - if (tags[i] == tag) + if (tags[i].tag_ == tag) { return true; } @@ -422,38 +463,13 @@ void DicomMap::GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level) { - DicomTag *tags = NULL; + const MainDicomTag *tags = NULL; size_t size; - - switch (level) - { - case ResourceType_Patient: - tags = patientTags; - size = sizeof(patientTags) / sizeof(DicomTag); - break; - - case ResourceType_Study: - tags = studyTags; - size = sizeof(studyTags) / sizeof(DicomTag); - break; - - case ResourceType_Series: - tags = seriesTags; - size = sizeof(seriesTags) / sizeof(DicomTag); - break; - - case ResourceType_Instance: - tags = instanceTags; - size = sizeof(instanceTags) / sizeof(DicomTag); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } + LoadMainDicomTags(tags, size, level); for (size_t i = 0; i < size; i++) { - result.insert(tags[i]); + result.insert(tags[i].tag_); } } @@ -479,8 +495,8 @@ { tags.clear(); - for (Map::const_iterator it = map_.begin(); - it != map_.end(); ++it) + for (Content::const_iterator it = content_.begin(); + it != content_.end(); ++it) { tags.insert(it->first); } @@ -1030,14 +1046,14 @@ void DicomMap::Merge(const DicomMap& other) { - for (Map::const_iterator it = other.map_.begin(); - it != other.map_.end(); ++it) + for (Content::const_iterator it = other.content_.begin(); + it != other.content_.end(); ++it) { assert(it->second != NULL); - if (map_.find(it->first) == map_.end()) + if (content_.find(it->first) == content_.end()) { - map_[it->first] = it->second->Clone(); + content_[it->first] = it->second->Clone(); } } } @@ -1046,7 +1062,7 @@ void DicomMap::ExtractMainDicomTagsInternal(const DicomMap& other, ResourceType level) { - const DicomTag* tags = NULL; + const MainDicomTag* tags = NULL; size_t size = 0; LoadMainDicomTags(tags, size, level); @@ -1054,13 +1070,13 @@ for (size_t i = 0; i < size; i++) { - Map::const_iterator found = other.map_.find(tags[i]); + Content::const_iterator found = other.content_.find(tags[i].tag_); - if (found != other.map_.end() && - map_.find(tags[i]) == map_.end()) + if (found != other.content_.end() && + content_.find(tags[i].tag_) == content_.end()) { assert(found->second != NULL); - map_[tags[i]] = found->second->Clone(); + content_[tags[i].tag_] = found->second->Clone(); } } } @@ -1083,7 +1099,7 @@ std::set<DicomTag> mainDicomTags; GetMainDicomTags(mainDicomTags); - for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) { if (mainDicomTags.find(it->first) == mainDicomTags.end()) { @@ -1099,7 +1115,7 @@ { target = Json::objectValue; - for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) { assert(it->second != NULL); @@ -1129,7 +1145,7 @@ DicomTag tag(0, 0); if (!DicomTag::ParseHexadecimal(tag, tags[i].c_str()) || - map_.find(tag) != map_.end()) + content_.find(tag) != content_.end()) { throw OrthancException(ErrorCode_BadFileFormat); } @@ -1137,7 +1153,7 @@ std::auto_ptr<DicomValue> value(new DicomValue); value->Unserialize(source[tags[i]]); - map_[tag] = value.release(); + content_[tag] = value.release(); } } @@ -1296,9 +1312,9 @@ void DicomMap::RemoveBinaryTags() { - Map kept; + Content kept; - for (Map::iterator it = map_.begin(); it != map_.end(); ++it) + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) { assert(it->second != NULL); @@ -1313,22 +1329,67 @@ } } - map_ = kept; + content_ = kept; } void DicomMap::DumpMainDicomTags(Json::Value& target, ResourceType level) const { + std::map<DicomTag, std::string> mainTags; // TODO - Create a singleton to hold this map + LoadMainDicomTags(mainTags, level); + target = Json::objectValue; - + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) + { + assert(it->second != NULL); + + if (!it->second->IsBinary() && + !it->second->IsNull()) + { + std::map<DicomTag, std::string>::const_iterator found = mainTags.find(it->first); + + if (found != mainTags.end()) + { + target[found->second] = it->second->GetContent(); + } + } + } } - void DicomMap::ParseMainDicomTags(Json::Value& target, + void DicomMap::ParseMainDicomTags(const Json::Value& source, ResourceType level) { + if (source.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + Clear(); + + std::map<std::string, DicomTag2> mainTags; // TODO - Create a singleton to hold this map + LoadMainDicomTags(mainTags, level); + + Json::Value::Members members = source.getMemberNames(); + for (size_t i = 0; i < members.size(); i++) + { + std::map<std::string, DicomTag2>::const_iterator found = mainTags.find(members[i]); + + if (found != mainTags.end()) + { + const Json::Value& value = source[members[i]]; + if (value.type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + SetValue(found->second, value.asString(), false); + } + } + } }
--- a/Core/DicomFormat/DicomMap.h Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomFormat/DicomMap.h Wed Feb 05 13:22:02 2020 +0100 @@ -45,28 +45,23 @@ { class DicomMap : public boost::noncopyable { + public: + typedef std::map<DicomTag, DicomValue*> Content; + private: friend class DicomArray; friend class FromDcmtkBridge; friend class ParsedDicomFile; - typedef std::map<DicomTag, DicomValue*> Map; - - Map map_; + Content content_; // Warning: This takes the ownership of "value" - void SetValue(uint16_t group, - uint16_t element, - DicomValue* value); + void SetValueInternal(uint16_t group, + uint16_t element, + DicomValue* value); - void SetValue(DicomTag tag, - DicomValue* value); - - void ExtractTags(DicomMap& source, - const DicomTag* tags, - size_t count) const; - - static void GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level); + static void GetMainDicomTagsInternal(std::set<DicomTag>& result, + ResourceType level); void ExtractMainDicomTagsInternal(const DicomMap& other, ResourceType level); @@ -83,7 +78,7 @@ size_t GetSize() const { - return map_.size(); + return content_.size(); } DicomMap* Clone() const; @@ -95,32 +90,32 @@ void SetNullValue(uint16_t group, uint16_t element) { - SetValue(group, element, new DicomValue); + SetValueInternal(group, element, new DicomValue); } void SetNullValue(const DicomTag& tag) { - SetValue(tag, new DicomValue); + SetValueInternal(tag.GetGroup(), tag.GetElement(), new DicomValue); } void SetValue(uint16_t group, uint16_t element, const DicomValue& value) { - SetValue(group, element, value.Clone()); + SetValueInternal(group, element, value.Clone()); } void SetValue(const DicomTag& tag, const DicomValue& value) { - SetValue(tag, value.Clone()); + SetValueInternal(tag.GetGroup(), tag.GetElement(), value.Clone()); } void SetValue(const DicomTag& tag, const std::string& str, bool isBinary) { - SetValue(tag, new DicomValue(str, isBinary)); + SetValueInternal(tag.GetGroup(), tag.GetElement(), new DicomValue(str, isBinary)); } void SetValue(uint16_t group, @@ -128,7 +123,7 @@ const std::string& str, bool isBinary) { - SetValue(group, element, new DicomValue(str, isBinary)); + SetValueInternal(group, element, new DicomValue(str, isBinary)); } bool HasTag(uint16_t group, uint16_t element) const @@ -138,7 +133,7 @@ bool HasTag(const DicomTag& tag) const { - return map_.find(tag) != map_.end(); + return content_.find(tag) != content_.end(); } const DicomValue& GetValue(uint16_t group, uint16_t element) const @@ -239,7 +234,7 @@ void DumpMainDicomTags(Json::Value& target, ResourceType level) const; - void ParseMainDicomTags(Json::Value& target, + void ParseMainDicomTags(const Json::Value& source, ResourceType level); void Print(FILE* fp) const; // For debugging only
--- a/Core/DicomFormat/DicomTag.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomFormat/DicomTag.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -187,6 +187,10 @@ if (*this == DICOM_TAG_IMAGE_ORIENTATION_PATIENT) return "ImageOrientationPatient"; + // New in Orthanc 1.6.0, as tagged as "RETIRED_" since DCMTK 3.6.4 + if (*this == DICOM_TAG_OTHER_PATIENT_IDS) + return "OtherPatientIDs"; + return ""; }
--- a/Core/DicomFormat/DicomTag.h Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomFormat/DicomTag.h Wed Feb 05 13:22:02 2020 +0100 @@ -191,6 +191,7 @@ static const DicomTag DICOM_TAG_PATIENT_COMMENTS(0x0010, 0x4000); static const DicomTag DICOM_TAG_PATIENT_SPECIES_DESCRIPTION(0x0010, 0x2201); static const DicomTag DICOM_TAG_STUDY_COMMENTS(0x0032, 0x4000); + static const DicomTag DICOM_TAG_OTHER_PATIENT_IDS(0x0010, 0x1000); // Tags used within the Stone of Orthanc static const DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009);
--- a/Core/DicomParsing/FromDcmtkBridge.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -468,10 +468,10 @@ DcmElement* element = dataset.getElement(i); if (element && element->isLeaf()) { - target.SetValue(element->getTag().getGTag(), - element->getTag().getETag(), - ConvertLeafElement(*element, DicomToJsonFlags_Default, - maxStringLength, encoding, hasCodeExtensions, ignoreTagLength)); + target.SetValueInternal(element->getTag().getGTag(), + element->getTag().getETag(), + ConvertLeafElement(*element, DicomToJsonFlags_Default, + maxStringLength, encoding, hasCodeExtensions, ignoreTagLength)); } } } @@ -1117,8 +1117,8 @@ result.clear(); - for (DicomMap::Map::const_iterator - it = values.map_.begin(); it != values.map_.end(); ++it) + for (DicomMap::Content::const_iterator + it = values.content_.begin(); it != values.content_.end(); ++it) { // TODO Inject PrivateCreator if some is available in the DicomMap? const std::string tagName = GetTagName(it->first, "");
--- a/Core/DicomParsing/FromDcmtkBridge.h Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.h Wed Feb 05 13:22:02 2020 +0100 @@ -192,7 +192,8 @@ const std::string& tagName, DicomValue* value) { - target.SetValue(ParseTag(tagName), value); + const DicomTag tag = ParseTag(tagName); + target.SetValueInternal(tag.GetGroup(), tag.GetElement(), value); } static void ToJson(Json::Value& result,
--- a/Core/DicomParsing/ParsedDicomFile.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/Core/DicomParsing/ParsedDicomFile.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -1007,8 +1007,8 @@ } } - for (DicomMap::Map::const_iterator - it = source.map_.begin(); it != source.map_.end(); ++it) + for (DicomMap::Content::const_iterator + it = source.content_.begin(); it != source.content_.end(); ++it) { if (it->first != DICOM_TAG_SPECIFIC_CHARACTER_SET && !it->second->IsNull())
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -1106,8 +1106,6 @@ static void PeerSystem(RestApiGetCall& call) { - ServerContext& context = OrthancRestApi::GetContext(call); - std::string remote = call.GetUriComponent("id", ""); OrthancConfiguration::ReaderLock lock;
--- a/UnitTestsSources/DicomMapTests.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/UnitTestsSources/DicomMapTests.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -991,3 +991,44 @@ ASSERT_TRUE(target.LookupStringValue(s, DICOM_TAG_PIXEL_SPACING, false)); ASSERT_EQ(s, "1.5\\1.3"); } + + +TEST(DicomMap, MainTagNames) +{ + ASSERT_EQ(3, ResourceType_Instance - ResourceType_Patient); + + for (int i = ResourceType_Patient; i <= ResourceType_Instance; i++) + { + ResourceType level = static_cast<ResourceType>(i); + + std::set<DicomTag> tags; + DicomMap::GetMainDicomTags(tags, level); + + for (std::set<DicomTag>::const_iterator it = tags.begin(); it != tags.end(); ++it) + { + DicomMap a; + a.SetValue(*it, "TEST", false); + + Json::Value json; + a.DumpMainDicomTags(json, level); + + ASSERT_EQ(Json::objectValue, json.type()); + ASSERT_EQ(1u, json.getMemberNames().size()); + + std::string name = json.getMemberNames() [0]; + EXPECT_EQ(name, FromDcmtkBridge::GetTagName(*it, "")); + + DicomMap b; + b.ParseMainDicomTags(json, level); + + ASSERT_EQ(1u, b.GetSize()); + ASSERT_EQ("TEST", b.GetStringValue(*it, "", false)); + + std::string main = it->GetMainTagsName(); + if (!main.empty()) + { + ASSERT_EQ(main, name); + } + } + } +}
--- a/UnitTestsSources/ImageProcessingTests.cpp Wed Feb 05 11:52:10 2020 +0100 +++ b/UnitTestsSources/ImageProcessingTests.cpp Wed Feb 05 13:22:02 2020 +0100 @@ -896,7 +896,7 @@ TEST(ImageProcessing, ApplyWindowingGrayScale8ToGrayScale16) { { - Image image(PixelFormat_Grayscale8, 6, 1, false); + Image image(PixelFormat_Grayscale8, 5, 1, false); SetGrayscale8Pixel(image, 0, 0, 0); SetGrayscale8Pixel(image, 1, 0, 2); SetGrayscale8Pixel(image, 2, 0, 5); @@ -904,7 +904,7 @@ SetGrayscale8Pixel(image, 4, 0, 255); { - Image target(PixelFormat_Grayscale16, 6, 1, false); + Image target(PixelFormat_Grayscale16, 5, 1, false); ImageProcessing::ApplyWindowing(target, image, 5.0f, 10.0f, 1.0f, 0.0f, false); ASSERT_TRUE(TestGrayscale16Pixel(target, 0, 0, 0)); @@ -919,7 +919,7 @@ TEST(ImageProcessing, ApplyWindowingGrayScale16ToGrayScale16) { { - Image image(PixelFormat_Grayscale16, 6, 1, false); + Image image(PixelFormat_Grayscale16, 5, 1, false); SetGrayscale16Pixel(image, 0, 0, 0); SetGrayscale16Pixel(image, 1, 0, 2); SetGrayscale16Pixel(image, 2, 0, 5); @@ -927,7 +927,7 @@ SetGrayscale16Pixel(image, 4, 0, 255); { - Image target(PixelFormat_Grayscale16, 6, 1, false); + Image target(PixelFormat_Grayscale16, 5, 1, false); ImageProcessing::ApplyWindowing(target, image, 5.0f, 10.0f, 1.0f, 0.0f, false); ASSERT_TRUE(TestGrayscale16Pixel(target, 0, 0, 0));