comparison OrthancFramework/UnitTestsSources/DicomMapTests.cpp @ 4220:92a21efa5c96

reorganization of DicomStreamReader
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 30 Sep 2020 15:33:47 +0200
parents b8ed2852a35d
children 3d6f14a05db1
comparison
equal deleted inserted replaced
4219:b8ed2852a35d 4220:92a21efa5c96
32 #include <gtest/gtest.h> 32 #include <gtest/gtest.h>
33 33
34 #include "../Sources/Compatibility.h" 34 #include "../Sources/Compatibility.h"
35 #include "../Sources/OrthancException.h" 35 #include "../Sources/OrthancException.h"
36 #include "../Sources/DicomFormat/DicomMap.h" 36 #include "../Sources/DicomFormat/DicomMap.h"
37 #include "../Sources/DicomFormat/DicomStreamReader.h"
37 #include "../Sources/DicomParsing/FromDcmtkBridge.h" 38 #include "../Sources/DicomParsing/FromDcmtkBridge.h"
38 #include "../Sources/DicomParsing/ToDcmtkBridge.h" 39 #include "../Sources/DicomParsing/ToDcmtkBridge.h"
39 #include "../Sources/DicomParsing/ParsedDicomFile.h" 40 #include "../Sources/DicomParsing/ParsedDicomFile.h"
40 #include "../Sources/DicomParsing/DicomWebJsonVisitor.h" 41 #include "../Sources/DicomParsing/DicomWebJsonVisitor.h"
41 42
796 } 797 }
797 798
798 799
799 namespace 800 namespace
800 { 801 {
801 class StreamBlockReader : public boost::noncopyable
802 {
803 private:
804 std::istream& stream_;
805 std::string block_;
806 size_t blockPos_;
807 uint64_t processedBytes_;
808
809 public:
810 StreamBlockReader(std::istream& stream) :
811 stream_(stream),
812 blockPos_(0),
813 processedBytes_(0)
814 {
815 }
816
817 void Schedule(size_t blockSize)
818 {
819 if (!block_.empty())
820 {
821 throw OrthancException(ErrorCode_BadSequenceOfCalls);
822 }
823 else
824 {
825 block_.resize(blockSize);
826 blockPos_ = 0;
827 }
828 }
829
830 bool Read(std::string& block)
831 {
832 if (block_.empty())
833 {
834 if (blockPos_ != 0)
835 {
836 throw OrthancException(ErrorCode_BadSequenceOfCalls);
837 }
838
839 block.clear();
840 return true;
841 }
842 else
843 {
844 while (blockPos_ < block_.size())
845 {
846 #if 0
847 char c;
848 stream_.get(c);
849
850 if (stream_.good())
851 {
852 block_[blockPos_] = c;
853 blockPos_++;
854 }
855 else
856 {
857 return false;
858 }
859 #else
860 size_t n = block_.size() - blockPos_;
861 std::streamsize r = stream_.readsome(&block_[blockPos_], n);
862 if (r == 0)
863 {
864 return false;
865 }
866 else
867 {
868 blockPos_ += r;
869 }
870 #endif
871 }
872
873 processedBytes_ += block_.size();
874
875 block.swap(block_);
876 block_.clear();
877 return true;
878 }
879 }
880
881 uint64_t GetProcessedBytes() const
882 {
883 return processedBytes_;
884 }
885 };
886
887
888
889
890 /**
891 * This class parses a stream containing a DICOM instance. It does
892 * *not* support the visit of sequences (it only works at the first
893 * level of the hierarchy), and it stops the processing once pixel
894 * data is reached in compressed transfer syntaxes.
895 **/
896 class DicomStreamReader : public boost::noncopyable
897 {
898 public:
899 class IVisitor : public boost::noncopyable
900 {
901 public:
902 virtual ~IVisitor()
903 {
904 }
905
906 // The data from this function will always be Little Endian (as
907 // specified by the DICOM standard)
908 virtual void VisitMetaHeaderTag(const DicomTag& tag,
909 const ValueRepresentation& vr,
910 const std::string& value) = 0;
911
912 // Return "false" to stop processing
913 virtual bool VisitDatasetTag(const DicomTag& tag,
914 const ValueRepresentation& vr,
915 DicomTransferSyntax transferSyntax,
916 const std::string& value,
917 bool isLittleEndian) = 0;
918 };
919
920 private:
921 enum State
922 {
923 State_Preamble,
924 State_MetaHeader,
925 State_DatasetTag,
926 State_SequenceExplicitLength,
927 State_SequenceExplicitValue,
928 State_DatasetExplicitLength,
929 State_DatasetValue,
930 State_Done
931 };
932
933 StreamBlockReader reader_;
934 State state_;
935 DicomTransferSyntax transferSyntax_;
936 DicomTag previousTag_;
937 DicomTag danglingTag_; // Root-level tag
938 ValueRepresentation danglingVR_;
939 unsigned int sequenceDepth_;
940
941 static uint16_t ReadUnsignedInteger16(const char* dicom,
942 bool littleEndian)
943 {
944 const uint8_t* p = reinterpret_cast<const uint8_t*>(dicom);
945
946 if (littleEndian)
947 {
948 return (static_cast<uint16_t>(p[0]) |
949 (static_cast<uint16_t>(p[1]) << 8));
950 }
951 else
952 {
953 return (static_cast<uint16_t>(p[1]) |
954 (static_cast<uint16_t>(p[0]) << 8));
955 }
956 }
957
958
959 static uint32_t ReadUnsignedInteger32(const char* dicom,
960 bool littleEndian)
961 {
962 const uint8_t* p = reinterpret_cast<const uint8_t*>(dicom);
963
964 if (littleEndian)
965 {
966 return (static_cast<uint32_t>(p[0]) |
967 (static_cast<uint32_t>(p[1]) << 8) |
968 (static_cast<uint32_t>(p[2]) << 16) |
969 (static_cast<uint32_t>(p[3]) << 24));
970 }
971 else
972 {
973 return (static_cast<uint32_t>(p[3]) |
974 (static_cast<uint32_t>(p[2]) << 8) |
975 (static_cast<uint32_t>(p[1]) << 16) |
976 (static_cast<uint32_t>(p[0]) << 24));
977 }
978 }
979
980
981 static DicomTag ReadTag(const char* dicom,
982 bool littleEndian)
983 {
984 return DicomTag(ReadUnsignedInteger16(dicom, littleEndian),
985 ReadUnsignedInteger16(dicom + 2, littleEndian));
986 }
987
988
989 static bool IsShortExplicitTag(ValueRepresentation vr)
990 {
991 /**
992 * Are we in the case of Table 7.1-2? "Data Element with
993 * Explicit VR of AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO,
994 * LT, PN, SH, SL, SS, ST, TM, UI, UL and US"
995 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_7.html#sect_7.1.2
996 **/
997 return (vr == ValueRepresentation_ApplicationEntity /* AE */ ||
998 vr == ValueRepresentation_AgeString /* AS */ ||
999 vr == ValueRepresentation_AttributeTag /* AT */ ||
1000 vr == ValueRepresentation_CodeString /* CS */ ||
1001 vr == ValueRepresentation_Date /* DA */ ||
1002 vr == ValueRepresentation_DecimalString /* DS */ ||
1003 vr == ValueRepresentation_DateTime /* DT */ ||
1004 vr == ValueRepresentation_FloatingPointSingle /* FL */ ||
1005 vr == ValueRepresentation_FloatingPointDouble /* FD */ ||
1006 vr == ValueRepresentation_IntegerString /* IS */ ||
1007 vr == ValueRepresentation_LongString /* LO */ ||
1008 vr == ValueRepresentation_LongText /* LT */ ||
1009 vr == ValueRepresentation_PersonName /* PN */ ||
1010 vr == ValueRepresentation_ShortString /* SH */ ||
1011 vr == ValueRepresentation_SignedLong /* SL */ ||
1012 vr == ValueRepresentation_SignedShort /* SS */ ||
1013 vr == ValueRepresentation_ShortText /* ST */ ||
1014 vr == ValueRepresentation_Time /* TM */ ||
1015 vr == ValueRepresentation_UniqueIdentifier /* UI */ ||
1016 vr == ValueRepresentation_UnsignedLong /* UL */ ||
1017 vr == ValueRepresentation_UnsignedShort /* US */);
1018 }
1019
1020
1021 bool IsLittleEndian() const
1022 {
1023 return (transferSyntax_ != DicomTransferSyntax_BigEndianExplicit);
1024 }
1025
1026
1027 void PrintBlock(const std::string& block)
1028 {
1029 for (size_t i = 0; i < block.size(); i++)
1030 {
1031 printf("%02x ", static_cast<uint8_t>(block[i]));
1032 if (i % 16 == 15)
1033 printf("\n");
1034 }
1035 printf("\n");
1036 }
1037
1038 void HandlePreamble(IVisitor& visitor,
1039 const std::string& block)
1040 {
1041 //printf("PREAMBLE:\n");
1042 //PrintBlock(block);
1043
1044 assert(block.size() == 144u);
1045 assert(reader_.GetProcessedBytes() == 144u);
1046
1047 /**
1048 * The "DICOM file meta information" is always encoded using
1049 * "Explicit VR Little Endian Transfer Syntax"
1050 * http://dicom.nema.org/medical/dicom/current/output/chtml/part10/chapter_7.html
1051 **/
1052 if (block[128] != 'D' ||
1053 block[129] != 'I' ||
1054 block[130] != 'C' ||
1055 block[131] != 'M' ||
1056 ReadTag(block.c_str() + 132, true) != DicomTag(0x0002, 0x0000) ||
1057 block[136] != 'U' ||
1058 block[137] != 'L' ||
1059 ReadUnsignedInteger16(block.c_str() + 138, true) != 4)
1060 {
1061 throw OrthancException(ErrorCode_BadFileFormat);
1062 }
1063
1064 uint32_t length = ReadUnsignedInteger32(block.c_str() + 140, true);
1065
1066 reader_.Schedule(length);
1067 state_ = State_MetaHeader;
1068 }
1069
1070
1071 void HandleMetaHeader(IVisitor& visitor,
1072 const std::string& block)
1073 {
1074 //printf("META-HEADER:\n");
1075 //PrintBlock(block);
1076
1077 size_t pos = 0;
1078 const char* p = block.c_str();
1079
1080 bool hasTransferSyntax = false;
1081
1082 while (pos + 8 <= block.size())
1083 {
1084 DicomTag tag = ReadTag(p + pos, true);
1085
1086 ValueRepresentation vr = StringToValueRepresentation(std::string(p + pos + 4, 2), true);
1087
1088 if (IsShortExplicitTag(vr))
1089 {
1090 uint16_t length = ReadUnsignedInteger16(p + pos + 6, true);
1091
1092 std::string value;
1093 value.assign(p + pos + 8, length);
1094
1095 if (tag.GetGroup() == 0x0002)
1096 {
1097 visitor.VisitMetaHeaderTag(tag, vr, value);
1098 }
1099
1100 if (tag == DICOM_TAG_TRANSFER_SYNTAX_UID)
1101 {
1102 // Remove possible padding byte
1103 if (!value.empty() &&
1104 value[value.size() - 1] == '\0')
1105 {
1106 value.resize(value.size() - 1);
1107 }
1108
1109 if (LookupTransferSyntax(transferSyntax_, value))
1110 {
1111 hasTransferSyntax = true;
1112 }
1113 else
1114 {
1115 throw OrthancException(ErrorCode_NotImplemented, "Unsupported transfer syntax: " + value);
1116 }
1117 }
1118
1119 pos += length + 8;
1120 }
1121 else if (pos + 12 <= block.size())
1122 {
1123 uint16_t reserved = ReadUnsignedInteger16(p + pos + 6, true);
1124 if (reserved != 0)
1125 {
1126 break;
1127 }
1128
1129 uint32_t length = ReadUnsignedInteger32(p + pos + 8, true);
1130
1131 std::string value;
1132 value.assign(p + pos + 12, length);
1133
1134 if (tag.GetGroup() == 0x0002)
1135 {
1136 visitor.VisitMetaHeaderTag(tag, vr, value);
1137 }
1138
1139 pos += length + 12;
1140 }
1141 }
1142
1143 if (pos != block.size())
1144 {
1145 throw OrthancException(ErrorCode_BadFileFormat);
1146 }
1147
1148 if (!hasTransferSyntax)
1149 {
1150 throw OrthancException(ErrorCode_BadFileFormat, "DICOM file meta-header without transfer syntax UID");
1151 }
1152
1153 reader_.Schedule(8);
1154 state_ = State_DatasetTag;
1155 }
1156
1157
1158 void HandleDatasetTag(const std::string& block,
1159 const DicomTag& untilTag)
1160 {
1161 static const DicomTag DICOM_TAG_SEQUENCE_ITEM(0xfffe, 0xe000);
1162 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_ITEM(0xfffe, 0xe00d);
1163 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE(0xfffe, 0xe0dd);
1164
1165 assert(block.size() == 8u);
1166
1167 const bool littleEndian = IsLittleEndian();
1168 DicomTag tag = ReadTag(block.c_str(), littleEndian);
1169
1170 if (sequenceDepth_ == 0 &&
1171 tag >= untilTag)
1172 {
1173 state_ = State_Done;
1174 return;
1175 }
1176
1177 if (tag == DICOM_TAG_SEQUENCE_ITEM ||
1178 tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM ||
1179 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE)
1180 {
1181 //printf("SEQUENCE TAG:\n");
1182 //PrintBlock(block);
1183
1184 // The special sequence items are encoded like "Implicit VR"
1185 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, littleEndian);
1186
1187 if (tag == DICOM_TAG_SEQUENCE_ITEM)
1188 {
1189 for (unsigned int i = 0; i <= sequenceDepth_; i++)
1190 printf(" ");
1191 if (length == 0xffffffffu)
1192 {
1193 // Undefined length: Need to loop over the tags of the nested dataset
1194 printf("...next dataset in sequence...\n");
1195 reader_.Schedule(8);
1196 state_ = State_DatasetTag;
1197 }
1198 else
1199 {
1200 // Explicit length: Can skip the full sequence at once
1201 printf("...next dataset in sequence... %u bytes\n", length);
1202 reader_.Schedule(length);
1203 state_ = State_DatasetValue;
1204 }
1205 }
1206 else if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM ||
1207 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE)
1208 {
1209 if (length != 0 ||
1210 sequenceDepth_ == 0)
1211 {
1212 throw OrthancException(ErrorCode_BadFileFormat);
1213 }
1214
1215 if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE)
1216 {
1217 for (unsigned int i = 0; i < sequenceDepth_; i++)
1218 printf(" ");
1219 printf("...leaving sequence...\n");
1220
1221 sequenceDepth_ --;
1222 }
1223 else
1224 {
1225 if (sequenceDepth_ == 0)
1226 {
1227 throw OrthancException(ErrorCode_BadFileFormat);
1228 }
1229 }
1230
1231 reader_.Schedule(8);
1232 state_ = State_DatasetTag;
1233 }
1234 else
1235 {
1236 throw OrthancException(ErrorCode_InternalError);
1237 }
1238 }
1239 else
1240 {
1241 //printf("DATASET TAG:\n");
1242 //PrintBlock(block);
1243
1244 previousTag_ = tag;
1245
1246 ValueRepresentation vr = ValueRepresentation_Unknown;
1247
1248 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit)
1249 {
1250 if (sequenceDepth_ == 0)
1251 {
1252 danglingTag_ = tag;
1253 danglingVR_ = vr;
1254 }
1255
1256 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */);
1257 HandleDatasetExplicitLength(length);
1258 }
1259 else
1260 {
1261 // This in an explicit transfer syntax
1262
1263 vr = StringToValueRepresentation(
1264 std::string(block.c_str() + 4, 2), false /* ignore unknown VR */);
1265
1266 if (vr != ValueRepresentation_Sequence &&
1267 sequenceDepth_ > 0)
1268 {
1269 for (unsigned int i = 0; i <= sequenceDepth_; i++)
1270 printf(" ");
1271 printf("%s\n", tag.Format().c_str());
1272 }
1273
1274 if (vr == ValueRepresentation_Sequence)
1275 {
1276 for (unsigned int i = 0; i <= sequenceDepth_; i++)
1277 printf(" ");
1278 printf("...entering sequence... %s\n", tag.Format().c_str());
1279 sequenceDepth_ ++;
1280 reader_.Schedule(4);
1281 state_ = State_SequenceExplicitLength;
1282 }
1283 else if (IsShortExplicitTag(vr))
1284 {
1285 uint16_t length = ReadUnsignedInteger16(block.c_str() + 6, littleEndian);
1286
1287 reader_.Schedule(length);
1288 state_ = State_DatasetValue;
1289 }
1290 else
1291 {
1292 uint16_t reserved = ReadUnsignedInteger16(block.c_str() + 6, littleEndian);
1293 if (reserved != 0)
1294 {
1295 throw OrthancException(ErrorCode_BadFileFormat);
1296 }
1297
1298 reader_.Schedule(4);
1299 state_ = State_DatasetExplicitLength;
1300 }
1301
1302 if (sequenceDepth_ == 0)
1303 {
1304 danglingTag_ = tag;
1305 danglingVR_ = vr;
1306 }
1307 }
1308 }
1309 }
1310
1311
1312 void HandleDatasetExplicitLength(uint32_t length)
1313 {
1314 if (length == 0xffffffffu)
1315 {
1316 /**
1317 * This is the case of pixel data with compressed transfer
1318 * syntaxes. Schedule the reading of the first tag of the
1319 * nested dataset.
1320 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.html
1321 **/
1322
1323 for (unsigned int i = 0; i <= sequenceDepth_; i++)
1324 printf(" ");
1325 printf("...entering sequence... %s\n", previousTag_.Format().c_str());
1326
1327 state_ = State_DatasetTag;
1328 reader_.Schedule(8);
1329 sequenceDepth_ ++;
1330 }
1331 else
1332 {
1333 reader_.Schedule(length);
1334 state_ = State_DatasetValue;
1335 }
1336 }
1337
1338 void HandleDatasetExplicitLength(const std::string& block)
1339 {
1340 //printf("DATASET TAG LENGTH:\n");
1341 //PrintBlock(block);
1342
1343 assert(block.size() == 4);
1344
1345 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian());
1346 HandleDatasetExplicitLength(length);
1347 }
1348
1349 void HandleSequenceExplicitLength(const std::string& block)
1350 {
1351 //printf("DATASET TAG LENGTH:\n");
1352 //PrintBlock(block);
1353
1354 assert(block.size() == 4);
1355
1356 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian());
1357 if (length == 0xffffffffu)
1358 {
1359 state_ = State_DatasetTag;
1360 reader_.Schedule(8);
1361 }
1362 else
1363 {
1364 for (unsigned int i = 0; i <= sequenceDepth_; i++)
1365 printf(" ");
1366 printf("...skipping sequence thanks to explicit length... %d\n", length);
1367
1368 reader_.Schedule(length);
1369 state_ = State_SequenceExplicitValue;
1370 }
1371 }
1372
1373 void HandleSequenceExplicitValue()
1374 {
1375 if (sequenceDepth_ == 0)
1376 {
1377 throw OrthancException(ErrorCode_InternalError);
1378 }
1379
1380 sequenceDepth_ --;
1381
1382 state_ = State_DatasetTag;
1383 reader_.Schedule(8);
1384 }
1385
1386
1387 void HandleDatasetValue(IVisitor& visitor,
1388 const std::string& block)
1389 {
1390 if (sequenceDepth_ == 0)
1391 {
1392 bool c;
1393
1394 if (!block.empty() &&
1395 (block[block.size() - 1] == ' ' ||
1396 block[block.size() - 1] == '\0') &&
1397 (danglingVR_ == ValueRepresentation_ApplicationEntity ||
1398 danglingVR_ == ValueRepresentation_AgeString ||
1399 danglingVR_ == ValueRepresentation_CodeString ||
1400 danglingVR_ == ValueRepresentation_DecimalString ||
1401 danglingVR_ == ValueRepresentation_IntegerString ||
1402 danglingVR_ == ValueRepresentation_LongString ||
1403 danglingVR_ == ValueRepresentation_LongText ||
1404 danglingVR_ == ValueRepresentation_PersonName ||
1405 danglingVR_ == ValueRepresentation_ShortString ||
1406 danglingVR_ == ValueRepresentation_ShortText ||
1407 danglingVR_ == ValueRepresentation_UniqueIdentifier ||
1408 danglingVR_ == ValueRepresentation_UnlimitedText))
1409 {
1410 std::string s(block.begin(), block.end() - 1);
1411 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, s, IsLittleEndian());
1412 }
1413 else
1414 {
1415 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, block, IsLittleEndian());
1416 }
1417
1418 if (!c)
1419 {
1420 state_ = State_Done;
1421 return;
1422 }
1423 }
1424
1425 reader_.Schedule(8);
1426 state_ = State_DatasetTag;
1427 }
1428
1429
1430 public:
1431 DicomStreamReader(std::istream& stream) :
1432 reader_(stream),
1433 state_(State_Preamble),
1434 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy
1435 previousTag_(0x0000, 0x0000), // Dummy
1436 danglingTag_(0x0000, 0x0000), // Dummy
1437 danglingVR_(ValueRepresentation_Unknown), // Dummy
1438 sequenceDepth_(0)
1439 {
1440 reader_.Schedule(128 /* empty header */ +
1441 4 /* "DICM" magic value */ +
1442 4 /* (0x0002, 0x0000) tag */ +
1443 2 /* value representation of (0x0002, 0x0000) == "UL" */ +
1444 2 /* length of "UL" value == 4 */ +
1445 4 /* actual length of the meta-header */);
1446 }
1447
1448 void Consume(IVisitor& visitor,
1449 const DicomTag& untilTag)
1450 {
1451 while (state_ != State_Done)
1452 {
1453 std::string block;
1454 if (reader_.Read(block))
1455 {
1456 switch (state_)
1457 {
1458 case State_Preamble:
1459 HandlePreamble(visitor, block);
1460 break;
1461
1462 case State_MetaHeader:
1463 HandleMetaHeader(visitor, block);
1464 break;
1465
1466 case State_DatasetTag:
1467 HandleDatasetTag(block, untilTag);
1468 break;
1469
1470 case State_DatasetExplicitLength:
1471 HandleDatasetExplicitLength(block);
1472 break;
1473
1474 case State_SequenceExplicitLength:
1475 HandleSequenceExplicitLength(block);
1476 break;
1477
1478 case State_SequenceExplicitValue:
1479 HandleSequenceExplicitValue();
1480 break;
1481
1482 case State_DatasetValue:
1483 HandleDatasetValue(visitor, block);
1484 break;
1485
1486 default:
1487 throw OrthancException(ErrorCode_InternalError);
1488 }
1489 }
1490 else
1491 {
1492 return; // No more data in the stream
1493 }
1494 }
1495 }
1496
1497 void Consume(IVisitor& visitor)
1498 {
1499 DicomTag untilTag(0xffff, 0xffff);
1500 Consume(visitor, untilTag);
1501 }
1502
1503 bool IsDone() const
1504 {
1505 return (state_ == State_Done);
1506 }
1507
1508 uint64_t GetProcessedBytes() const
1509 {
1510 return reader_.GetProcessedBytes();
1511 }
1512 };
1513
1514
1515
1516 class V : public DicomStreamReader::IVisitor 802 class V : public DicomStreamReader::IVisitor
1517 { 803 {
1518 private: 804 private:
1519 DicomMap map_; 805 DicomMap map_;
1520 806
1529 const std::string& value) ORTHANC_OVERRIDE 815 const std::string& value) ORTHANC_OVERRIDE
1530 { 816 {
1531 std::cout << "Header: " << tag.Format() << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl; 817 std::cout << "Header: " << tag.Format() << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl;
1532 } 818 }
1533 819
820 virtual void VisitTransferSyntax(DicomTransferSyntax transferSyntax) ORTHANC_OVERRIDE
821 {
822 printf("TRANSFER SYNTAX: %s\n", GetTransferSyntaxUid(transferSyntax));
823 }
824
1534 virtual bool VisitDatasetTag(const DicomTag& tag, 825 virtual bool VisitDatasetTag(const DicomTag& tag,
1535 const ValueRepresentation& vr, 826 const ValueRepresentation& vr,
1536 DicomTransferSyntax transferSyntax,
1537 const std::string& value, 827 const std::string& value,
1538 bool isLittleEndian) ORTHANC_OVERRIDE 828 bool isLittleEndian) ORTHANC_OVERRIDE
1539 { 829 {
1540 if (!isLittleEndian) 830 if (!isLittleEndian)
1541 printf("** "); 831 printf("** ");
1646 DicomStreamReader r(stream); 936 DicomStreamReader r(stream);
1647 V visitor; 937 V visitor;
1648 938
1649 try 939 try
1650 { 940 {
1651 //r.Consume(visitor, DICOM_TAG_PIXEL_DATA); 941 r.Consume(visitor, DICOM_TAG_PIXEL_DATA);
1652 r.Consume(visitor); 942 //r.Consume(visitor);
1653 success++; 943 success++;
1654 } 944 }
1655 catch (OrthancException& e) 945 catch (OrthancException& e)
1656 { 946 {
1657 errors.insert(path); 947 errors.insert(path);