comparison OrthancFramework/UnitTestsSources/DicomMapTests.cpp @ 4063:e00f3d089991 framework

shared library of orthanc framework
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 11 Jun 2020 16:40:34 +0200
parents 0953b3dc3261
children bf7b9edf6b81
comparison
equal deleted inserted replaced
4062:0953b3dc3261 4063:e00f3d089991
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. 30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/ 31 **/
32 32
33 33
34 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 34 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1
35 // Must be the first to be sure to use the Orthanc framework shared library
35 # include <OrthancFramework.h> 36 # include <OrthancFramework.h>
37 #endif
38
39 #if !defined(DCMTK_VERSION_NUMBER)
40 # error DCMTK_VERSION_NUMBER is not defined
36 #endif 41 #endif
37 42
38 #include <gtest/gtest.h> 43 #include <gtest/gtest.h>
39 44
40 #include "../Sources/Compatibility.h" 45 #include "../Sources/Compatibility.h"
43 #include "../Sources/DicomParsing/FromDcmtkBridge.h" 48 #include "../Sources/DicomParsing/FromDcmtkBridge.h"
44 #include "../Sources/DicomParsing/ToDcmtkBridge.h" 49 #include "../Sources/DicomParsing/ToDcmtkBridge.h"
45 #include "../Sources/DicomParsing/ParsedDicomFile.h" 50 #include "../Sources/DicomParsing/ParsedDicomFile.h"
46 #include "../Sources/DicomParsing/DicomWebJsonVisitor.h" 51 #include "../Sources/DicomParsing/DicomWebJsonVisitor.h"
47 52
48 #include <memory>
49 #include <dcmtk/dcmdata/dcdeftag.h>
50 #include <dcmtk/dcmdata/dcvrat.h>
51 53
52 using namespace Orthanc; 54 using namespace Orthanc;
53 55
54 TEST(DicomMap, MainTags) 56 TEST(DicomMap, MainTags)
55 { 57 {
595 ASSERT_FLOAT_EQ(2.5f, boost::lexical_cast<float>(v[3])); 597 ASSERT_FLOAT_EQ(2.5f, boost::lexical_cast<float>(v[3]));
596 } 598 }
597 } 599 }
598 600
599 601
600 static void SetTagKey(ParsedDicomFile& dicom,
601 const DicomTag& tag,
602 const DicomTag& value)
603 {
604 // This function emulates a call to function
605 // "dicom.GetDcmtkObject().getDataset()->putAndInsertTagKey(tag,
606 // value)" that was not available in DCMTK 3.6.0
607
608 std::unique_ptr<DcmAttributeTag> element(new DcmAttributeTag(ToDcmtkBridge::Convert(tag)));
609
610 DcmTagKey v = ToDcmtkBridge::Convert(value);
611 if (!element->putTagVal(v).good())
612 {
613 throw OrthancException(ErrorCode_InternalError);
614 }
615
616 dicom.GetDcmtkObject().getDataset()->insert(element.release());
617 }
618
619
620 TEST(DicomWebJson, ValueRepresentation)
621 {
622 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html
623
624 ParsedDicomFile dicom(false);
625 dicom.ReplacePlainString(DicomTag(0x0040, 0x0241), "AE");
626 dicom.ReplacePlainString(DicomTag(0x0010, 0x1010), "AS");
627 SetTagKey(dicom, DicomTag(0x0020, 0x9165), DicomTag(0x0010, 0x0020));
628 dicom.ReplacePlainString(DicomTag(0x0008, 0x0052), "CS");
629 dicom.ReplacePlainString(DicomTag(0x0008, 0x0012), "DA");
630 dicom.ReplacePlainString(DicomTag(0x0010, 0x1020), "42"); // DS
631 dicom.ReplacePlainString(DicomTag(0x0008, 0x002a), "DT");
632 dicom.ReplacePlainString(DicomTag(0x0010, 0x9431), "43"); // FL
633 dicom.ReplacePlainString(DicomTag(0x0008, 0x1163), "44"); // FD
634 dicom.ReplacePlainString(DicomTag(0x0008, 0x1160), "45"); // IS
635 dicom.ReplacePlainString(DicomTag(0x0008, 0x0070), "LO");
636 dicom.ReplacePlainString(DicomTag(0x0010, 0x4000), "LT");
637 dicom.ReplacePlainString(DicomTag(0x0028, 0x2000), "OB");
638 dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "3.14159"); // OD (other double)
639 dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "2.71828"); // OF (other float)
640 dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46"); // OL (other long)
641 ASSERT_THROW(dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "O"), OrthancException);
642 dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "OWOW");
643 dicom.ReplacePlainString(DicomTag(0x0010, 0x0010), "PN");
644 dicom.ReplacePlainString(DicomTag(0x0008, 0x0050), "SH");
645 dicom.ReplacePlainString(DicomTag(0x0018, 0x6020), "-15"); // SL
646 dicom.ReplacePlainString(DicomTag(0x0018, 0x9219), "-16"); // SS
647 dicom.ReplacePlainString(DicomTag(0x0008, 0x0081), "ST");
648 dicom.ReplacePlainString(DicomTag(0x0008, 0x0013), "TM");
649 dicom.ReplacePlainString(DicomTag(0x0008, 0x0119), "UC");
650 dicom.ReplacePlainString(DicomTag(0x0008, 0x0016), "UI");
651 dicom.ReplacePlainString(DicomTag(0x0008, 0x1161), "128"); // UL
652 dicom.ReplacePlainString(DicomTag(0x4342, 0x1234), "UN"); // Inexistent tag
653 dicom.ReplacePlainString(DicomTag(0x0008, 0x0120), "UR");
654 dicom.ReplacePlainString(DicomTag(0x0008, 0x0301), "17"); // US
655 dicom.ReplacePlainString(DicomTag(0x0040, 0x0031), "UT");
656
657 DicomWebJsonVisitor visitor;
658 dicom.Apply(visitor);
659
660 std::string s;
661
662 // The tag (0002,0002) is "Media Storage SOP Class UID" and is
663 // automatically copied by DCMTK from tag (0008,0016)
664 ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["vr"].asString());
665 ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["Value"][0].asString());
666 ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["vr"].asString());
667 ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["Value"][0].asString());
668 ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["vr"].asString());
669 ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["Value"][0].asString());
670 ASSERT_EQ("AT", visitor.GetResult() ["00209165"]["vr"].asString());
671 ASSERT_EQ("00100020", visitor.GetResult() ["00209165"]["Value"][0].asString());
672 ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["vr"].asString());
673 ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["Value"][0].asString());
674 ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["vr"].asString());
675 ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["Value"][0].asString());
676 ASSERT_EQ("DS", visitor.GetResult() ["00101020"]["vr"].asString());
677 ASSERT_FLOAT_EQ(42.0f, visitor.GetResult() ["00101020"]["Value"][0].asFloat());
678 ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["vr"].asString());
679 ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["Value"][0].asString());
680 ASSERT_EQ("FL", visitor.GetResult() ["00109431"]["vr"].asString());
681 ASSERT_FLOAT_EQ(43.0f, visitor.GetResult() ["00109431"]["Value"][0].asFloat());
682 ASSERT_EQ("FD", visitor.GetResult() ["00081163"]["vr"].asString());
683 ASSERT_FLOAT_EQ(44.0f, visitor.GetResult() ["00081163"]["Value"][0].asFloat());
684 ASSERT_EQ("IS", visitor.GetResult() ["00081160"]["vr"].asString());
685 ASSERT_FLOAT_EQ(45.0f, visitor.GetResult() ["00081160"]["Value"][0].asFloat());
686 ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["vr"].asString());
687 ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["Value"][0].asString());
688 ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["vr"].asString());
689 ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["Value"][0].asString());
690
691 ASSERT_EQ("OB", visitor.GetResult() ["00282000"]["vr"].asString());
692 Toolbox::DecodeBase64(s, visitor.GetResult() ["00282000"]["InlineBinary"].asString());
693 ASSERT_EQ("OB", s);
694
695 #if DCMTK_VERSION_NUMBER >= 361
696 ASSERT_EQ("OD", visitor.GetResult() ["7FE00009"]["vr"].asString());
697 ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(visitor.GetResult() ["7FE00009"]["Value"][0].asString()));
698 #else
699 ASSERT_EQ("UN", visitor.GetResult() ["7FE00009"]["vr"].asString());
700 Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString());
701 ASSERT_EQ(8u, s.size()); // Because of padding
702 ASSERT_EQ(0, s[7]);
703 ASSERT_EQ("3.14159", s.substr(0, 7));
704 #endif
705
706 ASSERT_EQ("OF", visitor.GetResult() ["00640009"]["vr"].asString());
707 ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(visitor.GetResult() ["00640009"]["Value"][0].asString()));
708
709 #if DCMTK_VERSION_NUMBER < 361
710 ASSERT_EQ("UN", visitor.GetResult() ["00660040"]["vr"].asString());
711 Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString());
712 ASSERT_EQ("46", s);
713 #elif DCMTK_VERSION_NUMBER == 361
714 ASSERT_EQ("UL", visitor.GetResult() ["00660040"]["vr"].asString());
715 ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt());
716 #else
717 ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString());
718 ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt());
719 #endif
720
721 ASSERT_EQ("OW", visitor.GetResult() ["00281201"]["vr"].asString());
722 Toolbox::DecodeBase64(s, visitor.GetResult() ["00281201"]["InlineBinary"].asString());
723 ASSERT_EQ("OWOW", s);
724
725 ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["vr"].asString());
726 ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["Value"][0]["Alphabetic"].asString());
727
728 ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["vr"].asString());
729 ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["Value"][0].asString());
730
731 ASSERT_EQ("SL", visitor.GetResult() ["00186020"]["vr"].asString());
732 ASSERT_EQ(-15, visitor.GetResult() ["00186020"]["Value"][0].asInt());
733
734 ASSERT_EQ("SS", visitor.GetResult() ["00189219"]["vr"].asString());
735 ASSERT_EQ(-16, visitor.GetResult() ["00189219"]["Value"][0].asInt());
736
737 ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["vr"].asString());
738 ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["Value"][0].asString());
739
740 ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["vr"].asString());
741 ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["Value"][0].asString());
742
743 #if DCMTK_VERSION_NUMBER >= 361
744 ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["vr"].asString());
745 ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["Value"][0].asString());
746 #else
747 ASSERT_EQ("UN", visitor.GetResult() ["00080119"]["vr"].asString());
748 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080119"]["InlineBinary"].asString());
749 ASSERT_EQ("UC", s);
750 #endif
751
752 ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["vr"].asString());
753 ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["Value"][0].asString());
754
755 ASSERT_EQ("UL", visitor.GetResult() ["00081161"]["vr"].asString());
756 ASSERT_EQ(128u, visitor.GetResult() ["00081161"]["Value"][0].asUInt());
757
758 ASSERT_EQ("UN", visitor.GetResult() ["43421234"]["vr"].asString());
759 Toolbox::DecodeBase64(s, visitor.GetResult() ["43421234"]["InlineBinary"].asString());
760 ASSERT_EQ("UN", s);
761
762 #if DCMTK_VERSION_NUMBER >= 361
763 ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["vr"].asString());
764 ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["Value"][0].asString());
765 #else
766 ASSERT_EQ("UN", visitor.GetResult() ["00080120"]["vr"].asString());
767 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080120"]["InlineBinary"].asString());
768 ASSERT_EQ("UR", s);
769 #endif
770
771 #if DCMTK_VERSION_NUMBER >= 361
772 ASSERT_EQ("US", visitor.GetResult() ["00080301"]["vr"].asString());
773 ASSERT_EQ(17u, visitor.GetResult() ["00080301"]["Value"][0].asUInt());
774 #else
775 ASSERT_EQ("UN", visitor.GetResult() ["00080301"]["vr"].asString());
776 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080301"]["InlineBinary"].asString());
777 ASSERT_EQ("17", s);
778 #endif
779
780 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["vr"].asString());
781 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString());
782
783 std::string xml;
784 visitor.FormatXml(xml);
785
786 {
787 DicomMap m;
788 m.FromDicomWeb(visitor.GetResult());
789 ASSERT_EQ(31u, m.GetSize());
790
791 std::string s;
792 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0002, 0x0002), false)); ASSERT_EQ("UI", s);
793 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0241), false)); ASSERT_EQ("AE", s);
794 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1010), false)); ASSERT_EQ("AS", s);
795 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0020, 0x9165), false)); ASSERT_EQ("00100020", s);
796 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0052), false)); ASSERT_EQ("CS", s);
797 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0012), false)); ASSERT_EQ("DA", s);
798 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1020), false)); ASSERT_EQ("42", s);
799 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x002a), false)); ASSERT_EQ("DT", s);
800 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x9431), false)); ASSERT_EQ("43", s);
801 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1163), false)); ASSERT_EQ("44", s);
802 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1160), false)); ASSERT_EQ("45", s);
803 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false)); ASSERT_EQ("LO", s);
804 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false)); ASSERT_EQ("LT", s);
805 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true)); ASSERT_EQ("OB", s);
806 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true));
807
808 #if DCMTK_VERSION_NUMBER >= 361
809 ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(s));
810 #else
811 ASSERT_EQ(8u, s.size()); // Because of padding
812 ASSERT_EQ(0, s[7]);
813 ASSERT_EQ("3.14159", s.substr(0, 7));
814 #endif
815
816 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true));
817 ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(s));
818 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true)); ASSERT_EQ("OWOW", s);
819 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false)); ASSERT_EQ("PN", s);
820 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false)); ASSERT_EQ("SH", s);
821 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x6020), false)); ASSERT_EQ("-15", s);
822 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false)); ASSERT_EQ("-16", s);
823 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false)); ASSERT_EQ("ST", s);
824 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false)); ASSERT_EQ("TM", s);
825 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false)); ASSERT_EQ("UI", s);
826 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false)); ASSERT_EQ("128", s);
827 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true)); ASSERT_EQ("UN", s);
828 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false)); ASSERT_EQ("UT", s);
829
830 #if DCMTK_VERSION_NUMBER >= 361
831 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false)); ASSERT_EQ("46", s);
832 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false)); ASSERT_EQ("UC", s);
833 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false)); ASSERT_EQ("UR", s);
834 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false)); ASSERT_EQ("17", s);
835 #else
836 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true)); ASSERT_EQ("46", s); // OL
837 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), true)); ASSERT_EQ("UC", s);
838 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), true)); ASSERT_EQ("UR", s);
839 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), true)); ASSERT_EQ("17", s); // US (but tag unknown to DCMTK 3.6.0)
840 #endif
841
842 }
843 }
844
845
846 TEST(DicomWebJson, Sequence)
847 {
848 ParsedDicomFile dicom(false);
849
850 {
851 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence));
852
853 for (unsigned int i = 0; i < 3; i++)
854 {
855 std::unique_ptr<DcmItem> item(new DcmItem);
856 std::string s = "item" + boost::lexical_cast<std::string>(i);
857 item->putAndInsertString(DCM_ReferencedSOPInstanceUID, s.c_str(), OFFalse);
858 ASSERT_TRUE(sequence->insert(item.release(), false, false).good());
859 }
860
861 ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->insert(sequence.release(), false, false).good());
862 }
863
864 DicomWebJsonVisitor visitor;
865 dicom.Apply(visitor);
866
867 ASSERT_EQ("SQ", visitor.GetResult() ["00081115"]["vr"].asString());
868 ASSERT_EQ(3u, visitor.GetResult() ["00081115"]["Value"].size());
869
870 std::set<std::string> items;
871
872 for (Json::Value::ArrayIndex i = 0; i < 3; i++)
873 {
874 ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i].size());
875 ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"].size());
876 ASSERT_EQ("UI", visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["vr"].asString());
877 items.insert(visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"][0].asString());
878 }
879
880 ASSERT_EQ(3u, items.size());
881 ASSERT_TRUE(items.find("item0") != items.end());
882 ASSERT_TRUE(items.find("item1") != items.end());
883 ASSERT_TRUE(items.find("item2") != items.end());
884
885 std::string xml;
886 visitor.FormatXml(xml);
887
888 {
889 DicomMap m;
890 m.FromDicomWeb(visitor.GetResult());
891 ASSERT_EQ(0u, m.GetSize()); // Sequences are not handled by DicomMap
892 }
893 }
894
895
896 TEST(DicomWebJson, PixelSpacing) 602 TEST(DicomWebJson, PixelSpacing)
897 { 603 {
898 // Test related to locales: Make sure that decimal separator is 604 // Test related to locales: Make sure that decimal separator is
899 // correctly handled (dot "." vs comma ",") 605 // correctly handled (dot "." vs comma ",")
900 ParsedDicomFile source(false); 606 ParsedDicomFile source(false);