# HG changeset patch # User Sebastien Jodogne # Date 1449051725 -3600 # Node ID 4e7c318a3f6977d4616004be333b3ebce5861fc3 # Parent 36ab170733d622403c9347f4dd033bb8eb08e5e2 C-FIND SCP will return tags with sequence value representation diff -r 36ab170733d6 -r 4e7c318a3f69 NEWS --- a/NEWS Tue Dec 01 16:57:03 2015 +0100 +++ b/NEWS Wed Dec 02 11:22:05 2015 +0100 @@ -4,8 +4,8 @@ Major ----- -* Experimental support of DICOM C-Find SCP for modality worklists through plugins -* Support of DICOM C-Find SCU for modality worklists ("/modalities/{dicom}/find-worklist") +* Experimental support of DICOM C-FIND SCP for modality worklists through plugins +* Support of DICOM C-FIND SCU for modality worklists ("/modalities/{dicom}/find-worklist") REST API -------- @@ -64,15 +64,16 @@ Maintenance ----------- -* Full indexation of the patient/study tags to speed up searches and C-Find +* Full indexation of the patient/study tags to speed up searches and C-FIND * Many refactorings, notably of the searching features and of the image decoding -* C-Move SCP for studies using AccessionNumber tag -* Fix issue 4 (C-Store Association not renegotiated on Specific-to-specific transfer syntax change) +* C-MOVE SCP for studies using AccessionNumber tag +* Fix issue 4 (C-STORE Association not renegotiated on Specific-to-specific transfer syntax change) * Fix formatting of multipart HTTP answers * "--logdir" flag creates a single log file instead of 3 separate files for errors/warnings/infos * "--errors" flag lists the error codes that could be returned by Orthanc * Under Windows, the exit status of Orthanc corresponds to the encountered error code * New "AgfaImpax", "EFilm2" and "Vitrea" modality manufacturers +* C-FIND SCP will return tags with sequence value representation * Upgrade to Boost 1.59.0 for static builds @@ -148,7 +149,7 @@ ------- * The configuration can be splitted into several files stored inside the same folder -* Custom setting of the local AET during C-Store SCU (both in Lua and in the REST API) +* Custom setting of the local AET during C-STORE SCU (both in Lua and in the REST API) * Many code refactorings Lua @@ -167,9 +168,9 @@ Fixes ----- -* Fix compatibility issues for C-Find SCU to Siemens Syngo.Via modalities SCP +* Fix compatibility issues for C-FIND SCU to Siemens Syngo.Via modalities SCP * Fix issue 15 (Lua scripts making HTTP requests) -* Fix issue 35 (Characters in PatientID string are not protected for C-Find) +* Fix issue 35 (Characters in PatientID string are not protected for C-FIND) * Fix issue 37 (Hyphens trigger range query even if datatype does not support ranges) @@ -180,7 +181,7 @@ ----- * DICOM Query/Retrieve available from Orthanc Explorer -* C-Move SCU and C-Find SCU are accessible through the REST API +* C-MOVE SCU and C-FIND SCU are accessible through the REST API * "?expand" flag for URIs "/patients", "/studies" and "/series" * "/tools/find" URI to search for DICOM resources from REST * Support of FreeBSD @@ -190,15 +191,15 @@ ----- * Speed-up in Orthanc Explorer for large amount of images -* Speed-up of the C-Find SCP server of Orthanc +* Speed-up of the C-FIND SCP server of Orthanc * Allow replacing PatientID/StudyInstanceUID/SeriesInstanceUID from Lua scripts -* Option "CaseSensitivePN" to enable case-insensitive C-Find SCP +* Option "CaseSensitivePN" to enable case-insensitive C-FIND SCP Fixes ----- * Prevent freeze on C-FIND if no DICOM tag is to be returned -* Fix slow C-Store SCP on recent versions of Linux, if +* Fix slow C-STORE SCP on recent versions of Linux, if USE_SYSTEM_DCMTK is set to OFF (http://forum.dcmtk.org/viewtopic.php?f=1&t=4009) * Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052)) * Fix issue 32 (Cyrillic symbols): Introduction of the "Windows1251" encoding @@ -269,7 +270,7 @@ * "/instances-tags" to get the tags of all the child instances of a patient/study/series with a single REST call (bulk tags retrieval) -* Configuration/Lua to select the accepted C-Store SCP transfer syntaxes +* Configuration/Lua to select the accepted C-STORE SCP transfer syntaxes * Fix reporting of errors in Orthanc Explorer when sending images to peers/modalities * Installation of plugin SDK in CMake @@ -380,7 +381,7 @@ Version 0.7.5 (2014/05/08) ========================== -* Dynamic negotiation of SOP classes for C-Store SCU +* Dynamic negotiation of SOP classes for C-STORE SCU * Creation of DICOM instances using the REST API * Embedding of images within DICOM instances * Adding/removal/modification of remote modalities/peers through REST @@ -427,8 +428,8 @@ ========================== * Support of Query/Retrieve from medInria -* Accept more transfer syntaxes for C-Store SCP and SCU (notably JPEG) -* Create the meta-header when receiving files through C-Store SCP +* Accept more transfer syntaxes for C-STORE SCP and SCU (notably JPEG) +* Create the meta-header when receiving files through C-STORE SCP * Fixes and improvements thanks to the static analyzer cppcheck @@ -471,7 +472,7 @@ ========================== * Detection of stable patients/studies/series -* C-Find SCU at the instance level +* C-FIND SCU at the instance level * Link from modified to original resource in Orthanc Explorer * Fix of issue #8 * Anonymization of the medical alerts tag (0010,2000) @@ -581,7 +582,7 @@ * The patient/study/series/instances are now indexed by SHA-1 digests of their DICOM Instance IDs (and not by UUIDs anymore): The same DICOM objects are thus always identified by the same Orthanc IDs -* Log of exported instances through DICOM C-Store SCU ("/exported" URI) +* Log of exported instances through DICOM C-STORE SCU ("/exported" URI) * Full refactoring of the DB schema and of the REST API * Introduction of generic classes for REST APIs (in Core/RestApi) diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/DicomProtocol/IFindRequestHandler.h --- a/OrthancServer/DicomProtocol/IFindRequestHandler.h Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/DicomProtocol/IFindRequestHandler.h Wed Dec 02 11:22:05 2015 +0100 @@ -45,6 +45,7 @@ virtual void Handle(DicomFindAnswers& answers, const DicomMap& input, + const std::list& sequencesToReturn, const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) = 0; diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/Internals/FindScp.cpp --- a/OrthancServer/Internals/FindScp.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/Internals/FindScp.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -148,9 +148,30 @@ { if (data.findHandler_ != NULL) { + std::list sequencesToReturn; + + for (unsigned long i = 0; i < requestIdentifiers->card(); i++) + { + DcmElement* element = requestIdentifiers->getElement(i); + if (element && !element->isLeaf()) + { + const DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); + + DcmSequenceOfItems& sequence = dynamic_cast(*element); + if (sequence.card() != 0) + { + LOG(WARNING) << "Orthanc only supports sequence matching on worklists, " + << "ignoring C-FIND SCU constraint on tag (" << tag.Format() + << ") " << FromDcmtkBridge::GetName(tag); + } + + sequencesToReturn.push_back(tag); + } + } + DicomMap input; FromDcmtkBridge::Convert(input, *requestIdentifiers); - data.findHandler_->Handle(data.answers_, input, + data.findHandler_->Handle(data.answers_, input, sequencesToReturn, *data.remoteIp_, *data.remoteAet_, *data.calledAet_); ok = true; diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -47,19 +47,21 @@ { static void AddAnswer(DicomFindAnswers& answers, const Json::Value& resource, - const DicomArray& query) + const DicomArray& query, + const std::list& sequencesToReturn) { DicomMap result; for (size_t i = 0; i < query.GetSize(); i++) { - // Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052)) if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) { + // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); } else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) { + // Do not include the encoding, this is handled by class ParsedDicomFile } else { @@ -77,13 +79,46 @@ } } - if (result.GetSize() == 0) + if (result.GetSize() == 0 && + sequencesToReturn.empty()) { LOG(WARNING) << "The C-FIND request does not return any DICOM tag"; } + else if (sequencesToReturn.empty()) + { + answers.Add(result); + } else { - answers.Add(result); + ParsedDicomFile dicom(result); + + for (std::list::const_iterator tag = sequencesToReturn.begin(); + tag != sequencesToReturn.end(); ++tag) + { + std::cout << tag->Format(); + + const Json::Value& source = resource[tag->Format()]; + + if (source.type() == Json::objectValue && + source.isMember("Type") && + source.isMember("Value") && + source["Type"].asString() == "Sequence" && + source["Value"].type() == Json::arrayValue) + { + Json::Value content = Json::arrayValue; + + for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++) + { + Json::Value item; + Toolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short); + content.append(item); + } + + dicom.Replace(*tag, content, false); + } + } + + answers.Add(dicom); } } @@ -126,6 +161,7 @@ void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, const DicomMap& input, + const std::list& sequencesToReturn, const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) @@ -181,6 +217,14 @@ } } + for (std::list::const_iterator it = sequencesToReturn.begin(); + it != sequencesToReturn.end(); ++it) + { + LOG(INFO) << " (" << it->Format() + << ") " << FromDcmtkBridge::GetName(*it) + << " : sequence tag whose content will be copied"; + } + /** * Build up the query object. @@ -255,7 +299,7 @@ } else { - AddAnswer(answers, dicom, query); + AddAnswer(answers, dicom, query, sequencesToReturn); } } } diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/OrthancFindRequestHandler.h --- a/OrthancServer/OrthancFindRequestHandler.h Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/OrthancFindRequestHandler.h Wed Dec 02 11:22:05 2015 +0100 @@ -62,6 +62,7 @@ virtual void Handle(DicomFindAnswers& answers, const DicomMap& input, + const std::list& sequencesToReturn, const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet); diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -209,7 +209,7 @@ context.ReadJson(full, publicId); Json::Value simplified; - Toolbox::SimplifyTags(simplified, full); + Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Simple); call.GetOutput().AnswerJson(simplified); } else @@ -928,7 +928,7 @@ if (simplify) { Json::Value simplified; - Toolbox::SimplifyTags(simplified, sharedTags); + Toolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Simple); call.GetOutput().AnswerJson(simplified); } else @@ -995,7 +995,7 @@ if (simplify) { Json::Value simplified; - Toolbox::SimplifyTags(simplified, result); + Toolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Simple); call.GetOutput().AnswerJson(simplified); } else @@ -1201,7 +1201,7 @@ if (simplify) { Json::Value simplified; - Toolbox::SimplifyTags(simplified, full); + Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Simple); result[*it] = simplified; } else @@ -1295,7 +1295,7 @@ if (simplify) { Json::Value simplified; - Toolbox::SimplifyTags(simplified, header); + Toolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Simple); call.GetOutput().AnswerJson(simplified); } else diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/ServerContext.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -189,7 +189,7 @@ resultPublicId = hasher.HashInstance(); Json::Value simplifiedTags; - Toolbox::SimplifyTags(simplifiedTags, dicom.GetJson()); + Toolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Simple); // Test if the instance must be filtered out bool accepted = true; diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/ServerToolbox.cpp --- a/OrthancServer/ServerToolbox.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/ServerToolbox.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -47,7 +47,8 @@ namespace Toolbox { void SimplifyTags(Json::Value& target, - const Json::Value& source) + const Json::Value& source, + DicomToJsonFormat format) { assert(source.isObject()); @@ -57,9 +58,23 @@ for (size_t i = 0; i < members.size(); i++) { const Json::Value& v = source[members[i]]; - const std::string& name = v["Name"].asString(); const std::string& type = v["Type"].asString(); + std::string name; + switch (format) + { + case DicomToJsonFormat_Simple: + name = v["Name"].asString(); + break; + + case DicomToJsonFormat_Short: + name = members[i]; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + if (type == "String") { target[name] = v["Value"].asString(); @@ -78,7 +93,7 @@ for (Json::Value::ArrayIndex i = 0; i < array.size(); i++) { Json::Value c; - SimplifyTags(c, array[i]); + SimplifyTags(c, array[i], format); children.append(c); } diff -r 36ab170733d6 -r 4e7c318a3f69 OrthancServer/ServerToolbox.h --- a/OrthancServer/ServerToolbox.h Tue Dec 01 16:57:03 2015 +0100 +++ b/OrthancServer/ServerToolbox.h Wed Dec 02 11:22:05 2015 +0100 @@ -42,7 +42,8 @@ namespace Toolbox { void SimplifyTags(Json::Value& target, - const Json::Value& source); + const Json::Value& source, + DicomToJsonFormat format); void LogMissingRequiredTag(const DicomMap& summary); diff -r 36ab170733d6 -r 4e7c318a3f69 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/Plugins/Engine/OrthancPlugins.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -1187,7 +1187,7 @@ else { Json::Value simplified; - Toolbox::SimplifyTags(simplified, instance.GetJson()); + Toolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Simple); s = writer.write(simplified); } diff -r 36ab170733d6 -r 4e7c318a3f69 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Tue Dec 01 16:57:03 2015 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Wed Dec 02 11:22:05 2015 +0100 @@ -395,7 +395,7 @@ FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii); Json::Value c; - Toolbox::SimplifyTags(c, b); + Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Simple); a[1]["PatientName"] = "Hello2"; // To remove the Data URI Scheme encoding ASSERT_EQ(0, c["ReferencedStudySequence"].compare(a)); @@ -474,7 +474,7 @@ f.ToJson(b, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0); Json::Value c; - Toolbox::SimplifyTags(c, b); + Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Simple); ASSERT_EQ(0, c["ReferencedPatientSequence"].compare(a)); ASSERT_NE(0, c["ReferencedStudySequence"].compare(a)); // Because Data URI Scheme decoding was enabled