# HG changeset patch # User Sebastien Jodogne # Date 1544625753 -3600 # Node ID 8265a6b5610027a4fbbdd5f3f9d07a2f8b00e5f2 # Parent 80d1a345280745bd70a03cc0121ae6b3e9265341 DicomMap::FromDicomAsJson diff -r 80d1a3452807 -r 8265a6b56100 Core/DicomFormat/DicomMap.cpp --- a/Core/DicomFormat/DicomMap.cpp Wed Dec 12 09:08:34 2018 +0100 +++ b/Core/DicomFormat/DicomMap.cpp Wed Dec 12 15:42:33 2018 +0100 @@ -982,6 +982,45 @@ } + void DicomMap::FromDicomAsJson(const Json::Value& dicomAsJson) + { + Clear(); + + Json::Value::Members tags = dicomAsJson.getMemberNames(); + for (Json::Value::Members::const_iterator + it = tags.begin(); it != tags.end(); ++it) + { + DicomTag tag(0, 0); + if (!DicomTag::ParseHexadecimal(tag, it->c_str())) + { + throw OrthancException(ErrorCode_CorruptedFile); + } + + const Json::Value& value = dicomAsJson[*it]; + + if (value.type() != Json::objectValue || + !value.isMember("Type") || + !value.isMember("Value") || + value["Type"].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_CorruptedFile); + } + + if (value["Type"] == "String") + { + if (value["Value"].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_CorruptedFile); + } + else + { + SetValue(tag, value["Value"].asString(), false /* not binary */); + } + } + } + } + + void DicomMap::Serialize(Json::Value& target) const { target = Json::objectValue; diff -r 80d1a3452807 -r 8265a6b56100 Core/DicomFormat/DicomMap.h --- a/Core/DicomFormat/DicomMap.h Wed Dec 12 09:08:34 2018 +0100 +++ b/Core/DicomFormat/DicomMap.h Wed Dec 12 15:42:33 2018 +0100 @@ -217,6 +217,8 @@ bool ParseDouble(double& result, const DicomTag& tag) const; + void FromDicomAsJson(const Json::Value& dicomAsJson); + void Serialize(Json::Value& target) const; void Unserialize(const Json::Value& source); diff -r 80d1a3452807 -r 8265a6b56100 OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Wed Dec 12 09:08:34 2018 +0100 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Wed Dec 12 15:42:33 2018 +0100 @@ -690,52 +690,8 @@ size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; - -#if 1 LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn); context_.Apply(visitor, lookup, 0 /* "since" is not relevant to C-FIND */, limit); - -#else - // Backup - Implementation of Orthanc <= 1.5.0 - // TODO - Remove this code - - // TODO - Use ServerContext::Apply() at this point, in order to - // share the code with the "/tools/find" REST URI - std::vector resources, instances; - context_.GetIndex().FindCandidates(resources, instances, lookup); - - LOG(INFO) << "Number of candidate resources after fast DB filtering: " << resources.size(); - - assert(resources.size() == instances.size()); - bool complete = true; - - for (size_t i = 0; i < instances.size(); i++) - { - // TODO - Don't read the full JSON from the disk if only "main - // DICOM tags" are to be returned - Json::Value dicom; - context_.ReadDicomAsJson(dicom, instances[i]); - - if (lookup.IsMatch(dicom)) - { - if (limit != 0 && - answers.GetSize() >= limit) - { - complete = false; - break; - } - else - { - std::auto_ptr counters(ComputeCounters(context_, instances[i], level, *filteredInput)); - AddAnswer(answers, dicom, query, sequencesToReturn, counters.get()); - } - } - } - - LOG(INFO) << "Number of matching resources: " << answers.GetSize(); - - answers.SetComplete(complete); -#endif } diff -r 80d1a3452807 -r 8265a6b56100 OrthancServer/Search/LookupResource.cpp --- a/OrthancServer/Search/LookupResource.cpp Wed Dec 12 09:08:34 2018 +0100 +++ b/OrthancServer/Search/LookupResource.cpp Wed Dec 12 15:42:33 2018 +0100 @@ -113,6 +113,7 @@ } else { + // This is not a main DICOM tag return false; } } diff -r 80d1a3452807 -r 8265a6b56100 OrthancServer/Search/LookupResource.h --- a/OrthancServer/Search/LookupResource.h Wed Dec 12 09:08:34 2018 +0100 +++ b/OrthancServer/Search/LookupResource.h Wed Dec 12 15:42:33 2018 +0100 @@ -70,7 +70,7 @@ ResourceType level_; Levels levels_; - Constraints unoptimizedConstraints_; + Constraints unoptimizedConstraints_; // Constraints on non-main DICOM tags std::auto_ptr modalitiesInStudy_; bool AddInternal(ResourceType level, diff -r 80d1a3452807 -r 8265a6b56100 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Wed Dec 12 09:08:34 2018 +0100 +++ b/OrthancServer/ServerContext.cpp Wed Dec 12 15:42:33 2018 +0100 @@ -781,7 +781,7 @@ std::vector resources, instances; GetIndex().FindCandidates(resources, instances, lookup); - LOG(INFO) << "Number of candidate resources after fast DB filtering: " << resources.size(); + LOG(INFO) << "Number of candidate resources after fast DB filtering on main DICOM tags: " << resources.size(); assert(resources.size() == instances.size()); diff -r 80d1a3452807 -r 8265a6b56100 UnitTestsSources/DicomMapTests.cpp --- a/UnitTestsSources/DicomMapTests.cpp Wed Dec 12 09:08:34 2018 +0100 +++ b/UnitTestsSources/DicomMapTests.cpp Wed Dec 12 15:42:33 2018 +0100 @@ -37,8 +37,12 @@ #include "../Core/OrthancException.h" #include "../Core/DicomFormat/DicomMap.h" #include "../Core/DicomParsing/FromDcmtkBridge.h" +#include "../Core/DicomParsing/ParsedDicomFile.h" + +#include "../OrthancServer/DicomInstanceToStore.h" #include +#include using namespace Orthanc; @@ -409,3 +413,94 @@ ASSERT_THROW(v->GetContent(), OrthancException); } } + + + +TEST(DicomMap, DicomAsJson) +{ + // This is a Latin-1 test string: "crane" with a circumflex accent + const unsigned char raw[] = { 0x63, 0x72, 0xe2, 0x6e, 0x65 }; + std::string latin1((char*) &raw[0], sizeof(raw) / sizeof(char)); + + std::string utf8 = Toolbox::ConvertToUtf8(latin1, Encoding_Latin1); + + ParsedDicomFile dicom(false); + dicom.SetEncoding(Encoding_Latin1); + dicom.ReplacePlainString(DICOM_TAG_PATIENT_NAME, "Hello"); + dicom.ReplacePlainString(DICOM_TAG_STUDY_DESCRIPTION, utf8); + dicom.ReplacePlainString(DICOM_TAG_SERIES_DESCRIPTION, std::string(ORTHANC_MAXIMUM_TAG_LENGTH, 'a')); + dicom.ReplacePlainString(DICOM_TAG_MANUFACTURER, std::string(ORTHANC_MAXIMUM_TAG_LENGTH + 1, 'a')); + dicom.ReplacePlainString(DICOM_TAG_PIXEL_DATA, "binary"); + dicom.ReplacePlainString(DICOM_TAG_ROWS, "512"); + + DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset(); + dataset.insertEmptyElement(DCM_StudyID, OFFalse); + + { + std::auto_ptr sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence)); + + { + std::auto_ptr item(new DcmItem); + item->putAndInsertString(DCM_ReferencedSOPInstanceUID, "nope", OFFalse); + ASSERT_TRUE(sequence->insert(item.release(), false, false).good()); + } + + ASSERT_TRUE(dataset.insert(sequence.release(), false, false).good()); + } + + + // Check re-encoding + DcmElement* element = NULL; + ASSERT_TRUE(dataset.findAndGetElement(DCM_StudyDescription, element).good() && + element != NULL); + + char* c = NULL; + ASSERT_TRUE(element != NULL && + element->isLeaf() && + element->isaString() && + element->getString(c).good()); + ASSERT_EQ(0, memcmp(c, raw, latin1.length())); + + ASSERT_TRUE(dataset.findAndGetElement(DCM_Rows, element).good() && + element != NULL && + element->getTag().getEVR() == EVR_US); + + DicomInstanceToStore toStore; + toStore.SetParsedDicomFile(dicom); + + DicomMap m; + m.FromDicomAsJson(toStore.GetJson()); + + ASSERT_EQ("ISO_IR 100", m.GetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET).GetContent()); + + ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).IsBinary()); + ASSERT_EQ("Hello", m.GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); + + ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_DESCRIPTION).IsBinary()); + ASSERT_EQ(utf8, m.GetValue(DICOM_TAG_STUDY_DESCRIPTION).GetContent()); + + ASSERT_FALSE(m.HasTag(DICOM_TAG_MANUFACTURER)); // Too long + ASSERT_FALSE(m.HasTag(DICOM_TAG_PIXEL_DATA)); // Pixel data + ASSERT_FALSE(m.HasTag(DICOM_TAG_REFERENCED_SERIES_SEQUENCE)); // Sequence + ASSERT_EQ(DICOM_TAG_REFERENCED_SERIES_SEQUENCE.GetGroup(), DCM_ReferencedSeriesSequence.getGroup()); + ASSERT_EQ(DICOM_TAG_REFERENCED_SERIES_SEQUENCE.GetElement(), DCM_ReferencedSeriesSequence.getElement()); + + ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_DESCRIPTION)); // Maximum length + ASSERT_FALSE(m.GetValue(DICOM_TAG_SERIES_DESCRIPTION).IsBinary()); + ASSERT_EQ(ORTHANC_MAXIMUM_TAG_LENGTH, m.GetValue(DICOM_TAG_SERIES_DESCRIPTION).GetContent().length()); + + ASSERT_FALSE(m.GetValue(DICOM_TAG_ROWS).IsBinary()); + ASSERT_EQ("512", m.GetValue(DICOM_TAG_ROWS).GetContent()); + + ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_ID).IsNull()); + ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_ID).IsBinary()); + ASSERT_EQ("", m.GetValue(DICOM_TAG_STUDY_ID).GetContent()); + + DicomArray a(m); + ASSERT_EQ(6u, a.GetSize()); + + + //dicom.SaveToFile("/tmp/test.dcm"); + //std::cout << toStore.GetJson() << std::endl; + //a.Print(stdout); +}