comparison Applications/Resources/Graveyard/Toolbox/DicomDataset.cpp @ 1586:b5417e377636

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 22 Oct 2020 16:17:10 +0200
parents OrthancStone/Resources/Graveyard/Toolbox/DicomDataset.cpp@244ad1e4e76a
children 4fb8fdf03314
comparison
equal deleted inserted replaced
1585:94edbfa64c97 1586:b5417e377636
1 /**
2 * Stone of Orthanc
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 Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "DicomDataset.h"
23
24 #include "../../Resources/Orthanc/Core/OrthancException.h"
25 #include "../../Resources/Orthanc/Core/Logging.h"
26 #include "../../Resources/Orthanc/Core/Toolbox.h"
27
28 #include <boost/lexical_cast.hpp>
29 #include <json/value.h>
30 #include <json/reader.h>
31
32 namespace OrthancStone
33 {
34 static uint16_t GetCharValue(char c)
35 {
36 if (c >= '0' && c <= '9')
37 return c - '0';
38 else if (c >= 'a' && c <= 'f')
39 return c - 'a' + 10;
40 else if (c >= 'A' && c <= 'F')
41 return c - 'A' + 10;
42 else
43 return 0;
44 }
45
46
47 static uint16_t GetHexadecimalValue(const char* c)
48 {
49 return ((GetCharValue(c[0]) << 12) +
50 (GetCharValue(c[1]) << 8) +
51 (GetCharValue(c[2]) << 4) +
52 GetCharValue(c[3]));
53 }
54
55
56 static DicomDataset::Tag ParseTag(const std::string& tag)
57 {
58 if (tag.size() == 9 &&
59 isxdigit(tag[0]) &&
60 isxdigit(tag[1]) &&
61 isxdigit(tag[2]) &&
62 isxdigit(tag[3]) &&
63 (tag[4] == '-' || tag[4] == ',') &&
64 isxdigit(tag[5]) &&
65 isxdigit(tag[6]) &&
66 isxdigit(tag[7]) &&
67 isxdigit(tag[8]))
68 {
69 uint16_t group = GetHexadecimalValue(tag.c_str());
70 uint16_t element = GetHexadecimalValue(tag.c_str() + 5);
71 return std::make_pair(group, element);
72 }
73 else if (tag.size() == 8 &&
74 isxdigit(tag[0]) &&
75 isxdigit(tag[1]) &&
76 isxdigit(tag[2]) &&
77 isxdigit(tag[3]) &&
78 isxdigit(tag[4]) &&
79 isxdigit(tag[5]) &&
80 isxdigit(tag[6]) &&
81 isxdigit(tag[7]))
82 {
83 uint16_t group = GetHexadecimalValue(tag.c_str());
84 uint16_t element = GetHexadecimalValue(tag.c_str() + 4);
85 return std::make_pair(group, element);
86 }
87 else
88 {
89 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
90 }
91 }
92
93 void DicomDataset::Parse(const std::string& content)
94 {
95 Json::Value json;
96 Json::Reader reader;
97 if (!reader.parse(content, json))
98 {
99 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
100 }
101
102 Parse(json);
103 }
104
105
106 void DicomDataset::Parse(const Json::Value& content)
107 {
108 if (content.type() != Json::objectValue)
109 {
110 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
111 }
112
113 Json::Value::Members members = content.getMemberNames();
114 for (size_t i = 0; i < members.size(); i++)
115 {
116 Tag tag = ParseTag(members[i]);
117
118 const Json::Value& item = content[members[i]];
119
120 if (item.type() != Json::objectValue ||
121 !item.isMember("Type") ||
122 !item.isMember("Value") ||
123 !item.isMember("Name") ||
124 item["Type"].type() != Json::stringValue ||
125 item["Name"].type() != Json::stringValue)
126 {
127 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
128 }
129
130 if (item["Type"].asString() == "String")
131 {
132 if (item["Value"].type() == Json::stringValue)
133 {
134 values_[tag] = item["Value"].asString();
135 }
136 else
137 {
138 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
139 }
140 }
141 }
142 }
143
144
145 DicomDataset::DicomDataset(OrthancPlugins::IOrthancConnection& orthanc,
146 const std::string& instanceId)
147 {
148 std::string content;
149 orthanc.RestApiGet(content, "/instances/" + instanceId + "/tags");
150
151 Parse(content);
152 }
153
154
155 std::string DicomDataset::GetStringValue(const Tag& tag) const
156 {
157 Values::const_iterator it = values_.find(tag);
158
159 if (it == values_.end())
160 {
161 LOG(ERROR) << "Trying to access a DICOM tag that is not set in a DICOM dataset";
162 throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
163 }
164 else
165 {
166 return it->second;
167 }
168 }
169
170
171 std::string DicomDataset::GetStringValue(const Tag& tag,
172 const std::string& defaultValue) const
173 {
174 Values::const_iterator it = values_.find(tag);
175
176 if (it == values_.end())
177 {
178 return defaultValue;
179 }
180 else
181 {
182 return it->second;
183 }
184 }
185
186
187 float DicomDataset::GetFloatValue(const Tag& tag) const
188 {
189 try
190 {
191 return boost::lexical_cast<float>(Orthanc::Toolbox::StripSpaces(GetStringValue(tag)));
192 }
193 catch (boost::bad_lexical_cast&)
194 {
195 LOG(ERROR) << "Trying to access a DICOM tag that is not a float";
196 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
197 }
198 }
199
200
201 double DicomDataset::GetDoubleValue(const Tag& tag) const
202 {
203 try
204 {
205 return boost::lexical_cast<double>(Orthanc::Toolbox::StripSpaces(GetStringValue(tag)));
206 }
207 catch (boost::bad_lexical_cast&)
208 {
209 LOG(ERROR) << "Trying to access a DICOM tag that is not a float";
210 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
211 }
212 }
213
214
215 int DicomDataset::GetIntegerValue(const Tag& tag) const
216 {
217 try
218 {
219 return boost::lexical_cast<int>(Orthanc::Toolbox::StripSpaces(GetStringValue(tag)));
220 }
221 catch (boost::bad_lexical_cast&)
222 {
223 LOG(ERROR) << "Trying to access a DICOM tag that is not an integer";
224 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
225 }
226 }
227
228
229 unsigned int DicomDataset::GetUnsignedIntegerValue(const Tag& tag) const
230 {
231 int v = GetIntegerValue(tag);
232
233 if (v < 0)
234 {
235 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
236 }
237 else
238 {
239 return static_cast<unsigned int>(v);
240 }
241 }
242
243
244 void DicomDataset::GetVectorValue(Vector& vector,
245 const Tag& tag) const
246 {
247 if (!GeometryToolbox::ParseVector(vector, Orthanc::Toolbox::StripSpaces(GetStringValue(tag))))
248 {
249 LOG(ERROR) << "Trying to access a DICOM tag that is not a vector";
250 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
251 }
252 }
253
254
255 void DicomDataset::GetVectorValue(Vector& vector,
256 const Tag& tag,
257 size_t expectedSize) const
258 {
259 GetVectorValue(vector, tag);
260
261 if (vector.size() != expectedSize)
262 {
263 LOG(ERROR) << "A vector in a DICOM tag has a bad size";
264 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
265 }
266 }
267
268
269 void DicomDataset::Print() const
270 {
271 for (Values::const_iterator it = values_.begin(); it != values_.end(); ++it)
272 {
273 printf("%04x,%04x = [%s]\n", it->first.first, it->first.second, it->second.c_str());
274 }
275 printf("\n");
276 }
277
278
279 bool DicomDataset::IsGrayscale() const
280 {
281 std::string photometric = Orthanc::Toolbox::StripSpaces(GetStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION));
282
283 return (photometric == "MONOCHROME1" ||
284 photometric == "MONOCHROME2");
285 }
286
287
288 void DicomDataset::GetPixelSpacing(double& spacingX,
289 double& spacingY) const
290 {
291 if (HasTag(DICOM_TAG_PIXEL_SPACING))
292 {
293 Vector spacing;
294 GetVectorValue(spacing, DICOM_TAG_PIXEL_SPACING, 2);
295 spacingX = spacing[0];
296 spacingY = spacing[1];
297 }
298 else
299 {
300 spacingX = 1.0;
301 spacingY = 1.0;
302 }
303 }
304 }