Mercurial > hg > orthanc
comparison UnitTestsSources/DicomMapTests.cpp @ 3202:ef4d86d05503
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 06 Feb 2019 15:21:32 +0100 |
parents | b69fe409cb4d |
children | 810772486249 |
comparison
equal
deleted
inserted
replaced
3201:b69fe409cb4d | 3202:ef4d86d05503 |
---|---|
36 | 36 |
37 #include "../Core/OrthancException.h" | 37 #include "../Core/OrthancException.h" |
38 #include "../Core/DicomFormat/DicomMap.h" | 38 #include "../Core/DicomFormat/DicomMap.h" |
39 #include "../Core/DicomParsing/FromDcmtkBridge.h" | 39 #include "../Core/DicomParsing/FromDcmtkBridge.h" |
40 #include "../Core/DicomParsing/ParsedDicomFile.h" | 40 #include "../Core/DicomParsing/ParsedDicomFile.h" |
41 #include "../Core/DicomParsing/DicomWebJsonVisitor.h" | |
41 | 42 |
42 #include "../OrthancServer/DicomInstanceToStore.h" | 43 #include "../OrthancServer/DicomInstanceToStore.h" |
43 | 44 |
44 #include <memory> | 45 #include <memory> |
45 #include <dcmtk/dcmdata/dcdeftag.h> | 46 #include <dcmtk/dcmdata/dcdeftag.h> |
552 ASSERT_FALSE(b.HasOnlyMainDicomTags()); | 553 ASSERT_FALSE(b.HasOnlyMainDicomTags()); |
553 } | 554 } |
554 | 555 |
555 | 556 |
556 | 557 |
557 | |
558 | |
559 #include <boost/math/special_functions/round.hpp> | |
560 #include <pugixml.hpp> | |
561 | |
562 | |
563 static const char* const KEY_ALPHABETIC = "Alphabetic"; | |
564 static const char* const KEY_BULK_DATA_URI = "BulkDataURI"; | |
565 static const char* const KEY_INLINE_BINARY = "InlineBinary"; | |
566 static const char* const KEY_SQ = "SQ"; | |
567 static const char* const KEY_VALUE = "Value"; | |
568 static const char* const KEY_VR = "vr"; | |
569 | |
570 namespace Orthanc | |
571 { | |
572 static void ExploreDataset(pugi::xml_node& target, | |
573 const Json::Value& source) | |
574 { | |
575 assert(source.type() == Json::objectValue); | |
576 | |
577 Json::Value::Members members = source.getMemberNames(); | |
578 for (size_t i = 0; i < members.size(); i++) | |
579 { | |
580 const DicomTag tag = FromDcmtkBridge::ParseTag(members[i]); | |
581 const Json::Value& content = source[members[i]]; | |
582 | |
583 assert(content.type() == Json::objectValue && | |
584 content.isMember("vr") && | |
585 content["vr"].type() == Json::stringValue); | |
586 const std::string vr = content["vr"].asString(); | |
587 | |
588 const std::string keyword = FromDcmtkBridge::GetTagName(tag, ""); | |
589 | |
590 pugi::xml_node node = target.append_child("DicomAttribute"); | |
591 node.append_attribute("tag").set_value(members[i].c_str()); | |
592 node.append_attribute("vr").set_value(vr.c_str()); | |
593 | |
594 if (keyword != std::string(DcmTag_ERROR_TagName)) | |
595 { | |
596 node.append_attribute("keyword").set_value(keyword.c_str()); | |
597 } | |
598 | |
599 if (content.isMember(KEY_VALUE)) | |
600 { | |
601 assert(content[KEY_VALUE].type() == Json::arrayValue); | |
602 | |
603 for (Json::Value::ArrayIndex j = 0; j < content[KEY_VALUE].size(); j++) | |
604 { | |
605 std::string number = boost::lexical_cast<std::string>(j + 1); | |
606 | |
607 if (vr == "SQ") | |
608 { | |
609 if (content[KEY_VALUE][j].type() == Json::objectValue) | |
610 { | |
611 pugi::xml_node child = node.append_child("Item"); | |
612 child.append_attribute("number").set_value(number.c_str()); | |
613 ExploreDataset(child, content[KEY_VALUE][j]); | |
614 } | |
615 } | |
616 if (vr == "PN") | |
617 { | |
618 if (content[KEY_VALUE][j].isMember(KEY_ALPHABETIC) && | |
619 content[KEY_VALUE][j][KEY_ALPHABETIC].type() == Json::stringValue) | |
620 { | |
621 std::vector<std::string> tokens; | |
622 Toolbox::TokenizeString(tokens, content[KEY_VALUE][j][KEY_ALPHABETIC].asString(), '^'); | |
623 | |
624 pugi::xml_node child = node.append_child("PersonName"); | |
625 child.append_attribute("number").set_value(number.c_str()); | |
626 | |
627 pugi::xml_node name = child.append_child(KEY_ALPHABETIC); | |
628 | |
629 if (tokens.size() >= 1) | |
630 { | |
631 name.append_child("FamilyName").text() = tokens[0].c_str(); | |
632 } | |
633 | |
634 if (tokens.size() >= 2) | |
635 { | |
636 name.append_child("GivenName").text() = tokens[1].c_str(); | |
637 } | |
638 | |
639 if (tokens.size() >= 3) | |
640 { | |
641 name.append_child("MiddleName").text() = tokens[2].c_str(); | |
642 } | |
643 | |
644 if (tokens.size() >= 4) | |
645 { | |
646 name.append_child("NamePrefix").text() = tokens[3].c_str(); | |
647 } | |
648 | |
649 if (tokens.size() >= 5) | |
650 { | |
651 name.append_child("NameSuffix").text() = tokens[4].c_str(); | |
652 } | |
653 } | |
654 } | |
655 else | |
656 { | |
657 pugi::xml_node child = node.append_child("Value"); | |
658 child.append_attribute("number").set_value(number.c_str()); | |
659 | |
660 switch (content[KEY_VALUE][j].type()) | |
661 { | |
662 case Json::stringValue: | |
663 child.text() = content[KEY_VALUE][j].asCString(); | |
664 break; | |
665 | |
666 case Json::realValue: | |
667 child.text() = content[KEY_VALUE][j].asFloat(); | |
668 break; | |
669 | |
670 case Json::intValue: | |
671 child.text() = content[KEY_VALUE][j].asInt(); | |
672 break; | |
673 | |
674 case Json::uintValue: | |
675 child.text() = content[KEY_VALUE][j].asUInt(); | |
676 break; | |
677 | |
678 default: | |
679 break; | |
680 } | |
681 } | |
682 } | |
683 } | |
684 else if (content.isMember(KEY_BULK_DATA_URI) && | |
685 content[KEY_BULK_DATA_URI].type() == Json::stringValue) | |
686 { | |
687 pugi::xml_node child = node.append_child("BulkData"); | |
688 child.append_attribute("URI").set_value(content[KEY_BULK_DATA_URI].asCString()); | |
689 } | |
690 else if (content.isMember(KEY_INLINE_BINARY) && | |
691 content[KEY_INLINE_BINARY].type() == Json::stringValue) | |
692 { | |
693 pugi::xml_node child = node.append_child("InlineBinary"); | |
694 child.text() = content[KEY_INLINE_BINARY].asCString(); | |
695 } | |
696 } | |
697 } | |
698 | |
699 | |
700 static void DicomWebJsonToXml(pugi::xml_document& target, | |
701 const Json::Value& source) | |
702 { | |
703 pugi::xml_node root = target.append_child("NativeDicomModel"); | |
704 root.append_attribute("xmlns").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); | |
705 root.append_attribute("xsi:schemaLocation").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); | |
706 root.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance"); | |
707 | |
708 ExploreDataset(root, source); | |
709 | |
710 pugi::xml_node decl = target.prepend_child(pugi::node_declaration); | |
711 decl.append_attribute("version").set_value("1.0"); | |
712 decl.append_attribute("encoding").set_value("utf-8"); | |
713 } | |
714 | |
715 | |
716 enum DicomWebBinaryMode | |
717 { | |
718 DicomWebBinaryMode_Ignore, | |
719 DicomWebBinaryMode_BulkDataUri, | |
720 DicomWebBinaryMode_InlineBinary | |
721 }; | |
722 | |
723 class IDicomWebBinaryFormatter : public boost::noncopyable | |
724 { | |
725 public: | |
726 virtual ~IDicomWebBinaryFormatter() | |
727 { | |
728 } | |
729 | |
730 virtual DicomWebBinaryMode Format(std::string& bulkDataUri, | |
731 const std::vector<DicomTag>& parentTags, | |
732 const std::vector<size_t>& parentIndexes, | |
733 const DicomTag& tag, | |
734 ValueRepresentation vr) = 0; | |
735 }; | |
736 | |
737 class DicomWebJsonVisitor : public ITagVisitor | |
738 { | |
739 private: | |
740 Json::Value result_; | |
741 IDicomWebBinaryFormatter *formatter_; | |
742 | |
743 static std::string FormatTag(const DicomTag& tag) | |
744 { | |
745 char buf[16]; | |
746 sprintf(buf, "%04X%04X", tag.GetGroup(), tag.GetElement()); | |
747 return std::string(buf); | |
748 } | |
749 | |
750 Json::Value& CreateNode(const std::vector<DicomTag>& parentTags, | |
751 const std::vector<size_t>& parentIndexes, | |
752 const DicomTag& tag) | |
753 { | |
754 assert(parentTags.size() == parentIndexes.size()); | |
755 | |
756 Json::Value* node = &result_; | |
757 | |
758 for (size_t i = 0; i < parentTags.size(); i++) | |
759 { | |
760 std::string t = FormatTag(parentTags[i]); | |
761 | |
762 if (!node->isMember(t)) | |
763 { | |
764 Json::Value item = Json::objectValue; | |
765 item[KEY_VR] = KEY_SQ; | |
766 item[KEY_VALUE] = Json::arrayValue; | |
767 item[KEY_VALUE].append(Json::objectValue); | |
768 (*node) [t] = item; | |
769 | |
770 node = &(*node)[t][KEY_VALUE][0]; | |
771 } | |
772 else if ((*node) [t].type() != Json::objectValue || | |
773 !(*node) [t].isMember(KEY_VR) || | |
774 (*node) [t][KEY_VR].type() != Json::stringValue || | |
775 (*node) [t][KEY_VR].asString() != KEY_SQ || | |
776 !(*node) [t].isMember(KEY_VALUE) || | |
777 (*node) [t][KEY_VALUE].type() != Json::arrayValue) | |
778 { | |
779 throw OrthancException(ErrorCode_InternalError); | |
780 } | |
781 else | |
782 { | |
783 size_t currentSize = (*node) [t][KEY_VALUE].size(); | |
784 | |
785 if (parentIndexes[i] < currentSize) | |
786 { | |
787 // The node already exists | |
788 } | |
789 else if (parentIndexes[i] == currentSize) | |
790 { | |
791 (*node) [t][KEY_VALUE].append(Json::objectValue); | |
792 } | |
793 else | |
794 { | |
795 throw OrthancException(ErrorCode_InternalError); | |
796 } | |
797 | |
798 node = &(*node) [t][KEY_VALUE][Json::ArrayIndex(parentIndexes[i])]; | |
799 } | |
800 } | |
801 | |
802 assert(node->type() == Json::objectValue); | |
803 | |
804 std::string t = FormatTag(tag); | |
805 if (node->isMember(t)) | |
806 { | |
807 throw OrthancException(ErrorCode_InternalError); | |
808 } | |
809 else | |
810 { | |
811 (*node) [t] = Json::objectValue; | |
812 return (*node) [t]; | |
813 } | |
814 } | |
815 | |
816 static Json::Value FormatInteger(int64_t value) | |
817 { | |
818 if (value < 0) | |
819 { | |
820 return Json::Value(static_cast<int32_t>(value)); | |
821 } | |
822 else | |
823 { | |
824 return Json::Value(static_cast<uint32_t>(value)); | |
825 } | |
826 } | |
827 | |
828 static Json::Value FormatDouble(double value) | |
829 { | |
830 long long a = boost::math::llround<double>(value); | |
831 | |
832 double d = fabs(value - static_cast<double>(a)); | |
833 | |
834 if (d <= std::numeric_limits<double>::epsilon() * 100.0) | |
835 { | |
836 return FormatInteger(a); | |
837 } | |
838 else | |
839 { | |
840 return Json::Value(value); | |
841 } | |
842 } | |
843 | |
844 public: | |
845 DicomWebJsonVisitor() : | |
846 formatter_(NULL) | |
847 { | |
848 Clear(); | |
849 } | |
850 | |
851 void SetFormatter(IDicomWebBinaryFormatter& formatter) | |
852 { | |
853 formatter_ = &formatter; | |
854 } | |
855 | |
856 void Clear() | |
857 { | |
858 result_ = Json::objectValue; | |
859 } | |
860 | |
861 const Json::Value& GetResult() const | |
862 { | |
863 return result_; | |
864 } | |
865 | |
866 void FormatXml(pugi::xml_document& target) const | |
867 { | |
868 DicomWebJsonToXml(target, result_); | |
869 } | |
870 | |
871 virtual void VisitNotSupported(const std::vector<DicomTag>& parentTags, | |
872 const std::vector<size_t>& parentIndexes, | |
873 const DicomTag& tag, | |
874 ValueRepresentation vr) ORTHANC_OVERRIDE | |
875 { | |
876 } | |
877 | |
878 virtual void VisitEmptySequence(const std::vector<DicomTag>& parentTags, | |
879 const std::vector<size_t>& parentIndexes, | |
880 const DicomTag& tag) ORTHANC_OVERRIDE | |
881 { | |
882 if (tag.GetElement() != 0x0000) | |
883 { | |
884 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
885 node[KEY_VR] = EnumerationToString(ValueRepresentation_Sequence); | |
886 } | |
887 } | |
888 | |
889 virtual void VisitBinary(const std::vector<DicomTag>& parentTags, | |
890 const std::vector<size_t>& parentIndexes, | |
891 const DicomTag& tag, | |
892 ValueRepresentation vr, | |
893 const void* data, | |
894 size_t size) ORTHANC_OVERRIDE | |
895 { | |
896 assert(vr == ValueRepresentation_OtherByte || | |
897 vr == ValueRepresentation_OtherDouble || | |
898 vr == ValueRepresentation_OtherFloat || | |
899 vr == ValueRepresentation_OtherLong || | |
900 vr == ValueRepresentation_OtherWord || | |
901 vr == ValueRepresentation_Unknown); | |
902 | |
903 if (tag.GetElement() != 0x0000) | |
904 { | |
905 DicomWebBinaryMode mode; | |
906 std::string bulkDataUri; | |
907 | |
908 if (formatter_ == NULL) | |
909 { | |
910 mode = DicomWebBinaryMode_InlineBinary; | |
911 } | |
912 else | |
913 { | |
914 mode = formatter_->Format(bulkDataUri, parentTags, parentIndexes, tag, vr); | |
915 } | |
916 | |
917 /*mode = DicomWebBinaryMode_BulkDataUri; | |
918 bulkDataUri = "http://localhost/" + tag.Format();*/ | |
919 | |
920 if (mode != DicomWebBinaryMode_Ignore) | |
921 { | |
922 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
923 node[KEY_VR] = EnumerationToString(vr); | |
924 | |
925 switch (mode) | |
926 { | |
927 case DicomWebBinaryMode_BulkDataUri: | |
928 node[KEY_BULK_DATA_URI] = bulkDataUri; | |
929 break; | |
930 | |
931 case DicomWebBinaryMode_InlineBinary: | |
932 { | |
933 std::string tmp(static_cast<const char*>(data), size); | |
934 | |
935 std::string base64; | |
936 Toolbox::EncodeBase64(base64, tmp); | |
937 | |
938 node[KEY_INLINE_BINARY] = base64; | |
939 break; | |
940 } | |
941 | |
942 default: | |
943 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
944 } | |
945 } | |
946 } | |
947 } | |
948 | |
949 virtual void VisitIntegers(const std::vector<DicomTag>& parentTags, | |
950 const std::vector<size_t>& parentIndexes, | |
951 const DicomTag& tag, | |
952 ValueRepresentation vr, | |
953 const std::vector<int64_t>& values) ORTHANC_OVERRIDE | |
954 { | |
955 if (tag.GetElement() != 0x0000 && | |
956 vr != ValueRepresentation_NotSupported) | |
957 { | |
958 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
959 node[KEY_VR] = EnumerationToString(vr); | |
960 | |
961 if (!values.empty()) | |
962 { | |
963 Json::Value content = Json::arrayValue; | |
964 for (size_t i = 0; i < values.size(); i++) | |
965 { | |
966 content.append(FormatInteger(values[i])); | |
967 } | |
968 | |
969 node[KEY_VALUE] = content; | |
970 } | |
971 } | |
972 } | |
973 | |
974 virtual void VisitDoubles(const std::vector<DicomTag>& parentTags, | |
975 const std::vector<size_t>& parentIndexes, | |
976 const DicomTag& tag, | |
977 ValueRepresentation vr, | |
978 const std::vector<double>& values) ORTHANC_OVERRIDE | |
979 { | |
980 if (tag.GetElement() != 0x0000 && | |
981 vr != ValueRepresentation_NotSupported) | |
982 { | |
983 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
984 node[KEY_VR] = EnumerationToString(vr); | |
985 | |
986 if (!values.empty()) | |
987 { | |
988 Json::Value content = Json::arrayValue; | |
989 for (size_t i = 0; i < values.size(); i++) | |
990 { | |
991 content.append(FormatDouble(values[i])); | |
992 } | |
993 | |
994 node[KEY_VALUE] = content; | |
995 } | |
996 } | |
997 } | |
998 | |
999 virtual void VisitAttributes(const std::vector<DicomTag>& parentTags, | |
1000 const std::vector<size_t>& parentIndexes, | |
1001 const DicomTag& tag, | |
1002 const std::vector<DicomTag>& values) ORTHANC_OVERRIDE | |
1003 { | |
1004 if (tag.GetElement() != 0x0000) | |
1005 { | |
1006 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
1007 node[KEY_VR] = EnumerationToString(ValueRepresentation_AttributeTag); | |
1008 | |
1009 if (!values.empty()) | |
1010 { | |
1011 Json::Value content = Json::arrayValue; | |
1012 for (size_t i = 0; i < values.size(); i++) | |
1013 { | |
1014 content.append(FormatTag(values[i])); | |
1015 } | |
1016 | |
1017 node[KEY_VALUE] = content; | |
1018 } | |
1019 } | |
1020 } | |
1021 | |
1022 virtual Action VisitString(std::string& newValue, | |
1023 const std::vector<DicomTag>& parentTags, | |
1024 const std::vector<size_t>& parentIndexes, | |
1025 const DicomTag& tag, | |
1026 ValueRepresentation vr, | |
1027 const std::string& value) ORTHANC_OVERRIDE | |
1028 { | |
1029 if (tag.GetElement() == 0x0000 || | |
1030 vr == ValueRepresentation_NotSupported) | |
1031 { | |
1032 return Action_None; | |
1033 } | |
1034 else | |
1035 { | |
1036 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
1037 node[KEY_VR] = EnumerationToString(vr); | |
1038 | |
1039 if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
1040 { | |
1041 // TODO - The JSON file has an UTF-8 encoding, thus DCMTK | |
1042 // replaces the specific character set with "ISO_IR 192" | |
1043 // (UNICODE UTF-8). It is unclear whether the source | |
1044 // character set should be kept: We thus mimic DCMTK. | |
1045 node[KEY_VALUE].append("ISO_IR 192"); | |
1046 } | |
1047 else | |
1048 { | |
1049 std::string truncated; | |
1050 | |
1051 if (!value.empty() && | |
1052 value[value.size() - 1] == '\0') | |
1053 { | |
1054 truncated = value.substr(0, value.size() - 1); | |
1055 } | |
1056 else | |
1057 { | |
1058 truncated = value; | |
1059 } | |
1060 | |
1061 if (!truncated.empty()) | |
1062 { | |
1063 std::vector<std::string> tokens; | |
1064 Toolbox::TokenizeString(tokens, truncated, '\\'); | |
1065 | |
1066 node[KEY_VALUE] = Json::arrayValue; | |
1067 for (size_t i = 0; i < tokens.size(); i++) | |
1068 { | |
1069 try | |
1070 { | |
1071 switch (vr) | |
1072 { | |
1073 case ValueRepresentation_PersonName: | |
1074 { | |
1075 Json::Value value = Json::objectValue; | |
1076 if (!tokens[i].empty()) | |
1077 { | |
1078 value[KEY_ALPHABETIC] = tokens[i]; | |
1079 } | |
1080 node[KEY_VALUE].append(value); | |
1081 break; | |
1082 } | |
1083 | |
1084 case ValueRepresentation_IntegerString: | |
1085 if (tokens[i].empty()) | |
1086 { | |
1087 node[KEY_VALUE].append(Json::nullValue); | |
1088 } | |
1089 else | |
1090 { | |
1091 int64_t value = boost::lexical_cast<int64_t>(tokens[i]); | |
1092 node[KEY_VALUE].append(FormatInteger(value)); | |
1093 } | |
1094 | |
1095 break; | |
1096 | |
1097 case ValueRepresentation_DecimalString: | |
1098 if (tokens[i].empty()) | |
1099 { | |
1100 node[KEY_VALUE].append(Json::nullValue); | |
1101 } | |
1102 else | |
1103 { | |
1104 double value = boost::lexical_cast<double>(tokens[i]); | |
1105 node[KEY_VALUE].append(FormatDouble(value)); | |
1106 } | |
1107 break; | |
1108 | |
1109 default: | |
1110 if (tokens[i].empty()) | |
1111 { | |
1112 node[KEY_VALUE].append(Json::nullValue); | |
1113 } | |
1114 else | |
1115 { | |
1116 node[KEY_VALUE].append(tokens[i]); | |
1117 } | |
1118 | |
1119 break; | |
1120 } | |
1121 } | |
1122 catch (boost::bad_lexical_cast&) | |
1123 { | |
1124 throw OrthancException(ErrorCode_BadFileFormat); | |
1125 } | |
1126 } | |
1127 } | |
1128 } | |
1129 } | |
1130 | |
1131 return Action_None; | |
1132 } | |
1133 }; | |
1134 } | |
1135 | |
1136 | |
1137 | |
1138 | |
1139 | |
1140 | |
1141 #include "../Core/SystemToolbox.h" | |
1142 | |
1143 | |
1144 /* | |
1145 | |
1146 MarekLatin2.dcm | |
1147 HierarchicalAnonymization/StructuredReports/IM0 | |
1148 DummyCT.dcm | |
1149 Brainix/Epi/IM-0001-0018.dcm | |
1150 Issue22.dcm | |
1151 | |
1152 | |
1153 cat << EOF > /tmp/tutu.py | |
1154 import json | |
1155 import sys | |
1156 j = json.loads(sys.stdin.read().decode("utf-8-sig")) | |
1157 print(json.dumps(j, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8')) | |
1158 EOF | |
1159 | |
1160 DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.4/dcmdata/data/dicom.dic /home/jodogne/Downloads/dcmtk-3.6.4/i/bin/dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm | tr -d '\0' | sed 's/\\u0000//g' | sed 's/\.0$//' | python /tmp/tutu.py > /tmp/a.json | |
1161 | |
1162 make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python /tmp/tutu.py < tutu.json > /tmp/b.json && diff -i /tmp/a.json /tmp/b.json | |
1163 | |
1164 */ | |
1165 | |
1166 TEST(DicomWebJson, Basic) | |
1167 { | |
1168 std::string content; | |
1169 Orthanc::SystemToolbox::ReadFile(content, "/home/jodogne/Subversion/orthanc-tests/Database/DummyCT.dcm"); | |
1170 | |
1171 Orthanc::ParsedDicomFile dicom(content); | |
1172 | |
1173 Orthanc::DicomWebJsonVisitor visitor; | |
1174 dicom.Apply(visitor); | |
1175 | |
1176 Orthanc::SystemToolbox::WriteFile(visitor.GetResult().toStyledString(), "tutu.json"); | |
1177 | |
1178 pugi::xml_document xml; | |
1179 visitor.FormatXml(xml); | |
1180 xml.print(std::cout); | |
1181 } | |
1182 | |
1183 | |
1184 TEST(DicomWebJson, Multiplicity) | 558 TEST(DicomWebJson, Multiplicity) |
1185 { | 559 { |
1186 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.4.html | 560 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.4.html |
1187 | 561 |
1188 ParsedDicomFile dicom(false); | 562 ParsedDicomFile dicom(false); |
1212 ASSERT_EQ(1u, tag.getMemberNames().size()); | 586 ASSERT_EQ(1u, tag.getMemberNames().size()); |
1213 } | 587 } |
1214 | 588 |
1215 pugi::xml_document xml; | 589 pugi::xml_document xml; |
1216 visitor.FormatXml(xml); | 590 visitor.FormatXml(xml); |
1217 xml.print(std::cout); | |
1218 } | 591 } |
1219 | 592 |
1220 | 593 |
1221 TEST(DicomWebJson, NullValue) | 594 TEST(DicomWebJson, NullValue) |
1222 { | 595 { |
1243 ASSERT_FLOAT_EQ(2.5f, value[3].asFloat()); | 616 ASSERT_FLOAT_EQ(2.5f, value[3].asFloat()); |
1244 } | 617 } |
1245 | 618 |
1246 pugi::xml_document xml; | 619 pugi::xml_document xml; |
1247 visitor.FormatXml(xml); | 620 visitor.FormatXml(xml); |
1248 xml.print(std::cout); | |
1249 } | 621 } |
1250 | 622 |
1251 | 623 |
1252 TEST(DicomWebJson, ValueRepresentation) | 624 TEST(DicomWebJson, ValueRepresentation) |
1253 { | 625 { |
1386 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString()); | 758 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString()); |
1387 | 759 |
1388 | 760 |
1389 pugi::xml_document xml; | 761 pugi::xml_document xml; |
1390 visitor.FormatXml(xml); | 762 visitor.FormatXml(xml); |
1391 xml.print(std::cout); | |
1392 } | 763 } |
1393 | 764 |
1394 | 765 |
1395 TEST(DicomWebJson, Sequence) | 766 TEST(DicomWebJson, Sequence) |
1396 { | 767 { |
1431 ASSERT_TRUE(items.find("item1") != items.end()); | 802 ASSERT_TRUE(items.find("item1") != items.end()); |
1432 ASSERT_TRUE(items.find("item2") != items.end()); | 803 ASSERT_TRUE(items.find("item2") != items.end()); |
1433 | 804 |
1434 pugi::xml_document xml; | 805 pugi::xml_document xml; |
1435 visitor.FormatXml(xml); | 806 visitor.FormatXml(xml); |
1436 xml.print(std::cout); | 807 } |
1437 } |