comparison Samples/Sdl/Loader.cpp @ 646:b4fe9642e83b

Merge from default
author Benjamin Golinvaux <bgo@osimis.io>
date Mon, 13 May 2019 15:22:08 +0200
parents 1e9ed656318e f0008c55e5f7
children 6af3099ed8da
comparison
equal deleted inserted replaced
645:1e9ed656318e 646:b4fe9642e83b
26 #include "../../Framework/StoneInitialization.h" 26 #include "../../Framework/StoneInitialization.h"
27 #include "../../Framework/Toolbox/GeometryToolbox.h" 27 #include "../../Framework/Toolbox/GeometryToolbox.h"
28 #include "../../Framework/Volumes/ImageBuffer3D.h" 28 #include "../../Framework/Volumes/ImageBuffer3D.h"
29 29
30 // From Orthanc framework 30 // From Orthanc framework
31 #include <Core/Compression/GzipCompressor.h>
32 #include <Core/Compression/ZlibCompressor.h>
31 #include <Core/DicomFormat/DicomArray.h> 33 #include <Core/DicomFormat/DicomArray.h>
32 #include <Core/DicomFormat/DicomImageInformation.h> 34 #include <Core/DicomFormat/DicomImageInformation.h>
33 #include <Core/HttpClient.h> 35 #include <Core/HttpClient.h>
34 #include <Core/IDynamicObject.h> 36 #include <Core/IDynamicObject.h>
35 #include <Core/Images/Image.h> 37 #include <Core/Images/Image.h>
36 #include <Core/Images/ImageProcessing.h> 38 #include <Core/Images/ImageProcessing.h>
39 #include <Core/Images/JpegReader.h>
40 #include <Core/Images/PamReader.h>
41 #include <Core/Images/PngReader.h>
37 #include <Core/Images/PngWriter.h> 42 #include <Core/Images/PngWriter.h>
38 #include <Core/Logging.h> 43 #include <Core/Logging.h>
39 #include <Core/MultiThreading/SharedMessageQueue.h> 44 #include <Core/MultiThreading/SharedMessageQueue.h>
40 #include <Core/OrthancException.h> 45 #include <Core/OrthancException.h>
41 #include <Core/Toolbox.h> 46 #include <Core/Toolbox.h>
47 #include <Core/SystemToolbox.h>
42 48
43 #include <json/reader.h> 49 #include <json/reader.h>
44 #include <json/value.h> 50 #include <json/value.h>
45 #include <json/writer.h> 51 #include <json/writer.h>
46 52
54 class IOracleCommand : public boost::noncopyable 60 class IOracleCommand : public boost::noncopyable
55 { 61 {
56 public: 62 public:
57 enum Type 63 enum Type
58 { 64 {
59 Type_OrthancApi 65 Type_OrthancRestApi,
66 Type_GetOrthancImage,
67 Type_GetOrthancWebViewerJpeg
60 }; 68 };
61 69
62 virtual ~IOracleCommand() 70 virtual ~IOracleCommand()
63 { 71 {
64 } 72 }
129 } 137 }
130 }; 138 };
131 139
132 140
133 141
142 class OracleCommandExceptionMessage : public OrthancStone::IMessage
143 {
144 ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
145
146 private:
147 const IOracleCommand& command_;
148 Orthanc::OrthancException exception_;
149
150 public:
151 OracleCommandExceptionMessage(const IOracleCommand& command,
152 const Orthanc::OrthancException& exception) :
153 command_(command),
154 exception_(exception)
155 {
156 }
157
158 OracleCommandExceptionMessage(const IOracleCommand& command,
159 const Orthanc::ErrorCode& error) :
160 command_(command),
161 exception_(error)
162 {
163 }
164
165 const IOracleCommand& GetCommand() const
166 {
167 return command_;
168 }
169
170 const Orthanc::OrthancException& GetException() const
171 {
172 return exception_;
173 }
174 };
175
176
134 typedef std::map<std::string, std::string> HttpHeaders; 177 typedef std::map<std::string, std::string> HttpHeaders;
135 178
136 class OrthancApiOracleCommand : public OracleCommandWithPayload 179 class OrthancRestApiCommand : public OracleCommandWithPayload
137 { 180 {
138 public: 181 public:
139 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_HttpRequestSuccess, // TODO 182 class SuccessMessage : public OrthancStone::OriginMessage<OrthancRestApiCommand>
140 OrthancApiOracleCommand> 183 {
141 { 184 ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
185
142 private: 186 private:
143 HttpHeaders headers_; 187 HttpHeaders headers_;
144 std::string answer_; 188 std::string answer_;
145 189
146 public: 190 public:
147 SuccessMessage(const OrthancApiOracleCommand& command, 191 SuccessMessage(const OrthancRestApiCommand& command,
148 const HttpHeaders& answerHeaders, 192 const HttpHeaders& answerHeaders,
149 std::string& answer /* will be swapped to avoid a memcpy() */) : 193 std::string& answer /* will be swapped to avoid a memcpy() */) :
150 OriginMessage(command), 194 OriginMessage(command),
151 headers_(answerHeaders), 195 headers_(answerHeaders),
152 answer_(answer) 196 answer_(answer)
168 } 212 }
169 213
170 const HttpHeaders& GetAnswerHeaders() const 214 const HttpHeaders& GetAnswerHeaders() const
171 { 215 {
172 return headers_; 216 return headers_;
173 }
174 };
175
176
177 class FailureMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_HttpRequestError, // TODO
178 OrthancApiOracleCommand>
179 {
180 private:
181 Orthanc::HttpStatus status_;
182
183 public:
184 FailureMessage(const OrthancApiOracleCommand& command,
185 Orthanc::HttpStatus status) :
186 OriginMessage(command),
187 status_(status)
188 {
189 }
190
191 Orthanc::HttpStatus GetHttpStatus() const
192 {
193 return status_;
194 } 217 }
195 }; 218 };
196 219
197 220
198 private: 221 private:
201 std::string body_; 224 std::string body_;
202 HttpHeaders headers_; 225 HttpHeaders headers_;
203 unsigned int timeout_; 226 unsigned int timeout_;
204 227
205 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_; 228 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_;
206 std::auto_ptr< OrthancStone::MessageHandler<FailureMessage> > failureCallback_; 229 std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> > failureCallback_;
207 230
208 public: 231 public:
209 OrthancApiOracleCommand() : 232 OrthancRestApiCommand() :
210 method_(Orthanc::HttpMethod_Get), 233 method_(Orthanc::HttpMethod_Get),
211 uri_("/"), 234 uri_("/"),
212 timeout_(10) 235 timeout_(10)
213 { 236 {
214 } 237 }
215 238
216 virtual Type GetType() const 239 virtual Type GetType() const
217 { 240 {
218 return Type_OrthancApi; 241 return Type_OrthancRestApi;
219 } 242 }
220 243
221 void SetMethod(Orthanc::HttpMethod method) 244 void SetMethod(Orthanc::HttpMethod method)
222 { 245 {
223 method_ = method; 246 method_ = method;
237 { 260 {
238 Json::FastWriter writer; 261 Json::FastWriter writer;
239 body_ = writer.write(json); 262 body_ = writer.write(json);
240 } 263 }
241 264
265 void SetHttpHeaders(const HttpHeaders& headers)
266 {
267 headers_ = headers;
268 }
269
242 void SetHttpHeader(const std::string& key, 270 void SetHttpHeader(const std::string& key,
243 const std::string& value) 271 const std::string& value)
244 { 272 {
245 headers_[key] = value; 273 headers_[key] = value;
246 } 274 }
281 unsigned int GetTimeout() const 309 unsigned int GetTimeout() const
282 { 310 {
283 return timeout_; 311 return timeout_;
284 } 312 }
285 }; 313 };
314
315
316
317
318 class GetOrthancImageCommand : public OracleCommandWithPayload
319 {
320 public:
321 class SuccessMessage : public OrthancStone::OriginMessage<GetOrthancImageCommand>
322 {
323 ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
324
325 private:
326 std::auto_ptr<Orthanc::ImageAccessor> image_;
327 Orthanc::MimeType mime_;
328
329 public:
330 SuccessMessage(const GetOrthancImageCommand& command,
331 Orthanc::ImageAccessor* image, // Takes ownership
332 Orthanc::MimeType mime) :
333 OriginMessage(command),
334 image_(image),
335 mime_(mime)
336 {
337 if (image == NULL)
338 {
339 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
340 }
341 }
342
343 const Orthanc::ImageAccessor& GetImage() const
344 {
345 return *image_;
346 }
347
348 Orthanc::MimeType GetMimeType() const
349 {
350 return mime_;
351 }
352 };
353
354
355 private:
356 std::string uri_;
357 HttpHeaders headers_;
358 unsigned int timeout_;
359
360 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_;
361 std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> > failureCallback_;
362
363 public:
364 GetOrthancImageCommand() :
365 uri_("/"),
366 timeout_(10)
367 {
368 }
369
370 virtual Type GetType() const
371 {
372 return Type_GetOrthancImage;
373 }
374
375 void SetUri(const std::string& uri)
376 {
377 uri_ = uri;
378 }
379
380 void SetHttpHeader(const std::string& key,
381 const std::string& value)
382 {
383 headers_[key] = value;
384 }
385
386 const std::string& GetUri() const
387 {
388 return uri_;
389 }
390
391 const HttpHeaders& GetHttpHeaders() const
392 {
393 return headers_;
394 }
395
396 void SetTimeout(unsigned int seconds)
397 {
398 timeout_ = seconds;
399 }
400
401 unsigned int GetTimeout() const
402 {
403 return timeout_;
404 }
405
406 void ProcessHttpAnswer(IMessageEmitter& emitter,
407 const OrthancStone::IObserver& receiver,
408 const std::string& answer,
409 const HttpHeaders& answerHeaders) const
410 {
411 Orthanc::MimeType contentType = Orthanc::MimeType_Binary;
412
413 for (HttpHeaders::const_iterator it = answerHeaders.begin();
414 it != answerHeaders.end(); ++it)
415 {
416 std::string s;
417 Orthanc::Toolbox::ToLowerCase(s, it->first);
418
419 if (s == "content-type")
420 {
421 contentType = Orthanc::StringToMimeType(it->second);
422 break;
423 }
424 }
425
426 std::auto_ptr<Orthanc::ImageAccessor> image;
427
428 switch (contentType)
429 {
430 case Orthanc::MimeType_Png:
431 {
432 image.reset(new Orthanc::PngReader);
433 dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(answer);
434 break;
435 }
436
437 case Orthanc::MimeType_Pam:
438 {
439 image.reset(new Orthanc::PamReader);
440 dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(answer);
441 break;
442 }
443
444 case Orthanc::MimeType_Jpeg:
445 {
446 image.reset(new Orthanc::JpegReader);
447 dynamic_cast<Orthanc::JpegReader&>(*image).ReadFromMemory(answer);
448 break;
449 }
450
451 default:
452 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
453 "Unsupported HTTP Content-Type for an image: " +
454 std::string(Orthanc::EnumerationToString(contentType)));
455 }
456
457 SuccessMessage message(*this, image.release(), contentType);
458 emitter.EmitMessage(receiver, message);
459 }
460 };
461
462
463
464 class GetOrthancWebViewerJpegCommand : public OracleCommandWithPayload
465 {
466 public:
467 class SuccessMessage : public OrthancStone::OriginMessage<GetOrthancWebViewerJpegCommand>
468 {
469 ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
470
471 private:
472 std::auto_ptr<Orthanc::ImageAccessor> image_;
473
474 public:
475 SuccessMessage(const GetOrthancWebViewerJpegCommand& command,
476 Orthanc::ImageAccessor* image) : // Takes ownership
477 OriginMessage(command),
478 image_(image)
479 {
480 if (image == NULL)
481 {
482 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
483 }
484 }
485
486 const Orthanc::ImageAccessor& GetImage() const
487 {
488 return *image_;
489 }
490 };
491
492 private:
493 std::string instanceId_;
494 unsigned int frame_;
495 unsigned int quality_;
496 HttpHeaders headers_;
497 unsigned int timeout_;
498 Orthanc::PixelFormat expectedFormat_;
499
500 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_;
501 std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> > failureCallback_;
502
503 public:
504 GetOrthancWebViewerJpegCommand() :
505 frame_(0),
506 quality_(95),
507 timeout_(10),
508 expectedFormat_(Orthanc::PixelFormat_Grayscale8)
509 {
510 }
511
512 virtual Type GetType() const
513 {
514 return Type_GetOrthancWebViewerJpeg;
515 }
516
517 void SetExpectedFormat(Orthanc::PixelFormat format)
518 {
519 expectedFormat_ = format;
520 }
521
522 void SetInstance(const std::string& instanceId)
523 {
524 instanceId_ = instanceId;
525 }
526
527 void SetFrame(unsigned int frame)
528 {
529 frame_ = frame;
530 }
531
532 void SetQuality(unsigned int quality)
533 {
534 if (quality <= 0 ||
535 quality > 100)
536 {
537 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
538 }
539 else
540 {
541 quality_ = quality;
542 }
543 }
544
545 void SetHttpHeader(const std::string& key,
546 const std::string& value)
547 {
548 headers_[key] = value;
549 }
550
551 Orthanc::PixelFormat GetExpectedFormat() const
552 {
553 return expectedFormat_;
554 }
555
556 const std::string& GetInstanceId() const
557 {
558 return instanceId_;
559 }
560
561 unsigned int GetFrame() const
562 {
563 return frame_;
564 }
565
566 unsigned int GetQuality() const
567 {
568 return quality_;
569 }
570
571 const HttpHeaders& GetHttpHeaders() const
572 {
573 return headers_;
574 }
575
576 void SetTimeout(unsigned int seconds)
577 {
578 timeout_ = seconds;
579 }
580
581 unsigned int GetTimeout() const
582 {
583 return timeout_;
584 }
585
586 std::string GetUri() const
587 {
588 return ("/web-viewer/instances/jpeg" + boost::lexical_cast<std::string>(quality_) +
589 "-" + instanceId_ + "_" + boost::lexical_cast<std::string>(frame_));
590 }
591
592 void ProcessHttpAnswer(IMessageEmitter& emitter,
593 const OrthancStone::IObserver& receiver,
594 const std::string& answer) const
595 {
596 // This code comes from older "OrthancSlicesLoader::ParseSliceImageJpeg()"
597
598 Json::Value encoded;
599
600 {
601 Json::Reader reader;
602 if (!reader.parse(answer, encoded))
603 {
604 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
605 }
606 }
607
608 if (encoded.type() != Json::objectValue ||
609 !encoded.isMember("Orthanc") ||
610 encoded["Orthanc"].type() != Json::objectValue)
611 {
612 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
613 }
614
615 const Json::Value& info = encoded["Orthanc"];
616 if (!info.isMember("PixelData") ||
617 !info.isMember("Stretched") ||
618 !info.isMember("Compression") ||
619 info["Compression"].type() != Json::stringValue ||
620 info["PixelData"].type() != Json::stringValue ||
621 info["Stretched"].type() != Json::booleanValue ||
622 info["Compression"].asString() != "Jpeg")
623 {
624 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
625 }
626
627 bool isSigned = false;
628 bool isStretched = info["Stretched"].asBool();
629
630 if (info.isMember("IsSigned"))
631 {
632 if (info["IsSigned"].type() != Json::booleanValue)
633 {
634 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
635 }
636 else
637 {
638 isSigned = info["IsSigned"].asBool();
639 }
640 }
641
642 std::auto_ptr<Orthanc::ImageAccessor> reader;
643
644 {
645 std::string jpeg;
646 Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
647
648 reader.reset(new Orthanc::JpegReader);
649 dynamic_cast<Orthanc::JpegReader&>(*reader).ReadFromMemory(jpeg);
650 }
651
652 if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image
653 {
654 if (expectedFormat_ != Orthanc::PixelFormat_RGB24)
655 {
656 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
657 }
658
659 if (isSigned || isStretched)
660 {
661 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
662 }
663 else
664 {
665 SuccessMessage message(*this, reader.release());
666 emitter.EmitMessage(receiver, message);
667 return;
668 }
669 }
670
671 if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8)
672 {
673 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
674 }
675
676 if (!isStretched)
677 {
678 if (expectedFormat_ != reader->GetFormat())
679 {
680 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
681 }
682 else
683 {
684 SuccessMessage message(*this, reader.release());
685 emitter.EmitMessage(receiver, message);
686 return;
687 }
688 }
689
690 int32_t stretchLow = 0;
691 int32_t stretchHigh = 0;
692
693 if (!info.isMember("StretchLow") ||
694 !info.isMember("StretchHigh") ||
695 info["StretchLow"].type() != Json::intValue ||
696 info["StretchHigh"].type() != Json::intValue)
697 {
698 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
699 }
700
701 stretchLow = info["StretchLow"].asInt();
702 stretchHigh = info["StretchHigh"].asInt();
703
704 if (stretchLow < -32768 ||
705 stretchHigh > 65535 ||
706 (stretchLow < 0 && stretchHigh > 32767))
707 {
708 // This range cannot be represented with a uint16_t or an int16_t
709 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
710 }
711
712 // Decode a grayscale JPEG 8bpp image coming from the Web viewer
713 std::auto_ptr<Orthanc::ImageAccessor> image
714 (new Orthanc::Image(expectedFormat_, reader->GetWidth(), reader->GetHeight(), false));
715
716 Orthanc::ImageProcessing::Convert(*image, *reader);
717 reader.reset();
718
719 float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
720
721 if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling))
722 {
723 float offset = static_cast<float>(stretchLow) / scaling;
724 Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
725 }
726
727 SuccessMessage message(*this, image.release());
728 emitter.EmitMessage(receiver, message);
729 }
730 };
731
732
286 733
287 734
288 735
289 class NativeOracle : public IOracle 736 class NativeOracle : public IOracle
290 { 737 {
334 State state_; 781 State state_;
335 boost::mutex mutex_; 782 boost::mutex mutex_;
336 std::vector<boost::thread*> workers_; 783 std::vector<boost::thread*> workers_;
337 784
338 785
786 void CopyHttpHeaders(Orthanc::HttpClient& client,
787 const HttpHeaders& headers)
788 {
789 for (HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); it++ )
790 {
791 client.AddHeader(it->first, it->second);
792 }
793 }
794
795
796 void DecodeAnswer(std::string& answer,
797 const HttpHeaders& headers)
798 {
799 Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None;
800
801 for (HttpHeaders::const_iterator it = headers.begin();
802 it != headers.end(); ++it)
803 {
804 std::string s;
805 Orthanc::Toolbox::ToLowerCase(s, it->first);
806
807 if (s == "content-encoding")
808 {
809 if (it->second == "gzip")
810 {
811 contentEncoding = Orthanc::HttpCompression_Gzip;
812 }
813 else
814 {
815 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
816 "Unsupported HTTP Content-Encoding: " + it->second);
817 }
818
819 break;
820 }
821 }
822
823 if (contentEncoding == Orthanc::HttpCompression_Gzip)
824 {
825 std::string compressed;
826 answer.swap(compressed);
827
828 Orthanc::GzipCompressor compressor;
829 compressor.Uncompress(answer, compressed.c_str(), compressed.size());
830 }
831 }
832
833
339 void Execute(const OrthancStone::IObserver& receiver, 834 void Execute(const OrthancStone::IObserver& receiver,
340 const OrthancApiOracleCommand& command) 835 const OrthancRestApiCommand& command)
341 { 836 {
342 Orthanc::HttpClient client(orthanc_, command.GetUri()); 837 Orthanc::HttpClient client(orthanc_, command.GetUri());
343 client.SetMethod(command.GetMethod()); 838 client.SetMethod(command.GetMethod());
344 client.SetTimeout(command.GetTimeout()); 839 client.SetTimeout(command.GetTimeout());
345 840
841 CopyHttpHeaders(client, command.GetHttpHeaders());
842
346 if (command.GetMethod() == Orthanc::HttpMethod_Post || 843 if (command.GetMethod() == Orthanc::HttpMethod_Post ||
347 command.GetMethod() == Orthanc::HttpMethod_Put) 844 command.GetMethod() == Orthanc::HttpMethod_Put)
348 { 845 {
349 client.SetBody(command.GetBody()); 846 client.SetBody(command.GetBody());
350 } 847 }
351
352 {
353 const HttpHeaders& headers = command.GetHttpHeaders();
354 for (HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); it++ )
355 {
356 client.AddHeader(it->first, it->second);
357 }
358 }
359 848
360 std::string answer; 849 std::string answer;
361 HttpHeaders answerHeaders; 850 HttpHeaders answerHeaders;
362 851 client.ApplyAndThrowException(answer, answerHeaders);
363 bool success; 852
364 try 853 DecodeAnswer(answer, answerHeaders);
365 { 854
366 success = client.Apply(answer, answerHeaders); 855 OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer);
367 } 856 emitter_.EmitMessage(receiver, message);
368 catch (Orthanc::OrthancException& e) 857 }
369 { 858
370 success = false; 859
371 } 860 void Execute(const OrthancStone::IObserver& receiver,
372 861 const GetOrthancImageCommand& command)
373 if (success) 862 {
374 { 863 Orthanc::HttpClient client(orthanc_, command.GetUri());
375 OrthancApiOracleCommand::SuccessMessage message(command, answerHeaders, answer); 864 client.SetTimeout(command.GetTimeout());
376 emitter_.EmitMessage(receiver, message); 865
377 } 866 CopyHttpHeaders(client, command.GetHttpHeaders());
378 else 867
379 { 868 std::string answer;
380 OrthancApiOracleCommand::FailureMessage message(command, client.GetLastStatus()); 869 HttpHeaders answerHeaders;
381 emitter_.EmitMessage(receiver, message); 870 client.ApplyAndThrowException(answer, answerHeaders);
382 } 871
383 } 872 DecodeAnswer(answer, answerHeaders);
384 873
874 command.ProcessHttpAnswer(emitter_, receiver, answer, answerHeaders);
875 }
876
877
878 void Execute(const OrthancStone::IObserver& receiver,
879 const GetOrthancWebViewerJpegCommand& command)
880 {
881 Orthanc::HttpClient client(orthanc_, command.GetUri());
882 client.SetTimeout(command.GetTimeout());
883
884 CopyHttpHeaders(client, command.GetHttpHeaders());
885
886 std::string answer;
887 HttpHeaders answerHeaders;
888 client.ApplyAndThrowException(answer, answerHeaders);
889
890 DecodeAnswer(answer, answerHeaders);
891
892 command.ProcessHttpAnswer(emitter_, receiver, answer);
893 }
385 894
386 895
387 void Step() 896 void Step()
388 { 897 {
389 std::auto_ptr<Orthanc::IDynamicObject> object(queue_.Dequeue(100)); 898 std::auto_ptr<Orthanc::IDynamicObject> object(queue_.Dequeue(100));
390 899
391 if (object.get() != NULL) 900 if (object.get() != NULL)
392 { 901 {
902 printf("===========================> REQUEST\n");
903
393 const Item& item = dynamic_cast<Item&>(*object); 904 const Item& item = dynamic_cast<Item&>(*object);
394 905
395 try 906 try
396 { 907 {
397 switch (item.GetCommand().GetType()) 908 switch (item.GetCommand().GetType())
398 { 909 {
399 case IOracleCommand::Type_OrthancApi: 910 case IOracleCommand::Type_OrthancRestApi:
400 Execute(item.GetReceiver(), 911 Execute(item.GetReceiver(),
401 dynamic_cast<const OrthancApiOracleCommand&>(item.GetCommand())); 912 dynamic_cast<const OrthancRestApiCommand&>(item.GetCommand()));
913 break;
914
915 case IOracleCommand::Type_GetOrthancImage:
916 Execute(item.GetReceiver(),
917 dynamic_cast<const GetOrthancImageCommand&>(item.GetCommand()));
918 break;
919
920 case IOracleCommand::Type_GetOrthancWebViewerJpeg:
921 Execute(item.GetReceiver(),
922 dynamic_cast<const GetOrthancWebViewerJpegCommand&>(item.GetCommand()));
402 break; 923 break;
403 924
404 default: 925 default:
405 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 926 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
406 } 927 }
407 } 928 }
408 catch (Orthanc::OrthancException& e) 929 catch (Orthanc::OrthancException& e)
409 { 930 {
410 LOG(ERROR) << "Exception within the oracle: " << e.What(); 931 LOG(ERROR) << "Exception within the oracle: " << e.What();
932 emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage(item.GetCommand(), e));
411 } 933 }
412 catch (...) 934 catch (...)
413 { 935 {
414 LOG(ERROR) << "Native exception within the oracle"; 936 LOG(ERROR) << "Native exception within the oracle";
937 emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage
938 (item.GetCommand(), Orthanc::ErrorCode_InternalError));
415 } 939 }
416 } 940 }
417 } 941 }
418 942
419 943
560 1084
561 1085
562 virtual void EmitMessage(const OrthancStone::IObserver& observer, 1086 virtual void EmitMessage(const OrthancStone::IObserver& observer,
563 const OrthancStone::IMessage& message) 1087 const OrthancStone::IMessage& message)
564 { 1088 {
565 boost::unique_lock<boost::shared_mutex> lock(mutex_); 1089 try
566 oracleObservable_.EmitMessage(observer, message); 1090 {
1091 boost::unique_lock<boost::shared_mutex> lock(mutex_);
1092 oracleObservable_.EmitMessage(observer, message);
1093 }
1094 catch (Orthanc::OrthancException& e)
1095 {
1096 LOG(ERROR) << "Exception while emitting a message: " << e.What();
1097 }
567 } 1098 }
568 1099
569 1100
570 class ReaderLock : public boost::noncopyable 1101 class ReaderLock : public boost::noncopyable
571 { 1102 {
800 return geometry_; 1331 return geometry_;
801 } 1332 }
802 1333
803 OrthancStone::CoordinateSystem3D GetFrameGeometry(unsigned int frame) const 1334 OrthancStone::CoordinateSystem3D GetFrameGeometry(unsigned int frame) const
804 { 1335 {
805 if (frame >= imageInformation_.GetNumberOfFrames()) 1336 if (frame == 0)
1337 {
1338 return geometry_;
1339 }
1340 else if (frame >= imageInformation_.GetNumberOfFrames())
806 { 1341 {
807 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 1342 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
808 } 1343 }
809 1344 else if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
810 if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
811 { 1345 {
812 if (frame >= frameOffsets_.size()) 1346 if (frame >= frameOffsets_.size())
813 { 1347 {
814 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 1348 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
815 } 1349 }
816 1350
817 return OrthancStone::CoordinateSystem3D( 1351 return OrthancStone::CoordinateSystem3D(
818 geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(), 1352 geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(),
819 geometry_.GetAxisX(), 1353 geometry_.GetAxisX(),
820 geometry_.GetAxisY()); 1354 geometry_.GetAxisY());
1355 }
1356 else
1357 {
1358 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
821 } 1359 }
822 } 1360 }
823 1361
824 bool FrameContainsPlane(unsigned int frame, 1362 bool FrameContainsPlane(unsigned int frame,
825 const OrthancStone::CoordinateSystem3D& plane) const 1363 const OrthancStone::CoordinateSystem3D& plane) const
919 { 1457 {
920 private: 1458 private:
921 class MessageHandler : public Orthanc::IDynamicObject 1459 class MessageHandler : public Orthanc::IDynamicObject
922 { 1460 {
923 public: 1461 public:
924 virtual void Handle(const OrthancApiOracleCommand::SuccessMessage& message) const = 0; 1462 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0;
925 }; 1463 };
926 1464
927 void Handle(const OrthancApiOracleCommand::SuccessMessage& message) 1465 void Handle(const OrthancRestApiCommand::SuccessMessage& message)
928 { 1466 {
929 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message); 1467 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message);
930 } 1468 }
931 1469
932 1470
939 LoadSeriesGeometryHandler(AxialVolumeOrthancLoader& that) : 1477 LoadSeriesGeometryHandler(AxialVolumeOrthancLoader& that) :
940 that_(that) 1478 that_(that)
941 { 1479 {
942 } 1480 }
943 1481
944 virtual void Handle(const OrthancApiOracleCommand::SuccessMessage& message) const 1482 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
945 { 1483 {
946 Json::Value value; 1484 Json::Value value;
947 message.ParseJsonBody(value); 1485 message.ParseJsonBody(value);
948 1486
949 if (value.type() != Json::objectValue) 1487 if (value.type() != Json::objectValue)
973 LoadInstanceGeometryHandler(AxialVolumeOrthancLoader& that) : 1511 LoadInstanceGeometryHandler(AxialVolumeOrthancLoader& that) :
974 that_(that) 1512 that_(that)
975 { 1513 {
976 } 1514 }
977 1515
978 virtual void Handle(const OrthancApiOracleCommand::SuccessMessage& message) const 1516 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
979 { 1517 {
980 Json::Value value; 1518 Json::Value value;
981 message.ParseJsonBody(value); 1519 message.ParseJsonBody(value);
982 1520
983 if (value.type() != Json::objectValue) 1521 if (value.type() != Json::objectValue)
1001 AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) : 1539 AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) :
1002 IObserver(oracle.GetBroker()), 1540 IObserver(oracle.GetBroker()),
1003 active_(false) 1541 active_(false)
1004 { 1542 {
1005 oracle.RegisterObserverCallback( 1543 oracle.RegisterObserverCallback(
1006 new OrthancStone::Callable<AxialVolumeOrthancLoader, OrthancApiOracleCommand::SuccessMessage> 1544 new OrthancStone::Callable<AxialVolumeOrthancLoader, OrthancRestApiCommand::SuccessMessage>
1007 (*this, &AxialVolumeOrthancLoader::Handle)); 1545 (*this, &AxialVolumeOrthancLoader::Handle));
1008 } 1546 }
1009 1547
1010 void LoadSeries(IOracle& oracle, 1548 void LoadSeries(IOracle& oracle,
1011 const std::string& seriesId) 1549 const std::string& seriesId)
1015 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 1553 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1016 } 1554 }
1017 1555
1018 active_ = true; 1556 active_ = true;
1019 1557
1020 std::auto_ptr<Refactoring::OrthancApiOracleCommand> command(new Refactoring::OrthancApiOracleCommand); 1558 std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
1021 command->SetUri("/series/" + seriesId + "/instances-tags"); 1559 command->SetUri("/series/" + seriesId + "/instances-tags");
1022 command->SetPayload(new LoadSeriesGeometryHandler(*this)); 1560 command->SetPayload(new LoadSeriesGeometryHandler(*this));
1023 1561
1024 oracle.Schedule(*this, command.release()); 1562 oracle.Schedule(*this, command.release());
1025 } 1563 }
1037 // Tag "3004-000c" is "Grid Frame Offset Vector", which is 1575 // Tag "3004-000c" is "Grid Frame Offset Vector", which is
1038 // mandatory to read RT DOSE, but is too long to be returned by default 1576 // mandatory to read RT DOSE, but is too long to be returned by default
1039 1577
1040 // TODO => Should be part of a second call if needed 1578 // TODO => Should be part of a second call if needed
1041 1579
1042 std::auto_ptr<Refactoring::OrthancApiOracleCommand> command(new Refactoring::OrthancApiOracleCommand); 1580 std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
1043 command->SetUri("/instances/" + instanceId + "/tags?ignore-length=3004-000c"); 1581 command->SetUri("/instances/" + instanceId + "/tags?ignore-length=3004-000c");
1044 command->SetPayload(new LoadInstanceGeometryHandler(*this)); 1582 command->SetPayload(new LoadInstanceGeometryHandler(*this));
1045 1583
1046 oracle.Schedule(*this, command.release()); 1584 oracle.Schedule(*this, command.release());
1047 } 1585 }
1052 1590
1053 1591
1054 class Toto : public OrthancStone::IObserver 1592 class Toto : public OrthancStone::IObserver
1055 { 1593 {
1056 private: 1594 private:
1057 void Handle(const Refactoring::OrthancApiOracleCommand::SuccessMessage& message) 1595 void Handle(const Refactoring::OrthancRestApiCommand::SuccessMessage& message)
1058 { 1596 {
1059 Json::Value v; 1597 Json::Value v;
1060 message.ParseJsonBody(v); 1598 message.ParseJsonBody(v);
1061 1599
1062 printf("ICI [%s]\n", v.toStyledString().c_str()); 1600 printf("ICI [%s]\n", v.toStyledString().c_str());
1063 } 1601 }
1064 1602
1065 void Handle(const Refactoring::OrthancApiOracleCommand::FailureMessage& message) 1603 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message)
1066 { 1604 {
1067 printf("ERROR %d\n", message.GetHttpStatus()); 1605 printf("IMAGE %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
1606 }
1607
1608 void Handle(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
1609 {
1610 printf("WebViewer %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
1611 }
1612
1613 void Handle(const Refactoring::OracleCommandExceptionMessage& message)
1614 {
1615 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType());
1616
1617 switch (message.GetCommand().GetType())
1618 {
1619 case Refactoring::IOracleCommand::Type_GetOrthancWebViewerJpeg:
1620 printf("URI: [%s]\n", dynamic_cast<const Refactoring::GetOrthancWebViewerJpegCommand&>
1621 (message.GetCommand()).GetUri().c_str());
1622 break;
1623
1624 default:
1625 break;
1626 }
1068 } 1627 }
1069 1628
1070 public: 1629 public:
1071 Toto(OrthancStone::IObservable& oracle) : 1630 Toto(OrthancStone::IObservable& oracle) :
1072 IObserver(oracle.GetBroker()) 1631 IObserver(oracle.GetBroker())
1073 { 1632 {
1074 oracle.RegisterObserverCallback 1633 oracle.RegisterObserverCallback
1075 (new OrthancStone::Callable 1634 (new OrthancStone::Callable
1076 <Toto, Refactoring::OrthancApiOracleCommand::SuccessMessage>(*this, &Toto::Handle)); 1635 <Toto, Refactoring::OrthancRestApiCommand::SuccessMessage>(*this, &Toto::Handle));
1636
1637 oracle.RegisterObserverCallback
1638 (new OrthancStone::Callable
1639 <Toto, Refactoring::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle));
1640
1641 oracle.RegisterObserverCallback
1642 (new OrthancStone::Callable
1643 <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle));
1644
1645 oracle.RegisterObserverCallback
1646 (new OrthancStone::Callable
1647 <Toto, Refactoring::OracleCommandExceptionMessage>(*this, &Toto::Handle));
1077 } 1648 }
1078 }; 1649 };
1079 1650
1080 1651
1081 void Run(Refactoring::NativeApplicationContext& context) 1652 void Run(Refactoring::NativeApplicationContext& context)
1099 oracle.SetOrthancParameters(p); 1670 oracle.SetOrthancParameters(p);
1100 } 1671 }
1101 1672
1102 oracle.Start(); 1673 oracle.Start();
1103 1674
1675 if (1)
1104 { 1676 {
1105 Json::Value v = Json::objectValue; 1677 Json::Value v = Json::objectValue;
1106 v["Level"] = "Series"; 1678 v["Level"] = "Series";
1107 v["Query"] = Json::objectValue; 1679 v["Query"] = Json::objectValue;
1108 1680
1109 std::auto_ptr<Refactoring::OrthancApiOracleCommand> command(new Refactoring::OrthancApiOracleCommand); 1681 std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
1110 command->SetMethod(Orthanc::HttpMethod_Post); 1682 command->SetMethod(Orthanc::HttpMethod_Post);
1111 command->SetUri("/tools/find"); 1683 command->SetUri("/tools/find");
1112 command->SetBody(v); 1684 command->SetBody(v);
1113 1685
1114 oracle.Schedule(*toto, command.release()); 1686 oracle.Schedule(*toto, command.release());
1115 } 1687 }
1116 1688
1689 if (1)
1690 {
1691 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1692 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg)));
1693 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
1694 oracle.Schedule(*toto, command.release());
1695 }
1696
1697 if (1)
1698 {
1699 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1700 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
1701 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
1702 oracle.Schedule(*toto, command.release());
1703 }
1704
1705 if (1)
1706 {
1707 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1708 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
1709 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
1710 oracle.Schedule(*toto, command.release());
1711 }
1712
1713 if (1)
1714 {
1715 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1716 command->SetHttpHeader("Accept-Encoding", "gzip");
1717 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
1718 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
1719 oracle.Schedule(*toto, command.release());
1720 }
1721
1722 if (1)
1723 {
1724 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1725 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
1726 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
1727 oracle.Schedule(*toto, command.release());
1728 }
1729
1730 if (1)
1731 {
1732 std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> command(new Refactoring::GetOrthancWebViewerJpegCommand);
1733 command->SetHttpHeader("Accept-Encoding", "gzip");
1734 command->SetInstance("e6c7c20b-c9f65d7e-0d76f2e2-830186f2-3e3c600e");
1735 command->SetQuality(90);
1736 oracle.Schedule(*toto, command.release());
1737 }
1738
1739
1117 // 2017-11-17-Anonymized 1740 // 2017-11-17-Anonymized
1118 loader1->LoadSeries(oracle, "cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT 1741 loader1->LoadSeries(oracle, "cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
1119 loader2->LoadInstance(oracle, "41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE 1742 loader2->LoadInstance(oracle, "41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
1120 1743
1121 boost::this_thread::sleep(boost::posix_time::seconds(1)); 1744 LOG(WARNING) << "...Waiting for Ctrl-C...";
1745 Orthanc::SystemToolbox::ServerBarrier();
1746 //boost::this_thread::sleep(boost::posix_time::seconds(1));
1122 1747
1123 oracle.Stop(); 1748 oracle.Stop();
1124 } 1749 }
1125 1750
1126 1751