Mercurial > hg > orthanc
comparison OrthancServer/UnitTestsSources/DicomMapTests.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | UnitTestsSources/DicomMapTests.cpp@2a170a8f1faf |
children | 05b8fd21089c |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "PrecompiledHeadersUnitTests.h" | |
35 #include "gtest/gtest.h" | |
36 | |
37 #include "../Core/Compatibility.h" | |
38 #include "../Core/OrthancException.h" | |
39 #include "../Core/DicomFormat/DicomMap.h" | |
40 #include "../Core/DicomParsing/FromDcmtkBridge.h" | |
41 #include "../Core/DicomParsing/ToDcmtkBridge.h" | |
42 #include "../Core/DicomParsing/ParsedDicomFile.h" | |
43 #include "../Core/DicomParsing/DicomWebJsonVisitor.h" | |
44 | |
45 #include "../OrthancServer/DicomInstanceToStore.h" | |
46 | |
47 #include <memory> | |
48 #include <dcmtk/dcmdata/dcdeftag.h> | |
49 #include <dcmtk/dcmdata/dcvrat.h> | |
50 | |
51 using namespace Orthanc; | |
52 | |
53 TEST(DicomMap, MainTags) | |
54 { | |
55 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_PATIENT_ID)); | |
56 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_PATIENT_ID, ResourceType_Patient)); | |
57 ASSERT_FALSE(DicomMap::IsMainDicomTag(DICOM_TAG_PATIENT_ID, ResourceType_Study)); | |
58 | |
59 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); | |
60 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_ACCESSION_NUMBER)); | |
61 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); | |
62 ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_SOP_INSTANCE_UID)); | |
63 | |
64 std::set<DicomTag> s; | |
65 DicomMap::GetMainDicomTags(s); | |
66 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_PATIENT_ID)); | |
67 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_STUDY_INSTANCE_UID)); | |
68 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_ACCESSION_NUMBER)); | |
69 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SERIES_INSTANCE_UID)); | |
70 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SOP_INSTANCE_UID)); | |
71 | |
72 DicomMap::GetMainDicomTags(s, ResourceType_Patient); | |
73 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_PATIENT_ID)); | |
74 ASSERT_TRUE(s.end() == s.find(DICOM_TAG_STUDY_INSTANCE_UID)); | |
75 | |
76 DicomMap::GetMainDicomTags(s, ResourceType_Study); | |
77 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_STUDY_INSTANCE_UID)); | |
78 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_ACCESSION_NUMBER)); | |
79 ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); | |
80 | |
81 DicomMap::GetMainDicomTags(s, ResourceType_Series); | |
82 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SERIES_INSTANCE_UID)); | |
83 ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); | |
84 | |
85 DicomMap::GetMainDicomTags(s, ResourceType_Instance); | |
86 ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SOP_INSTANCE_UID)); | |
87 ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); | |
88 } | |
89 | |
90 | |
91 TEST(DicomMap, Tags) | |
92 { | |
93 std::set<DicomTag> s; | |
94 | |
95 DicomMap m; | |
96 m.GetTags(s); | |
97 ASSERT_EQ(0u, s.size()); | |
98 | |
99 ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_NAME)); | |
100 ASSERT_FALSE(m.HasTag(0x0010, 0x0010)); | |
101 m.SetValue(0x0010, 0x0010, "PatientName", false); | |
102 ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_NAME)); | |
103 ASSERT_TRUE(m.HasTag(0x0010, 0x0010)); | |
104 | |
105 m.GetTags(s); | |
106 ASSERT_EQ(1u, s.size()); | |
107 ASSERT_EQ(DICOM_TAG_PATIENT_NAME, *s.begin()); | |
108 | |
109 ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_ID)); | |
110 m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID", false); | |
111 ASSERT_TRUE(m.HasTag(0x0010, 0x0020)); | |
112 m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID2", false); | |
113 ASSERT_EQ("PatientID2", m.GetValue(0x0010, 0x0020).GetContent()); | |
114 | |
115 m.GetTags(s); | |
116 ASSERT_EQ(2u, s.size()); | |
117 | |
118 m.Remove(DICOM_TAG_PATIENT_ID); | |
119 ASSERT_THROW(m.GetValue(0x0010, 0x0020), OrthancException); | |
120 | |
121 m.GetTags(s); | |
122 ASSERT_EQ(1u, s.size()); | |
123 ASSERT_EQ(DICOM_TAG_PATIENT_NAME, *s.begin()); | |
124 | |
125 std::unique_ptr<DicomMap> mm(m.Clone()); | |
126 ASSERT_EQ("PatientName", mm->GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); | |
127 | |
128 m.SetValue(DICOM_TAG_PATIENT_ID, "Hello", false); | |
129 ASSERT_THROW(mm->GetValue(DICOM_TAG_PATIENT_ID), OrthancException); | |
130 mm->CopyTagIfExists(m, DICOM_TAG_PATIENT_ID); | |
131 ASSERT_EQ("Hello", mm->GetValue(DICOM_TAG_PATIENT_ID).GetContent()); | |
132 | |
133 DicomValue v; | |
134 ASSERT_TRUE(v.IsNull()); | |
135 } | |
136 | |
137 | |
138 TEST(DicomMap, FindTemplates) | |
139 { | |
140 DicomMap m; | |
141 | |
142 DicomMap::SetupFindPatientTemplate(m); | |
143 ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_ID)); | |
144 | |
145 DicomMap::SetupFindStudyTemplate(m); | |
146 ASSERT_TRUE(m.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)); | |
147 ASSERT_TRUE(m.HasTag(DICOM_TAG_ACCESSION_NUMBER)); | |
148 | |
149 DicomMap::SetupFindSeriesTemplate(m); | |
150 ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)); | |
151 | |
152 DicomMap::SetupFindInstanceTemplate(m); | |
153 ASSERT_TRUE(m.HasTag(DICOM_TAG_SOP_INSTANCE_UID)); | |
154 } | |
155 | |
156 | |
157 | |
158 | |
159 static void TestModule(ResourceType level, | |
160 DicomModule module) | |
161 { | |
162 // REFERENCE: DICOM PS3.3 2015c - Information Object Definitions | |
163 // http://dicom.nema.org/medical/dicom/current/output/html/part03.html | |
164 | |
165 std::set<DicomTag> moduleTags, main; | |
166 DicomTag::AddTagsForModule(moduleTags, module); | |
167 DicomMap::GetMainDicomTags(main, level); | |
168 | |
169 // The main dicom tags are a subset of the module | |
170 for (std::set<DicomTag>::const_iterator it = main.begin(); it != main.end(); ++it) | |
171 { | |
172 bool ok = moduleTags.find(*it) != moduleTags.end(); | |
173 | |
174 // Exceptions for the Study level | |
175 if (level == ResourceType_Study && | |
176 (*it == DicomTag(0x0008, 0x0080) || /* InstitutionName, from Visit identification module, related to Visit */ | |
177 *it == DicomTag(0x0032, 0x1032) || /* RequestingPhysician, from Imaging Service Request module, related to Study */ | |
178 *it == DicomTag(0x0032, 0x1060))) /* RequestedProcedureDescription, from Requested Procedure module, related to Study */ | |
179 { | |
180 ok = true; | |
181 } | |
182 | |
183 // Exceptions for the Series level | |
184 if (level == ResourceType_Series && | |
185 (*it == DicomTag(0x0008, 0x0070) || /* Manufacturer, from General Equipment Module */ | |
186 *it == DicomTag(0x0008, 0x1010) || /* StationName, from General Equipment Module */ | |
187 *it == DicomTag(0x0018, 0x0024) || /* SequenceName, from MR Image Module (SIMPLIFICATION => Series) */ | |
188 *it == DicomTag(0x0018, 0x1090) || /* CardiacNumberOfImages, from MR Image Module (SIMPLIFICATION => Series) */ | |
189 *it == DicomTag(0x0020, 0x0037) || /* ImageOrientationPatient, from Image Plane Module (SIMPLIFICATION => Series) */ | |
190 *it == DicomTag(0x0020, 0x0105) || /* NumberOfTemporalPositions, from MR Image Module (SIMPLIFICATION => Series) */ | |
191 *it == DicomTag(0x0020, 0x1002) || /* ImagesInAcquisition, from General Image Module (SIMPLIFICATION => Series) */ | |
192 *it == DicomTag(0x0054, 0x0081) || /* NumberOfSlices, from PET Series module */ | |
193 *it == DicomTag(0x0054, 0x0101) || /* NumberOfTimeSlices, from PET Series module */ | |
194 *it == DicomTag(0x0054, 0x1000) || /* SeriesType, from PET Series module */ | |
195 *it == DicomTag(0x0018, 0x1400) || /* AcquisitionDeviceProcessingDescription, from CR/X-Ray/DX/WholeSlideMicro Image (SIMPLIFICATION => Series) */ | |
196 *it == DicomTag(0x0018, 0x0010))) /* ContrastBolusAgent, from Contrast/Bolus module (SIMPLIFICATION => Series) */ | |
197 { | |
198 ok = true; | |
199 } | |
200 | |
201 // Exceptions for the Instance level | |
202 if (level == ResourceType_Instance && | |
203 (*it == DicomTag(0x0020, 0x0012) || /* AccessionNumber, from General Image module */ | |
204 *it == DicomTag(0x0054, 0x1330) || /* ImageIndex, from PET Image module */ | |
205 *it == DicomTag(0x0020, 0x0100) || /* TemporalPositionIdentifier, from MR Image module */ | |
206 *it == DicomTag(0x0028, 0x0008) || /* NumberOfFrames, from Multi-frame module attributes, related to Image */ | |
207 *it == DicomTag(0x0020, 0x0032) || /* ImagePositionPatient, from Image Plan module, related to Image */ | |
208 *it == DicomTag(0x0020, 0x0037) || /* ImageOrientationPatient, from Image Plane Module (Orthanc 1.4.2) */ | |
209 *it == DicomTag(0x0020, 0x4000))) /* ImageComments, from General Image module */ | |
210 { | |
211 ok = true; | |
212 } | |
213 | |
214 if (!ok) | |
215 { | |
216 std::cout << it->Format() << ": " << FromDcmtkBridge::GetTagName(*it, "") | |
217 << " not expected at level " << EnumerationToString(level) << std::endl; | |
218 } | |
219 | |
220 EXPECT_TRUE(ok); | |
221 } | |
222 } | |
223 | |
224 | |
225 TEST(DicomMap, Modules) | |
226 { | |
227 TestModule(ResourceType_Patient, DicomModule_Patient); | |
228 TestModule(ResourceType_Study, DicomModule_Study); | |
229 TestModule(ResourceType_Series, DicomModule_Series); // TODO | |
230 TestModule(ResourceType_Instance, DicomModule_Instance); | |
231 } | |
232 | |
233 | |
234 TEST(DicomMap, Parse) | |
235 { | |
236 DicomMap m; | |
237 float f; | |
238 double d; | |
239 int32_t i; | |
240 int64_t j; | |
241 uint32_t k; | |
242 uint64_t l; | |
243 unsigned int ui; | |
244 std::string s; | |
245 | |
246 m.SetValue(DICOM_TAG_PATIENT_NAME, " ", false); // Empty value | |
247 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
248 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
249 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
250 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
251 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
252 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
253 | |
254 m.SetValue(DICOM_TAG_PATIENT_NAME, "0", true); // Binary value | |
255 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
256 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
257 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
258 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
259 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
260 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
261 | |
262 ASSERT_FALSE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false)); | |
263 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, true)); | |
264 ASSERT_EQ("0", s); | |
265 | |
266 | |
267 // 2**31-1 | |
268 m.SetValue(DICOM_TAG_PATIENT_NAME, "2147483647", false); | |
269 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
270 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
271 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
272 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
273 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
274 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
275 ASSERT_FLOAT_EQ(2147483647.0f, f); | |
276 ASSERT_DOUBLE_EQ(2147483647.0, d); | |
277 ASSERT_EQ(2147483647, i); | |
278 ASSERT_EQ(2147483647ll, j); | |
279 ASSERT_EQ(2147483647u, k); | |
280 ASSERT_EQ(2147483647ull, l); | |
281 | |
282 // Test shortcuts | |
283 m.SetValue(DICOM_TAG_PATIENT_NAME, "42", false); | |
284 ASSERT_TRUE(m.ParseFloat(f, DICOM_TAG_PATIENT_NAME)); | |
285 ASSERT_TRUE(m.ParseDouble(d, DICOM_TAG_PATIENT_NAME)); | |
286 ASSERT_TRUE(m.ParseInteger32(i, DICOM_TAG_PATIENT_NAME)); | |
287 ASSERT_TRUE(m.ParseInteger64(j, DICOM_TAG_PATIENT_NAME)); | |
288 ASSERT_TRUE(m.ParseUnsignedInteger32(k, DICOM_TAG_PATIENT_NAME)); | |
289 ASSERT_TRUE(m.ParseUnsignedInteger64(l, DICOM_TAG_PATIENT_NAME)); | |
290 ASSERT_FLOAT_EQ(42.0f, f); | |
291 ASSERT_DOUBLE_EQ(42.0, d); | |
292 ASSERT_EQ(42, i); | |
293 ASSERT_EQ(42ll, j); | |
294 ASSERT_EQ(42u, k); | |
295 ASSERT_EQ(42ull, l); | |
296 | |
297 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false)); | |
298 ASSERT_EQ("42", s); | |
299 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, true)); | |
300 ASSERT_EQ("42", s); | |
301 | |
302 | |
303 // 2**31 | |
304 m.SetValue(DICOM_TAG_PATIENT_NAME, "2147483648", false); | |
305 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
306 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
307 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
308 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
309 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
310 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
311 ASSERT_FLOAT_EQ(2147483648.0f, f); | |
312 ASSERT_DOUBLE_EQ(2147483648.0, d); | |
313 ASSERT_EQ(2147483648ll, j); | |
314 ASSERT_EQ(2147483648u, k); | |
315 ASSERT_EQ(2147483648ull, l); | |
316 | |
317 // 2**32-1 | |
318 m.SetValue(DICOM_TAG_PATIENT_NAME, "4294967295", false); | |
319 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
320 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
321 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
322 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
323 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
324 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
325 ASSERT_FLOAT_EQ(4294967295.0f, f); | |
326 ASSERT_DOUBLE_EQ(4294967295.0, d); | |
327 ASSERT_EQ(4294967295ll, j); | |
328 ASSERT_EQ(4294967295u, k); | |
329 ASSERT_EQ(4294967295ull, l); | |
330 | |
331 // 2**32 | |
332 m.SetValue(DICOM_TAG_PATIENT_NAME, "4294967296", false); | |
333 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
334 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
335 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
336 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
337 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
338 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
339 ASSERT_FLOAT_EQ(4294967296.0f, f); | |
340 ASSERT_DOUBLE_EQ(4294967296.0, d); | |
341 ASSERT_EQ(4294967296ll, j); | |
342 ASSERT_EQ(4294967296ull, l); | |
343 | |
344 m.SetValue(DICOM_TAG_PATIENT_NAME, "-1", false); | |
345 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
346 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
347 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
348 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
349 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
350 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
351 ASSERT_FLOAT_EQ(-1.0f, f); | |
352 ASSERT_DOUBLE_EQ(-1.0, d); | |
353 ASSERT_EQ(-1, i); | |
354 ASSERT_EQ(-1ll, j); | |
355 | |
356 // -2**31 | |
357 m.SetValue(DICOM_TAG_PATIENT_NAME, "-2147483648", false); | |
358 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
359 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
360 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
361 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
362 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
363 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
364 ASSERT_FLOAT_EQ(-2147483648.0f, f); | |
365 ASSERT_DOUBLE_EQ(-2147483648.0, d); | |
366 ASSERT_EQ(static_cast<int32_t>(-2147483648ll), i); | |
367 ASSERT_EQ(-2147483648ll, j); | |
368 | |
369 // -2**31 - 1 | |
370 m.SetValue(DICOM_TAG_PATIENT_NAME, "-2147483649", false); | |
371 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f)); | |
372 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d)); | |
373 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i)); | |
374 ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j)); | |
375 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k)); | |
376 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l)); | |
377 ASSERT_FLOAT_EQ(-2147483649.0f, f); | |
378 ASSERT_DOUBLE_EQ(-2147483649.0, d); | |
379 ASSERT_EQ(-2147483649ll, j); | |
380 | |
381 | |
382 // "800\0" in US COLMUNS tag | |
383 m.SetValue(DICOM_TAG_COLUMNS, "800\0", false); | |
384 ASSERT_TRUE(m.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(ui)); | |
385 ASSERT_EQ(800u, ui); | |
386 m.SetValue(DICOM_TAG_COLUMNS, "800", false); | |
387 ASSERT_TRUE(m.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(ui)); | |
388 ASSERT_EQ(800u, ui); | |
389 } | |
390 | |
391 | |
392 TEST(DicomMap, Serialize) | |
393 { | |
394 Json::Value s; | |
395 | |
396 { | |
397 DicomMap m; | |
398 m.SetValue(DICOM_TAG_PATIENT_NAME, "Hello", false); | |
399 m.SetValue(DICOM_TAG_STUDY_DESCRIPTION, "Binary", true); | |
400 m.SetNullValue(DICOM_TAG_SERIES_DESCRIPTION); | |
401 m.Serialize(s); | |
402 } | |
403 | |
404 { | |
405 DicomMap m; | |
406 m.Unserialize(s); | |
407 | |
408 const DicomValue* v = m.TestAndGetValue(DICOM_TAG_ACCESSION_NUMBER); | |
409 ASSERT_TRUE(v == NULL); | |
410 | |
411 v = m.TestAndGetValue(DICOM_TAG_PATIENT_NAME); | |
412 ASSERT_TRUE(v != NULL); | |
413 ASSERT_FALSE(v->IsNull()); | |
414 ASSERT_FALSE(v->IsBinary()); | |
415 ASSERT_EQ("Hello", v->GetContent()); | |
416 | |
417 v = m.TestAndGetValue(DICOM_TAG_STUDY_DESCRIPTION); | |
418 ASSERT_TRUE(v != NULL); | |
419 ASSERT_FALSE(v->IsNull()); | |
420 ASSERT_TRUE(v->IsBinary()); | |
421 ASSERT_EQ("Binary", v->GetContent()); | |
422 | |
423 v = m.TestAndGetValue(DICOM_TAG_SERIES_DESCRIPTION); | |
424 ASSERT_TRUE(v != NULL); | |
425 ASSERT_TRUE(v->IsNull()); | |
426 ASSERT_FALSE(v->IsBinary()); | |
427 ASSERT_THROW(v->GetContent(), OrthancException); | |
428 } | |
429 } | |
430 | |
431 | |
432 | |
433 TEST(DicomMap, DicomAsJson) | |
434 { | |
435 // This is a Latin-1 test string: "crane" with a circumflex accent | |
436 const unsigned char raw[] = { 0x63, 0x72, 0xe2, 0x6e, 0x65 }; | |
437 std::string latin1((char*) &raw[0], sizeof(raw) / sizeof(char)); | |
438 | |
439 std::string utf8 = Toolbox::ConvertToUtf8(latin1, Encoding_Latin1, false); | |
440 | |
441 ParsedDicomFile dicom(false); | |
442 dicom.SetEncoding(Encoding_Latin1); | |
443 dicom.ReplacePlainString(DICOM_TAG_PATIENT_NAME, "Hello"); | |
444 dicom.ReplacePlainString(DICOM_TAG_STUDY_DESCRIPTION, utf8); | |
445 dicom.ReplacePlainString(DICOM_TAG_SERIES_DESCRIPTION, std::string(ORTHANC_MAXIMUM_TAG_LENGTH, 'a')); | |
446 dicom.ReplacePlainString(DICOM_TAG_MANUFACTURER, std::string(ORTHANC_MAXIMUM_TAG_LENGTH + 1, 'a')); | |
447 dicom.ReplacePlainString(DICOM_TAG_PIXEL_DATA, "binary"); | |
448 dicom.ReplacePlainString(DICOM_TAG_ROWS, "512"); | |
449 | |
450 DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset(); | |
451 dataset.insertEmptyElement(DCM_StudyID, OFFalse); | |
452 | |
453 { | |
454 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence)); | |
455 | |
456 { | |
457 std::unique_ptr<DcmItem> item(new DcmItem); | |
458 item->putAndInsertString(DCM_ReferencedSOPInstanceUID, "nope", OFFalse); | |
459 ASSERT_TRUE(sequence->insert(item.release(), false, false).good()); | |
460 } | |
461 | |
462 ASSERT_TRUE(dataset.insert(sequence.release(), false, false).good()); | |
463 } | |
464 | |
465 | |
466 // Check re-encoding | |
467 DcmElement* element = NULL; | |
468 ASSERT_TRUE(dataset.findAndGetElement(DCM_StudyDescription, element).good() && | |
469 element != NULL); | |
470 | |
471 char* c = NULL; | |
472 ASSERT_TRUE(element != NULL && | |
473 element->isLeaf() && | |
474 element->isaString() && | |
475 element->getString(c).good()); | |
476 ASSERT_EQ(0, memcmp(c, raw, latin1.length())); | |
477 | |
478 ASSERT_TRUE(dataset.findAndGetElement(DCM_Rows, element).good() && | |
479 element != NULL && | |
480 element->getTag().getEVR() == EVR_US); | |
481 | |
482 DicomInstanceToStore toStore; | |
483 toStore.SetParsedDicomFile(dicom); | |
484 | |
485 DicomMap m; | |
486 m.FromDicomAsJson(toStore.GetJson()); | |
487 | |
488 ASSERT_EQ("ISO_IR 100", m.GetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET).GetContent()); | |
489 | |
490 ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).IsBinary()); | |
491 ASSERT_EQ("Hello", m.GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); | |
492 | |
493 ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_DESCRIPTION).IsBinary()); | |
494 ASSERT_EQ(utf8, m.GetValue(DICOM_TAG_STUDY_DESCRIPTION).GetContent()); | |
495 | |
496 ASSERT_FALSE(m.HasTag(DICOM_TAG_MANUFACTURER)); // Too long | |
497 ASSERT_FALSE(m.HasTag(DICOM_TAG_PIXEL_DATA)); // Pixel data | |
498 ASSERT_FALSE(m.HasTag(DICOM_TAG_REFERENCED_SERIES_SEQUENCE)); // Sequence | |
499 ASSERT_EQ(DICOM_TAG_REFERENCED_SERIES_SEQUENCE.GetGroup(), DCM_ReferencedSeriesSequence.getGroup()); | |
500 ASSERT_EQ(DICOM_TAG_REFERENCED_SERIES_SEQUENCE.GetElement(), DCM_ReferencedSeriesSequence.getElement()); | |
501 | |
502 ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_DESCRIPTION)); // Maximum length | |
503 ASSERT_FALSE(m.GetValue(DICOM_TAG_SERIES_DESCRIPTION).IsBinary()); | |
504 ASSERT_EQ(ORTHANC_MAXIMUM_TAG_LENGTH, | |
505 static_cast<int>(m.GetValue(DICOM_TAG_SERIES_DESCRIPTION).GetContent().length())); | |
506 | |
507 ASSERT_FALSE(m.GetValue(DICOM_TAG_ROWS).IsBinary()); | |
508 ASSERT_EQ("512", m.GetValue(DICOM_TAG_ROWS).GetContent()); | |
509 | |
510 ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_ID).IsNull()); | |
511 ASSERT_FALSE(m.GetValue(DICOM_TAG_STUDY_ID).IsBinary()); | |
512 ASSERT_EQ("", m.GetValue(DICOM_TAG_STUDY_ID).GetContent()); | |
513 | |
514 DicomArray a(m); | |
515 ASSERT_EQ(6u, a.GetSize()); | |
516 | |
517 | |
518 //dicom.SaveToFile("/tmp/test.dcm"); | |
519 //std::cout << toStore.GetJson() << std::endl; | |
520 //a.Print(stdout); | |
521 } | |
522 | |
523 | |
524 | |
525 TEST(DicomMap, ExtractMainDicomTags) | |
526 { | |
527 DicomMap b; | |
528 b.SetValue(DICOM_TAG_PATIENT_NAME, "E", false); | |
529 ASSERT_TRUE(b.HasOnlyMainDicomTags()); | |
530 | |
531 { | |
532 DicomMap a; | |
533 a.SetValue(DICOM_TAG_PATIENT_NAME, "A", false); | |
534 a.SetValue(DICOM_TAG_STUDY_DESCRIPTION, "B", false); | |
535 a.SetValue(DICOM_TAG_SERIES_DESCRIPTION, "C", false); | |
536 a.SetValue(DICOM_TAG_NUMBER_OF_FRAMES, "D", false); | |
537 a.SetValue(DICOM_TAG_SLICE_THICKNESS, "F", false); | |
538 ASSERT_FALSE(a.HasOnlyMainDicomTags()); | |
539 b.ExtractMainDicomTags(a); | |
540 } | |
541 | |
542 ASSERT_EQ(4u, b.GetSize()); | |
543 ASSERT_EQ("A", b.GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); | |
544 ASSERT_EQ("B", b.GetValue(DICOM_TAG_STUDY_DESCRIPTION).GetContent()); | |
545 ASSERT_EQ("C", b.GetValue(DICOM_TAG_SERIES_DESCRIPTION).GetContent()); | |
546 ASSERT_EQ("D", b.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent()); | |
547 ASSERT_FALSE(b.HasTag(DICOM_TAG_SLICE_THICKNESS)); | |
548 ASSERT_TRUE(b.HasOnlyMainDicomTags()); | |
549 | |
550 b.SetValue(DICOM_TAG_PATIENT_NAME, "G", false); | |
551 | |
552 { | |
553 DicomMap a; | |
554 a.SetValue(DICOM_TAG_PATIENT_NAME, "A", false); | |
555 a.SetValue(DICOM_TAG_SLICE_THICKNESS, "F", false); | |
556 ASSERT_FALSE(a.HasOnlyMainDicomTags()); | |
557 b.Merge(a); | |
558 } | |
559 | |
560 ASSERT_EQ(5u, b.GetSize()); | |
561 ASSERT_EQ("G", b.GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); | |
562 ASSERT_EQ("B", b.GetValue(DICOM_TAG_STUDY_DESCRIPTION).GetContent()); | |
563 ASSERT_EQ("C", b.GetValue(DICOM_TAG_SERIES_DESCRIPTION).GetContent()); | |
564 ASSERT_EQ("D", b.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent()); | |
565 ASSERT_EQ("F", b.GetValue(DICOM_TAG_SLICE_THICKNESS).GetContent()); | |
566 ASSERT_FALSE(b.HasOnlyMainDicomTags()); | |
567 } | |
568 | |
569 | |
570 TEST(DicomMap, RemoveBinary) | |
571 { | |
572 DicomMap b; | |
573 b.SetValue(DICOM_TAG_PATIENT_NAME, "A", false); | |
574 b.SetValue(DICOM_TAG_PATIENT_ID, "B", true); | |
575 b.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, DicomValue()); // NULL | |
576 b.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, DicomValue("C", false)); | |
577 b.SetValue(DICOM_TAG_SOP_INSTANCE_UID, DicomValue("D", true)); | |
578 | |
579 b.RemoveBinaryTags(); | |
580 | |
581 std::string s; | |
582 ASSERT_EQ(2u, b.GetSize()); | |
583 ASSERT_TRUE(b.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false)); ASSERT_EQ("A", s); | |
584 ASSERT_TRUE(b.LookupStringValue(s, DICOM_TAG_SERIES_INSTANCE_UID, false)); ASSERT_EQ("C", s); | |
585 } | |
586 | |
587 | |
588 | |
589 TEST(DicomWebJson, Multiplicity) | |
590 { | |
591 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.4.html | |
592 | |
593 ParsedDicomFile dicom(false); | |
594 dicom.ReplacePlainString(DICOM_TAG_PATIENT_NAME, "SB1^SB2^SB3^SB4^SB5"); | |
595 dicom.ReplacePlainString(DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "1\\2.3\\4"); | |
596 dicom.ReplacePlainString(DICOM_TAG_IMAGE_POSITION_PATIENT, ""); | |
597 | |
598 DicomWebJsonVisitor visitor; | |
599 dicom.Apply(visitor); | |
600 | |
601 { | |
602 const Json::Value& tag = visitor.GetResult() ["00200037"]; // ImageOrientationPatient | |
603 const Json::Value& value = tag["Value"]; | |
604 | |
605 ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); | |
606 ASSERT_EQ(2u, tag.getMemberNames().size()); | |
607 ASSERT_EQ(3u, value.size()); | |
608 ASSERT_EQ(Json::realValue, value[1].type()); | |
609 ASSERT_FLOAT_EQ(1.0f, value[0].asFloat()); | |
610 ASSERT_FLOAT_EQ(2.3f, value[1].asFloat()); | |
611 ASSERT_FLOAT_EQ(4.0f, value[2].asFloat()); | |
612 } | |
613 | |
614 { | |
615 const Json::Value& tag = visitor.GetResult() ["00200032"]; // ImagePositionPatient | |
616 ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); | |
617 ASSERT_EQ(1u, tag.getMemberNames().size()); | |
618 } | |
619 | |
620 std::string xml; | |
621 visitor.FormatXml(xml); | |
622 | |
623 { | |
624 DicomMap m; | |
625 m.FromDicomWeb(visitor.GetResult()); | |
626 ASSERT_EQ(3u, m.GetSize()); | |
627 | |
628 std::string s; | |
629 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false)); | |
630 ASSERT_EQ("SB1^SB2^SB3^SB4^SB5", s); | |
631 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_POSITION_PATIENT, false)); | |
632 ASSERT_TRUE(s.empty()); | |
633 | |
634 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false)); | |
635 | |
636 std::vector<std::string> v; | |
637 Toolbox::TokenizeString(v, s, '\\'); | |
638 ASSERT_FLOAT_EQ(1.0f, boost::lexical_cast<float>(v[0])); | |
639 ASSERT_FLOAT_EQ(2.3f, boost::lexical_cast<float>(v[1])); | |
640 ASSERT_FLOAT_EQ(4.0f, boost::lexical_cast<float>(v[2])); | |
641 } | |
642 } | |
643 | |
644 | |
645 TEST(DicomWebJson, NullValue) | |
646 { | |
647 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.5.html | |
648 | |
649 ParsedDicomFile dicom(false); | |
650 dicom.ReplacePlainString(DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "1.5\\\\\\2.5"); | |
651 | |
652 DicomWebJsonVisitor visitor; | |
653 dicom.Apply(visitor); | |
654 | |
655 { | |
656 const Json::Value& tag = visitor.GetResult() ["00200037"]; | |
657 const Json::Value& value = tag["Value"]; | |
658 | |
659 ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); | |
660 ASSERT_EQ(2u, tag.getMemberNames().size()); | |
661 ASSERT_EQ(4u, value.size()); | |
662 ASSERT_EQ(Json::realValue, value[0].type()); | |
663 ASSERT_EQ(Json::nullValue, value[1].type()); | |
664 ASSERT_EQ(Json::nullValue, value[2].type()); | |
665 ASSERT_EQ(Json::realValue, value[3].type()); | |
666 ASSERT_FLOAT_EQ(1.5f, value[0].asFloat()); | |
667 ASSERT_FLOAT_EQ(2.5f, value[3].asFloat()); | |
668 } | |
669 | |
670 std::string xml; | |
671 visitor.FormatXml(xml); | |
672 | |
673 { | |
674 DicomMap m; | |
675 m.FromDicomWeb(visitor.GetResult()); | |
676 ASSERT_EQ(1u, m.GetSize()); | |
677 | |
678 std::string s; | |
679 ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false)); | |
680 | |
681 std::vector<std::string> v; | |
682 Toolbox::TokenizeString(v, s, '\\'); | |
683 ASSERT_FLOAT_EQ(1.5f, boost::lexical_cast<float>(v[0])); | |
684 ASSERT_TRUE(v[1].empty()); | |
685 ASSERT_TRUE(v[2].empty()); | |
686 ASSERT_FLOAT_EQ(2.5f, boost::lexical_cast<float>(v[3])); | |
687 } | |
688 } | |
689 | |
690 | |
691 static void SetTagKey(ParsedDicomFile& dicom, | |
692 const DicomTag& tag, | |
693 const DicomTag& value) | |
694 { | |
695 // This function emulates a call to function | |
696 // "dicom.GetDcmtkObject().getDataset()->putAndInsertTagKey(tag, | |
697 // value)" that was not available in DCMTK 3.6.0 | |
698 | |
699 std::unique_ptr<DcmAttributeTag> element(new DcmAttributeTag(ToDcmtkBridge::Convert(tag))); | |
700 | |
701 DcmTagKey v = ToDcmtkBridge::Convert(value); | |
702 if (!element->putTagVal(v).good()) | |
703 { | |
704 throw OrthancException(ErrorCode_InternalError); | |
705 } | |
706 | |
707 dicom.GetDcmtkObject().getDataset()->insert(element.release()); | |
708 } | |
709 | |
710 | |
711 TEST(DicomWebJson, ValueRepresentation) | |
712 { | |
713 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html | |
714 | |
715 ParsedDicomFile dicom(false); | |
716 dicom.ReplacePlainString(DicomTag(0x0040, 0x0241), "AE"); | |
717 dicom.ReplacePlainString(DicomTag(0x0010, 0x1010), "AS"); | |
718 SetTagKey(dicom, DicomTag(0x0020, 0x9165), DicomTag(0x0010, 0x0020)); | |
719 dicom.ReplacePlainString(DicomTag(0x0008, 0x0052), "CS"); | |
720 dicom.ReplacePlainString(DicomTag(0x0008, 0x0012), "DA"); | |
721 dicom.ReplacePlainString(DicomTag(0x0010, 0x1020), "42"); // DS | |
722 dicom.ReplacePlainString(DicomTag(0x0008, 0x002a), "DT"); | |
723 dicom.ReplacePlainString(DicomTag(0x0010, 0x9431), "43"); // FL | |
724 dicom.ReplacePlainString(DicomTag(0x0008, 0x1163), "44"); // FD | |
725 dicom.ReplacePlainString(DicomTag(0x0008, 0x1160), "45"); // IS | |
726 dicom.ReplacePlainString(DicomTag(0x0008, 0x0070), "LO"); | |
727 dicom.ReplacePlainString(DicomTag(0x0010, 0x4000), "LT"); | |
728 dicom.ReplacePlainString(DicomTag(0x0028, 0x2000), "OB"); | |
729 dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "3.14159"); // OD (other double) | |
730 dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "2.71828"); // OF (other float) | |
731 dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46"); // OL (other long) | |
732 ASSERT_THROW(dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "O"), OrthancException); | |
733 dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "OWOW"); | |
734 dicom.ReplacePlainString(DicomTag(0x0010, 0x0010), "PN"); | |
735 dicom.ReplacePlainString(DicomTag(0x0008, 0x0050), "SH"); | |
736 dicom.ReplacePlainString(DicomTag(0x0018, 0x6020), "-15"); // SL | |
737 dicom.ReplacePlainString(DicomTag(0x0018, 0x9219), "-16"); // SS | |
738 dicom.ReplacePlainString(DicomTag(0x0008, 0x0081), "ST"); | |
739 dicom.ReplacePlainString(DicomTag(0x0008, 0x0013), "TM"); | |
740 dicom.ReplacePlainString(DicomTag(0x0008, 0x0119), "UC"); | |
741 dicom.ReplacePlainString(DicomTag(0x0008, 0x0016), "UI"); | |
742 dicom.ReplacePlainString(DicomTag(0x0008, 0x1161), "128"); // UL | |
743 dicom.ReplacePlainString(DicomTag(0x4342, 0x1234), "UN"); // Inexistent tag | |
744 dicom.ReplacePlainString(DicomTag(0x0008, 0x0120), "UR"); | |
745 dicom.ReplacePlainString(DicomTag(0x0008, 0x0301), "17"); // US | |
746 dicom.ReplacePlainString(DicomTag(0x0040, 0x0031), "UT"); | |
747 | |
748 DicomWebJsonVisitor visitor; | |
749 dicom.Apply(visitor); | |
750 | |
751 std::string s; | |
752 | |
753 // The tag (0002,0002) is "Media Storage SOP Class UID" and is | |
754 // automatically copied by DCMTK from tag (0008,0016) | |
755 ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["vr"].asString()); | |
756 ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["Value"][0].asString()); | |
757 ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["vr"].asString()); | |
758 ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["Value"][0].asString()); | |
759 ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["vr"].asString()); | |
760 ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["Value"][0].asString()); | |
761 ASSERT_EQ("AT", visitor.GetResult() ["00209165"]["vr"].asString()); | |
762 ASSERT_EQ("00100020", visitor.GetResult() ["00209165"]["Value"][0].asString()); | |
763 ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["vr"].asString()); | |
764 ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["Value"][0].asString()); | |
765 ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["vr"].asString()); | |
766 ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["Value"][0].asString()); | |
767 ASSERT_EQ("DS", visitor.GetResult() ["00101020"]["vr"].asString()); | |
768 ASSERT_FLOAT_EQ(42.0f, visitor.GetResult() ["00101020"]["Value"][0].asFloat()); | |
769 ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["vr"].asString()); | |
770 ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["Value"][0].asString()); | |
771 ASSERT_EQ("FL", visitor.GetResult() ["00109431"]["vr"].asString()); | |
772 ASSERT_FLOAT_EQ(43.0f, visitor.GetResult() ["00109431"]["Value"][0].asFloat()); | |
773 ASSERT_EQ("FD", visitor.GetResult() ["00081163"]["vr"].asString()); | |
774 ASSERT_FLOAT_EQ(44.0f, visitor.GetResult() ["00081163"]["Value"][0].asFloat()); | |
775 ASSERT_EQ("IS", visitor.GetResult() ["00081160"]["vr"].asString()); | |
776 ASSERT_FLOAT_EQ(45.0f, visitor.GetResult() ["00081160"]["Value"][0].asFloat()); | |
777 ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["vr"].asString()); | |
778 ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["Value"][0].asString()); | |
779 ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["vr"].asString()); | |
780 ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["Value"][0].asString()); | |
781 | |
782 ASSERT_EQ("OB", visitor.GetResult() ["00282000"]["vr"].asString()); | |
783 Toolbox::DecodeBase64(s, visitor.GetResult() ["00282000"]["InlineBinary"].asString()); | |
784 ASSERT_EQ("OB", s); | |
785 | |
786 #if DCMTK_VERSION_NUMBER >= 361 | |
787 ASSERT_EQ("OD", visitor.GetResult() ["7FE00009"]["vr"].asString()); | |
788 ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(visitor.GetResult() ["7FE00009"]["Value"][0].asString())); | |
789 #else | |
790 ASSERT_EQ("UN", visitor.GetResult() ["7FE00009"]["vr"].asString()); | |
791 Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString()); | |
792 ASSERT_EQ(8u, s.size()); // Because of padding | |
793 ASSERT_EQ(0, s[7]); | |
794 ASSERT_EQ("3.14159", s.substr(0, 7)); | |
795 #endif | |
796 | |
797 ASSERT_EQ("OF", visitor.GetResult() ["00640009"]["vr"].asString()); | |
798 ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(visitor.GetResult() ["00640009"]["Value"][0].asString())); | |
799 | |
800 #if DCMTK_VERSION_NUMBER < 361 | |
801 ASSERT_EQ("UN", visitor.GetResult() ["00660040"]["vr"].asString()); | |
802 Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString()); | |
803 ASSERT_EQ("46", s); | |
804 #elif DCMTK_VERSION_NUMBER == 361 | |
805 ASSERT_EQ("UL", visitor.GetResult() ["00660040"]["vr"].asString()); | |
806 ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); | |
807 #else | |
808 ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString()); | |
809 ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); | |
810 #endif | |
811 | |
812 ASSERT_EQ("OW", visitor.GetResult() ["00281201"]["vr"].asString()); | |
813 Toolbox::DecodeBase64(s, visitor.GetResult() ["00281201"]["InlineBinary"].asString()); | |
814 ASSERT_EQ("OWOW", s); | |
815 | |
816 ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["vr"].asString()); | |
817 ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["Value"][0]["Alphabetic"].asString()); | |
818 | |
819 ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["vr"].asString()); | |
820 ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["Value"][0].asString()); | |
821 | |
822 ASSERT_EQ("SL", visitor.GetResult() ["00186020"]["vr"].asString()); | |
823 ASSERT_EQ(-15, visitor.GetResult() ["00186020"]["Value"][0].asInt()); | |
824 | |
825 ASSERT_EQ("SS", visitor.GetResult() ["00189219"]["vr"].asString()); | |
826 ASSERT_EQ(-16, visitor.GetResult() ["00189219"]["Value"][0].asInt()); | |
827 | |
828 ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["vr"].asString()); | |
829 ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["Value"][0].asString()); | |
830 | |
831 ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["vr"].asString()); | |
832 ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["Value"][0].asString()); | |
833 | |
834 #if DCMTK_VERSION_NUMBER >= 361 | |
835 ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["vr"].asString()); | |
836 ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["Value"][0].asString()); | |
837 #else | |
838 ASSERT_EQ("UN", visitor.GetResult() ["00080119"]["vr"].asString()); | |
839 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080119"]["InlineBinary"].asString()); | |
840 ASSERT_EQ("UC", s); | |
841 #endif | |
842 | |
843 ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["vr"].asString()); | |
844 ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["Value"][0].asString()); | |
845 | |
846 ASSERT_EQ("UL", visitor.GetResult() ["00081161"]["vr"].asString()); | |
847 ASSERT_EQ(128u, visitor.GetResult() ["00081161"]["Value"][0].asUInt()); | |
848 | |
849 ASSERT_EQ("UN", visitor.GetResult() ["43421234"]["vr"].asString()); | |
850 Toolbox::DecodeBase64(s, visitor.GetResult() ["43421234"]["InlineBinary"].asString()); | |
851 ASSERT_EQ("UN", s); | |
852 | |
853 #if DCMTK_VERSION_NUMBER >= 361 | |
854 ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["vr"].asString()); | |
855 ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["Value"][0].asString()); | |
856 #else | |
857 ASSERT_EQ("UN", visitor.GetResult() ["00080120"]["vr"].asString()); | |
858 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080120"]["InlineBinary"].asString()); | |
859 ASSERT_EQ("UR", s); | |
860 #endif | |
861 | |
862 #if DCMTK_VERSION_NUMBER >= 361 | |
863 ASSERT_EQ("US", visitor.GetResult() ["00080301"]["vr"].asString()); | |
864 ASSERT_EQ(17u, visitor.GetResult() ["00080301"]["Value"][0].asUInt()); | |
865 #else | |
866 ASSERT_EQ("UN", visitor.GetResult() ["00080301"]["vr"].asString()); | |
867 Toolbox::DecodeBase64(s, visitor.GetResult() ["00080301"]["InlineBinary"].asString()); | |
868 ASSERT_EQ("17", s); | |
869 #endif | |
870 | |
871 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["vr"].asString()); | |
872 ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString()); | |
873 | |
874 std::string xml; | |
875 visitor.FormatXml(xml); | |
876 | |
877 { | |
878 DicomMap m; | |
879 m.FromDicomWeb(visitor.GetResult()); | |
880 ASSERT_EQ(31u, m.GetSize()); | |
881 | |
882 std::string s; | |
883 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0002, 0x0002), false)); ASSERT_EQ("UI", s); | |
884 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0241), false)); ASSERT_EQ("AE", s); | |
885 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1010), false)); ASSERT_EQ("AS", s); | |
886 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0020, 0x9165), false)); ASSERT_EQ("00100020", s); | |
887 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0052), false)); ASSERT_EQ("CS", s); | |
888 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0012), false)); ASSERT_EQ("DA", s); | |
889 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1020), false)); ASSERT_EQ("42", s); | |
890 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x002a), false)); ASSERT_EQ("DT", s); | |
891 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x9431), false)); ASSERT_EQ("43", s); | |
892 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1163), false)); ASSERT_EQ("44", s); | |
893 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1160), false)); ASSERT_EQ("45", s); | |
894 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false)); ASSERT_EQ("LO", s); | |
895 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false)); ASSERT_EQ("LT", s); | |
896 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true)); ASSERT_EQ("OB", s); | |
897 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true)); | |
898 | |
899 #if DCMTK_VERSION_NUMBER >= 361 | |
900 ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(s)); | |
901 #else | |
902 ASSERT_EQ(8u, s.size()); // Because of padding | |
903 ASSERT_EQ(0, s[7]); | |
904 ASSERT_EQ("3.14159", s.substr(0, 7)); | |
905 #endif | |
906 | |
907 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true)); | |
908 ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(s)); | |
909 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true)); ASSERT_EQ("OWOW", s); | |
910 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false)); ASSERT_EQ("PN", s); | |
911 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false)); ASSERT_EQ("SH", s); | |
912 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x6020), false)); ASSERT_EQ("-15", s); | |
913 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false)); ASSERT_EQ("-16", s); | |
914 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false)); ASSERT_EQ("ST", s); | |
915 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false)); ASSERT_EQ("TM", s); | |
916 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false)); ASSERT_EQ("UI", s); | |
917 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false)); ASSERT_EQ("128", s); | |
918 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true)); ASSERT_EQ("UN", s); | |
919 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false)); ASSERT_EQ("UT", s); | |
920 | |
921 #if DCMTK_VERSION_NUMBER >= 361 | |
922 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false)); ASSERT_EQ("46", s); | |
923 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false)); ASSERT_EQ("UC", s); | |
924 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false)); ASSERT_EQ("UR", s); | |
925 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false)); ASSERT_EQ("17", s); | |
926 #else | |
927 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true)); ASSERT_EQ("46", s); // OL | |
928 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), true)); ASSERT_EQ("UC", s); | |
929 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), true)); ASSERT_EQ("UR", s); | |
930 ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), true)); ASSERT_EQ("17", s); // US (but tag unknown to DCMTK 3.6.0) | |
931 #endif | |
932 | |
933 } | |
934 } | |
935 | |
936 | |
937 TEST(DicomWebJson, Sequence) | |
938 { | |
939 ParsedDicomFile dicom(false); | |
940 | |
941 { | |
942 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence)); | |
943 | |
944 for (unsigned int i = 0; i < 3; i++) | |
945 { | |
946 std::unique_ptr<DcmItem> item(new DcmItem); | |
947 std::string s = "item" + boost::lexical_cast<std::string>(i); | |
948 item->putAndInsertString(DCM_ReferencedSOPInstanceUID, s.c_str(), OFFalse); | |
949 ASSERT_TRUE(sequence->insert(item.release(), false, false).good()); | |
950 } | |
951 | |
952 ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->insert(sequence.release(), false, false).good()); | |
953 } | |
954 | |
955 DicomWebJsonVisitor visitor; | |
956 dicom.Apply(visitor); | |
957 | |
958 ASSERT_EQ("SQ", visitor.GetResult() ["00081115"]["vr"].asString()); | |
959 ASSERT_EQ(3u, visitor.GetResult() ["00081115"]["Value"].size()); | |
960 | |
961 std::set<std::string> items; | |
962 | |
963 for (Json::Value::ArrayIndex i = 0; i < 3; i++) | |
964 { | |
965 ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i].size()); | |
966 ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"].size()); | |
967 ASSERT_EQ("UI", visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["vr"].asString()); | |
968 items.insert(visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"][0].asString()); | |
969 } | |
970 | |
971 ASSERT_EQ(3u, items.size()); | |
972 ASSERT_TRUE(items.find("item0") != items.end()); | |
973 ASSERT_TRUE(items.find("item1") != items.end()); | |
974 ASSERT_TRUE(items.find("item2") != items.end()); | |
975 | |
976 std::string xml; | |
977 visitor.FormatXml(xml); | |
978 | |
979 { | |
980 DicomMap m; | |
981 m.FromDicomWeb(visitor.GetResult()); | |
982 ASSERT_EQ(0u, m.GetSize()); // Sequences are not handled by DicomMap | |
983 } | |
984 } | |
985 | |
986 | |
987 TEST(DicomWebJson, PixelSpacing) | |
988 { | |
989 // Test related to locales: Make sure that decimal separator is | |
990 // correctly handled (dot "." vs comma ",") | |
991 ParsedDicomFile source(false); | |
992 source.ReplacePlainString(DICOM_TAG_PIXEL_SPACING, "1.5\\1.3"); | |
993 | |
994 DicomWebJsonVisitor visitor; | |
995 source.Apply(visitor); | |
996 | |
997 DicomMap target; | |
998 target.FromDicomWeb(visitor.GetResult()); | |
999 | |
1000 ASSERT_EQ("DS", visitor.GetResult() ["00280030"]["vr"].asString()); | |
1001 ASSERT_FLOAT_EQ(1.5f, visitor.GetResult() ["00280030"]["Value"][0].asFloat()); | |
1002 ASSERT_FLOAT_EQ(1.3f, visitor.GetResult() ["00280030"]["Value"][1].asFloat()); | |
1003 | |
1004 std::string s; | |
1005 ASSERT_TRUE(target.LookupStringValue(s, DICOM_TAG_PIXEL_SPACING, false)); | |
1006 ASSERT_EQ(s, "1.5\\1.3"); | |
1007 } | |
1008 | |
1009 | |
1010 TEST(DicomMap, MainTagNames) | |
1011 { | |
1012 ASSERT_EQ(3, ResourceType_Instance - ResourceType_Patient); | |
1013 | |
1014 for (int i = ResourceType_Patient; i <= ResourceType_Instance; i++) | |
1015 { | |
1016 ResourceType level = static_cast<ResourceType>(i); | |
1017 | |
1018 std::set<DicomTag> tags; | |
1019 DicomMap::GetMainDicomTags(tags, level); | |
1020 | |
1021 for (std::set<DicomTag>::const_iterator it = tags.begin(); it != tags.end(); ++it) | |
1022 { | |
1023 DicomMap a; | |
1024 a.SetValue(*it, "TEST", false); | |
1025 | |
1026 Json::Value json; | |
1027 a.DumpMainDicomTags(json, level); | |
1028 | |
1029 ASSERT_EQ(Json::objectValue, json.type()); | |
1030 ASSERT_EQ(1u, json.getMemberNames().size()); | |
1031 | |
1032 std::string name = json.getMemberNames() [0]; | |
1033 EXPECT_EQ(name, FromDcmtkBridge::GetTagName(*it, "")); | |
1034 | |
1035 DicomMap b; | |
1036 b.ParseMainDicomTags(json, level); | |
1037 | |
1038 ASSERT_EQ(1u, b.GetSize()); | |
1039 ASSERT_EQ("TEST", b.GetStringValue(*it, "", false)); | |
1040 | |
1041 std::string main = it->GetMainTagsName(); | |
1042 if (!main.empty()) | |
1043 { | |
1044 ASSERT_EQ(main, name); | |
1045 } | |
1046 } | |
1047 } | |
1048 } |