comparison Framework/Deprecated/Toolbox/MessagingToolbox.cpp @ 792:4fe4b221a31f

deprecating MessagingToolbox
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 May 2019 08:49:49 +0200
parents Framework/Toolbox/MessagingToolbox.cpp@b70e9be013e4
children 2d8ab34c8c91
comparison
equal deleted inserted replaced
791:907189734acd 792:4fe4b221a31f
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-2019 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 "MessagingToolbox.h"
23
24 #include <Core/Images/Image.h>
25 #include <Core/Images/ImageProcessing.h>
26 #include <Core/Images/JpegReader.h>
27 #include <Core/Images/PngReader.h>
28 #include <Core/OrthancException.h>
29 #include <Core/Toolbox.h>
30 #include <Core/Logging.h>
31
32 #include <boost/lexical_cast.hpp>
33 #include <json/reader.h>
34 #include <json/writer.h>
35
36 namespace Deprecated
37 {
38 namespace MessagingToolbox
39 {
40 static bool ParseVersion(std::string& version,
41 unsigned int& major,
42 unsigned int& minor,
43 unsigned int& patch,
44 const Json::Value& info)
45 {
46 if (info.type() != Json::objectValue ||
47 !info.isMember("Version") ||
48 info["Version"].type() != Json::stringValue)
49 {
50 return false;
51 }
52
53 version = info["Version"].asString();
54 if (version == "mainline")
55 {
56 // Some arbitrary high values Orthanc versions will never reach ;)
57 major = 999;
58 minor = 999;
59 patch = 999;
60 return true;
61 }
62
63 std::vector<std::string> tokens;
64 Orthanc::Toolbox::TokenizeString(tokens, version, '.');
65
66 if (tokens.size() != 2 &&
67 tokens.size() != 3)
68 {
69 return false;
70 }
71
72 int a, b, c;
73 try
74 {
75 a = boost::lexical_cast<int>(tokens[0]);
76 b = boost::lexical_cast<int>(tokens[1]);
77
78 if (tokens.size() == 3)
79 {
80 c = boost::lexical_cast<int>(tokens[2]);
81 }
82 else
83 {
84 c = 0;
85 }
86 }
87 catch (boost::bad_lexical_cast&)
88 {
89 return false;
90 }
91
92 if (a < 0 ||
93 b < 0 ||
94 c < 0)
95 {
96 return false;
97 }
98 else
99 {
100 major = static_cast<unsigned int>(a);
101 minor = static_cast<unsigned int>(b);
102 patch = static_cast<unsigned int>(c);
103 return true;
104 }
105 }
106
107
108 bool ParseJson(Json::Value& target,
109 const void* content,
110 size_t size)
111 {
112 Json::Reader reader;
113 return reader.parse(reinterpret_cast<const char*>(content),
114 reinterpret_cast<const char*>(content) + size,
115 target);
116 }
117
118 void JsonToString(std::string& target,
119 const Json::Value& source)
120 {
121 Json::FastWriter writer;
122 target = writer.write(source);
123 }
124
125 static void ParseJsonException(Json::Value& target,
126 const std::string& source)
127 {
128 Json::Reader reader;
129 if (!reader.parse(source, target))
130 {
131 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
132 }
133 }
134
135
136 void RestApiGet(Json::Value& target,
137 OrthancPlugins::IOrthancConnection& orthanc,
138 const std::string& uri)
139 {
140 std::string tmp;
141 orthanc.RestApiGet(tmp, uri);
142 ParseJsonException(target, tmp);
143 }
144
145
146 void RestApiPost(Json::Value& target,
147 OrthancPlugins::IOrthancConnection& orthanc,
148 const std::string& uri,
149 const std::string& body)
150 {
151 std::string tmp;
152 orthanc.RestApiPost(tmp, uri, body);
153 ParseJsonException(target, tmp);
154 }
155
156
157 bool HasWebViewerInstalled(OrthancPlugins::IOrthancConnection& orthanc)
158 {
159 try
160 {
161 Json::Value json;
162 RestApiGet(json, orthanc, "/plugins/web-viewer");
163 return json.type() == Json::objectValue;
164 }
165 catch (Orthanc::OrthancException&)
166 {
167 return false;
168 }
169 }
170
171
172 bool CheckOrthancVersion(OrthancPlugins::IOrthancConnection& orthanc)
173 {
174 Json::Value json;
175 std::string version;
176 unsigned int major, minor, patch;
177
178 try
179 {
180 RestApiGet(json, orthanc, "/system");
181 }
182 catch (Orthanc::OrthancException&)
183 {
184 LOG(ERROR) << "Cannot connect to your Orthanc server";
185 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
186 }
187
188 if (!ParseVersion(version, major, minor, patch, json))
189 {
190 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
191 }
192
193 LOG(WARNING) << "Version of the Orthanc core (must be above 1.3.1): " << version;
194
195 // Stone is only compatible with Orthanc >= 1.3.1
196 if (major < 1 ||
197 (major == 1 && minor < 3) ||
198 (major == 1 && minor == 3 && patch < 1))
199 {
200 return false;
201 }
202
203 try
204 {
205 RestApiGet(json, orthanc, "/plugins/web-viewer");
206 }
207 catch (Orthanc::OrthancException&)
208 {
209 // The Web viewer is not installed, this is OK
210 LOG(WARNING) << "The Web viewer plugin is not installed, progressive download is disabled";
211 return true;
212 }
213
214 if (!ParseVersion(version, major, minor, patch, json))
215 {
216 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
217 }
218
219 LOG(WARNING) << "Version of the Web viewer plugin (must be above 2.2): " << version;
220
221 return (major >= 3 ||
222 (major == 2 && minor >= 2));
223 }
224
225
226 Orthanc::ImageAccessor* DecodeFrame(OrthancPlugins::IOrthancConnection& orthanc,
227 const std::string& instance,
228 unsigned int frame,
229 Orthanc::PixelFormat targetFormat)
230 {
231 std::string uri = ("instances/" + instance + "/frames/" +
232 boost::lexical_cast<std::string>(frame));
233
234 std::string compressed;
235
236 switch (targetFormat)
237 {
238 case Orthanc::PixelFormat_RGB24:
239 orthanc.RestApiGet(compressed, uri + "/preview");
240 break;
241
242 case Orthanc::PixelFormat_Grayscale16:
243 orthanc.RestApiGet(compressed, uri + "/image-uint16");
244 break;
245
246 case Orthanc::PixelFormat_SignedGrayscale16:
247 orthanc.RestApiGet(compressed, uri + "/image-int16");
248 break;
249
250 default:
251 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
252 }
253
254 std::auto_ptr<Orthanc::PngReader> result(new Orthanc::PngReader);
255 result->ReadFromMemory(compressed);
256
257 if (targetFormat == Orthanc::PixelFormat_SignedGrayscale16)
258 {
259 if (result->GetFormat() == Orthanc::PixelFormat_Grayscale16)
260 {
261 result->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
262 }
263 else
264 {
265 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
266 }
267 }
268
269 return result.release();
270 }
271
272
273 Orthanc::ImageAccessor* DecodeJpegFrame(OrthancPlugins::IOrthancConnection& orthanc,
274 const std::string& instance,
275 unsigned int frame,
276 unsigned int quality,
277 Orthanc::PixelFormat targetFormat)
278 {
279 if (quality <= 0 ||
280 quality > 100)
281 {
282 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
283 }
284
285 // This requires the official Web viewer plugin to be installed!
286 std::string uri = ("web-viewer/instances/jpeg" +
287 boost::lexical_cast<std::string>(quality) +
288 "-" + instance + "_" +
289 boost::lexical_cast<std::string>(frame));
290
291 Json::Value encoded;
292 RestApiGet(encoded, orthanc, uri);
293
294 if (encoded.type() != Json::objectValue ||
295 !encoded.isMember("Orthanc") ||
296 encoded["Orthanc"].type() != Json::objectValue)
297 {
298 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
299 }
300
301 Json::Value& info = encoded["Orthanc"];
302 if (!info.isMember("PixelData") ||
303 !info.isMember("Stretched") ||
304 !info.isMember("Compression") ||
305 info["Compression"].type() != Json::stringValue ||
306 info["PixelData"].type() != Json::stringValue ||
307 info["Stretched"].type() != Json::booleanValue ||
308 info["Compression"].asString() != "Jpeg")
309 {
310 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
311 }
312
313 bool isSigned = false;
314 bool isStretched = info["Stretched"].asBool();
315
316 if (info.isMember("IsSigned"))
317 {
318 if (info["IsSigned"].type() != Json::booleanValue)
319 {
320 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
321 }
322 else
323 {
324 isSigned = info["IsSigned"].asBool();
325 }
326 }
327
328 std::string jpeg;
329 Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
330
331 std::auto_ptr<Orthanc::JpegReader> reader(new Orthanc::JpegReader);
332 reader->ReadFromMemory(jpeg);
333
334 if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image
335 {
336 if (targetFormat != Orthanc::PixelFormat_RGB24)
337 {
338 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
339 }
340
341 if (isSigned || isStretched)
342 {
343 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
344 }
345 else
346 {
347 return reader.release();
348 }
349 }
350
351 if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8)
352 {
353 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
354 }
355
356 if (!isStretched)
357 {
358 if (targetFormat != reader->GetFormat())
359 {
360 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
361 }
362
363 return reader.release();
364 }
365
366 int32_t stretchLow = 0;
367 int32_t stretchHigh = 0;
368
369 if (!info.isMember("StretchLow") ||
370 !info.isMember("StretchHigh") ||
371 info["StretchLow"].type() != Json::intValue ||
372 info["StretchHigh"].type() != Json::intValue)
373 {
374 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
375 }
376
377 stretchLow = info["StretchLow"].asInt();
378 stretchHigh = info["StretchHigh"].asInt();
379
380 if (stretchLow < -32768 ||
381 stretchHigh > 65535 ||
382 (stretchLow < 0 && stretchHigh > 32767))
383 {
384 // This range cannot be represented with a uint16_t or an int16_t
385 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
386 }
387
388 // Decode a grayscale JPEG 8bpp image coming from the Web viewer
389 std::auto_ptr<Orthanc::ImageAccessor> image
390 (new Orthanc::Image(targetFormat, reader->GetWidth(), reader->GetHeight(), false));
391
392 float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
393 float offset = static_cast<float>(stretchLow) / scaling;
394
395 Orthanc::ImageProcessing::Convert(*image, *reader);
396 Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
397
398 #if 0
399 /*info.removeMember("PixelData");
400 std::cout << info.toStyledString();*/
401
402 int64_t a, b;
403 Orthanc::ImageProcessing::GetMinMaxValue(a, b, *image);
404 std::cout << stretchLow << "->" << stretchHigh << " = " << a << "->" << b << std::endl;
405 #endif
406
407 return image.release();
408 }
409
410
411 static void AddTag(Orthanc::DicomMap& target,
412 const OrthancPlugins::IDicomDataset& source,
413 const Orthanc::DicomTag& tag)
414 {
415 OrthancPlugins::DicomTag key(tag.GetGroup(), tag.GetElement());
416
417 std::string value;
418 if (source.GetStringValue(value, key))
419 {
420 target.SetValue(tag, value, false);
421 }
422 }
423
424
425 void ConvertDataset(Orthanc::DicomMap& target,
426 const OrthancPlugins::IDicomDataset& source)
427 {
428 target.Clear();
429
430 AddTag(target, source, Orthanc::DICOM_TAG_BITS_ALLOCATED);
431 AddTag(target, source, Orthanc::DICOM_TAG_BITS_STORED);
432 AddTag(target, source, Orthanc::DICOM_TAG_COLUMNS);
433 AddTag(target, source, Orthanc::DICOM_TAG_DOSE_GRID_SCALING);
434 AddTag(target, source, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER);
435 AddTag(target, source, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR);
436 AddTag(target, source, Orthanc::DICOM_TAG_HIGH_BIT);
437 AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT);
438 AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT);
439 AddTag(target, source, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES);
440 AddTag(target, source, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION);
441 AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION);
442 AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_SPACING);
443 AddTag(target, source, Orthanc::DICOM_TAG_PLANAR_CONFIGURATION);
444 AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_INTERCEPT);
445 AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_SLOPE);
446 AddTag(target, source, Orthanc::DICOM_TAG_ROWS);
447 AddTag(target, source, Orthanc::DICOM_TAG_SAMPLES_PER_PIXEL);
448 AddTag(target, source, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID);
449 AddTag(target, source, Orthanc::DICOM_TAG_SLICE_THICKNESS);
450 AddTag(target, source, Orthanc::DICOM_TAG_SOP_CLASS_UID);
451 AddTag(target, source, Orthanc::DICOM_TAG_SOP_INSTANCE_UID);
452 AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_CENTER);
453 AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_WIDTH);
454 }
455 }
456 }