# HG changeset patch # User Sebastien Jodogne # Date 1549388067 -3600 # Node ID 47ef29168698ace3db721c94a4bc2cd87ba25265 # Parent c6cfd502bf79010e4a86fb2383f33c3d66829e13 support of value multiplicity in ITagVisitor diff -r c6cfd502bf79 -r 47ef29168698 Core/DicomParsing/DicomModification.cpp --- a/Core/DicomParsing/DicomModification.cpp Tue Feb 05 17:00:45 2019 +0100 +++ b/Core/DicomParsing/DicomModification.cpp Tue Feb 05 18:34:27 2019 +0100 @@ -95,27 +95,27 @@ { } - virtual void VisitInteger(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - int64_t value) + virtual void VisitIntegers(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) { } - virtual void VisitDouble(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - double value) + virtual void VisitDoubles(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& value) { } - virtual void VisitAttribute(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const DicomTag& value) + virtual void VisitAttributes(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& value) { } diff -r c6cfd502bf79 -r 47ef29168698 Core/DicomParsing/FromDcmtkBridge.cpp --- a/Core/DicomParsing/FromDcmtkBridge.cpp Tue Feb 05 17:00:45 2019 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.cpp Tue Feb 05 18:34:27 2019 +0100 @@ -2265,67 +2265,121 @@ case EVR_SL: // signed long { - Sint32 f; - if (dynamic_cast(element).getSint32(f).good()) + DcmSignedLong& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); + Sint32 f; + if (content.getSint32(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); break; } case EVR_SS: // signed short { - Sint16 f; - if (dynamic_cast(element).getSint16(f).good()) + DcmSignedShort& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); + Sint16 f; + if (content.getSint16(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); break; } case EVR_UL: // unsigned long { - Uint32 f; - if (dynamic_cast(element).getUint32(f).good()) + DcmUnsignedLong& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); + Uint32 f; + if (content.getUint32(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); break; } case EVR_US: // unsigned short { - Uint16 f; - if (dynamic_cast(element).getUint16(f).good()) + DcmUnsignedShort& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); + Uint16 f; + if (content.getUint16(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); break; } case EVR_FL: // float single-precision { - Float32 f; - if (dynamic_cast(element).getFloat32(f).good()) + DcmFloatingPointSingle& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f); + Float32 f; + if (content.getFloat32(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values); break; } case EVR_FD: // float double-precision { - Float64 f; - if (dynamic_cast(element).getFloat64(f).good()) + DcmFloatingPointDouble& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f); + Float64 f; + if (content.getFloat64(f, i).good()) + { + values.push_back(f); + } } + visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values); break; } @@ -2336,13 +2390,22 @@ case EVR_AT: { - DcmTagKey tagKey; - if (dynamic_cast(element).getTagVal(tagKey, 0).good()) + DcmAttributeTag& content = dynamic_cast(element); + + std::vector values; + values.reserve(content.getVM()); + + for (unsigned long i = 0; i < content.getVM(); i++) { - DicomTag t(tagKey.getGroup(), tagKey.getElement()); - visitor.VisitAttribute(parentTags, parentIndexes, tag, vr, t); + DcmTagKey f; + if (content.getTagVal(f, i).good()) + { + DicomTag t(f.getGroup(), f.getElement()); + values.push_back(t); + } } + visitor.VisitAttributes(parentTags, parentIndexes, tag, vr, values); break; } diff -r c6cfd502bf79 -r 47ef29168698 Core/DicomParsing/ITagVisitor.h --- a/Core/DicomParsing/ITagVisitor.h Tue Feb 05 17:00:45 2019 +0100 +++ b/Core/DicomParsing/ITagVisitor.h Tue Feb 05 18:34:27 2019 +0100 @@ -65,23 +65,23 @@ const void* data, size_t size) = 0; - virtual void VisitInteger(const std::vector& parentTags, + virtual void VisitIntegers(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) = 0; + + virtual void VisitDoubles(const std::vector& parentTags, const std::vector& parentIndexes, const DicomTag& tag, ValueRepresentation vr, - int64_t value) = 0; + const std::vector& values) = 0; - virtual void VisitDouble(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - double value) = 0; - - virtual void VisitAttribute(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const DicomTag& value) = 0; + virtual void VisitAttributes(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) = 0; virtual Action VisitString(std::string& newValue, const std::vector& parentTags, diff -r c6cfd502bf79 -r 47ef29168698 UnitTestsSources/DicomMapTests.cpp --- a/UnitTestsSources/DicomMapTests.cpp Tue Feb 05 17:00:45 2019 +0100 +++ b/UnitTestsSources/DicomMapTests.cpp Tue Feb 05 18:34:27 2019 +0100 @@ -557,6 +557,8 @@ #if 0 +#include + namespace Orthanc { class DicomJsonVisitor : public ITagVisitor @@ -636,7 +638,35 @@ (*node) [t] = Json::objectValue; return (*node) [t]; } - } + } + + static Json::Value FormatInteger(int64_t value) + { + if (value < 0) + { + return Json::Value(static_cast(value)); + } + else + { + return Json::Value(static_cast(value)); + } + } + + static Json::Value FormatDouble(double value) + { + long long a = boost::math::llround(value); + + double d = fabs(value - static_cast(a)); + + if (d <= std::numeric_limits::epsilon() * 100.0) + { + return FormatInteger(a); + } + else + { + return Json::Value(value); + } + } public: DicomJsonVisitor() @@ -664,6 +694,8 @@ const DicomTag& tag, ValueRepresentation vr) ORTHANC_OVERRIDE { + Json::Value& node = CreateNode(parentTags, parentIndexes, tag); + node["vr"] = EnumerationToString(vr); } virtual void VisitBinary(const std::vector& parentTags, @@ -681,11 +713,11 @@ } } - virtual void VisitInteger(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - int64_t value) ORTHANC_OVERRIDE + virtual void VisitIntegers(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) ORTHANC_OVERRIDE { if (vr != ValueRepresentation_NotSupported) { @@ -693,23 +725,20 @@ node["vr"] = EnumerationToString(vr); Json::Value content = Json::arrayValue; - if (value < 0) + for (size_t i = 0; i < values.size(); i++) { - content.append(static_cast(value)); + content.append(FormatInteger(values[i])); } - else - { - content.append(static_cast(value)); - } + node["Value"] = content; } } - virtual void VisitDouble(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - double value) ORTHANC_OVERRIDE + virtual void VisitDoubles(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) ORTHANC_OVERRIDE { if (vr != ValueRepresentation_NotSupported) { @@ -717,21 +746,26 @@ node["vr"] = EnumerationToString(vr); Json::Value content = Json::arrayValue; - content.append(value); + for (size_t i = 0; i < values.size(); i++) + { + content.append(FormatDouble(values[i])); + } node["Value"] = content; } } - virtual void VisitAttribute(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const DicomTag& value) ORTHANC_OVERRIDE + virtual void VisitAttributes(const std::vector& parentTags, + const std::vector& parentIndexes, + const DicomTag& tag, + ValueRepresentation vr, + const std::vector& values) ORTHANC_OVERRIDE { if (vr != ValueRepresentation_NotSupported) { Json::Value& node = CreateNode(parentTags, parentIndexes, tag); node["vr"] = EnumerationToString(vr); + + } } @@ -768,27 +802,30 @@ case ValueRepresentation_IntegerString: { int64_t value = boost::lexical_cast(tokens[i]); - if (value < 0) - { - node["Value"].append(static_cast(value)); - } - else - { - node["Value"].append(static_cast(value)); - } + node["Value"].append(FormatInteger(value)); break; } case ValueRepresentation_DecimalString: { double value = boost::lexical_cast(tokens[i]); - node["Value"].append(value); + node["Value"].append(FormatDouble(value)); break; } default: + { + size_t l = tokens[i].size(); + + if (l > 0 && + tokens[i][l - 1] == '\0') + { + tokens[i] = tokens[i].substr(0, l - 1); + } + node["Value"].append(tokens[i]); break; + } } } catch (boost::bad_lexical_cast&) @@ -808,11 +845,16 @@ /* - cd /home/jodogne/Subversion/orthanc/s/dcmtk-3.6.2/i/bin - DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.2/dcmdata/data/dicom.dic ./dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm | python -mjson.tool > /tmp/a.json +cat << EOF > /tmp/tutu.py +import json +import sys +j = json.loads(sys.stdin.read().decode("utf-8-sig")) +print(json.dumps(j, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8')) +EOF - make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python -mjson.tool /tmp/tutu.json > /tmp/b.json - diff /tmp/a.json /tmp/b.json +DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.2/dcmdata/data/dicom.dic /home/jodogne/Downloads/dcmtk-3.6.2/i/bin/dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm | tr -d '\0' | sed 's/\\u0000//g' | sed 's/\.0$//' | python /tmp/tutu.py | grep -v 'InlineBinary' > /tmp/a.json + +make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python /tmp/tutu.py < /tmp/tutu.json > /tmp/b.json && diff -i /tmp/a.json /tmp/b.json */