comparison Samples/Sdl/Loader.cpp @ 642:7ca8dc7ec17b

GetOrthancWebViewerJpegCommand::ProcessHttpHandler()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 10 May 2019 14:54:03 +0200
parents 392783c90607
children f0008c55e5f7 1e9ed656318e
comparison
equal deleted inserted replaced
641:392783c90607 642:7ca8dc7ec17b
42 #include <Core/Images/PngWriter.h> 42 #include <Core/Images/PngWriter.h>
43 #include <Core/Logging.h> 43 #include <Core/Logging.h>
44 #include <Core/MultiThreading/SharedMessageQueue.h> 44 #include <Core/MultiThreading/SharedMessageQueue.h>
45 #include <Core/OrthancException.h> 45 #include <Core/OrthancException.h>
46 #include <Core/Toolbox.h> 46 #include <Core/Toolbox.h>
47 #include <Core/SystemToolbox.h>
47 48
48 #include <json/reader.h> 49 #include <json/reader.h>
49 #include <json/value.h> 50 #include <json/value.h>
50 #include <json/writer.h> 51 #include <json/writer.h>
51 52
137 }; 138 };
138 139
139 140
140 141
141 class OracleCommandExceptionMessage : 142 class OracleCommandExceptionMessage :
142 public OrthancStone::BaseMessage<OrthancStone::MessageType_OrthancException> 143 public OrthancStone::BaseMessage<OrthancStone::MessageType_OracleCommandExceptionMessage>
143 { 144 {
144 private: 145 private:
145 const IOracleCommand& command_; 146 const IOracleCommand& command_;
146 Orthanc::OrthancException exception_; 147 Orthanc::OrthancException exception_;
147 148
175 typedef std::map<std::string, std::string> HttpHeaders; 176 typedef std::map<std::string, std::string> HttpHeaders;
176 177
177 class OrthancRestApiCommand : public OracleCommandWithPayload 178 class OrthancRestApiCommand : public OracleCommandWithPayload
178 { 179 {
179 public: 180 public:
180 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_HttpRequestSuccess, // TODO 181 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_OrthancRestApiCommand,
181 OrthancRestApiCommand> 182 OrthancRestApiCommand>
182 { 183 {
183 private: 184 private:
184 HttpHeaders headers_; 185 HttpHeaders headers_;
185 std::string answer_; 186 std::string answer_;
313 314
314 315
315 class GetOrthancImageCommand : public OracleCommandWithPayload 316 class GetOrthancImageCommand : public OracleCommandWithPayload
316 { 317 {
317 public: 318 public:
318 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_ImageReady, // TODO 319 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_GetOrthancImageCommand,
319 GetOrthancImageCommand> 320 GetOrthancImageCommand>
320 { 321 {
321 private: 322 private:
322 std::auto_ptr<Orthanc::ImageAccessor> image_; 323 std::auto_ptr<Orthanc::ImageAccessor> image_;
323 Orthanc::MimeType mime_; 324 Orthanc::MimeType mime_;
448 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, 449 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
449 "Unsupported HTTP Content-Type for an image: " + 450 "Unsupported HTTP Content-Type for an image: " +
450 std::string(Orthanc::EnumerationToString(contentType))); 451 std::string(Orthanc::EnumerationToString(contentType)));
451 } 452 }
452 453
453 GetOrthancImageCommand::SuccessMessage message(*this, image.release(), contentType); 454 SuccessMessage message(*this, image.release(), contentType);
454 emitter.EmitMessage(receiver, message); 455 emitter.EmitMessage(receiver, message);
455 } 456 }
456 }; 457 };
457 458
458 459
459 460
460 class GetOrthancWebViewerJpegCommand : public OracleCommandWithPayload 461 class GetOrthancWebViewerJpegCommand : public OracleCommandWithPayload
461 { 462 {
462 public: 463 public:
463 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_ImageReady, // TODO 464 class SuccessMessage : public OrthancStone::OriginMessage<OrthancStone::MessageType_GetOrthancWebViewerJpegCommand,
464 GetOrthancWebViewerJpegCommand> 465 GetOrthancWebViewerJpegCommand>
465 { 466 {
466 private: 467 private:
467 std::auto_ptr<Orthanc::ImageAccessor> image_; 468 std::auto_ptr<Orthanc::ImageAccessor> image_;
468 469
483 return *image_; 484 return *image_;
484 } 485 }
485 }; 486 };
486 487
487 private: 488 private:
488 std::string instanceId_; 489 std::string instanceId_;
489 unsigned int frame_; 490 unsigned int frame_;
490 unsigned int quality_; 491 unsigned int quality_;
491 HttpHeaders headers_; 492 HttpHeaders headers_;
492 unsigned int timeout_; 493 unsigned int timeout_;
494 Orthanc::PixelFormat expectedFormat_;
493 495
494 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_; 496 std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> > successCallback_;
495 std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> > failureCallback_; 497 std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> > failureCallback_;
496 498
497 public: 499 public:
498 GetOrthancWebViewerJpegCommand() : 500 GetOrthancWebViewerJpegCommand() :
499 frame_(0), 501 frame_(0),
500 quality_(95), 502 quality_(95),
501 timeout_(10) 503 timeout_(10),
504 expectedFormat_(Orthanc::PixelFormat_Grayscale8)
502 { 505 {
503 } 506 }
504 507
505 virtual Type GetType() const 508 virtual Type GetType() const
506 { 509 {
507 return Type_GetOrthancWebViewerJpeg; 510 return Type_GetOrthancWebViewerJpeg;
511 }
512
513 void SetExpectedFormat(Orthanc::PixelFormat format)
514 {
515 expectedFormat_ = format;
508 } 516 }
509 517
510 void SetInstance(const std::string& instanceId) 518 void SetInstance(const std::string& instanceId)
511 { 519 {
512 instanceId_ = instanceId; 520 instanceId_ = instanceId;
532 540
533 void SetHttpHeader(const std::string& key, 541 void SetHttpHeader(const std::string& key,
534 const std::string& value) 542 const std::string& value)
535 { 543 {
536 headers_[key] = value; 544 headers_[key] = value;
545 }
546
547 Orthanc::PixelFormat GetExpectedFormat() const
548 {
549 return expectedFormat_;
537 } 550 }
538 551
539 const std::string& GetInstanceId() const 552 const std::string& GetInstanceId() const
540 { 553 {
541 return instanceId_; 554 return instanceId_;
574 587
575 void ProcessHttpAnswer(IMessageEmitter& emitter, 588 void ProcessHttpAnswer(IMessageEmitter& emitter,
576 const OrthancStone::IObserver& receiver, 589 const OrthancStone::IObserver& receiver,
577 const std::string& answer) const 590 const std::string& answer) const
578 { 591 {
579 Json::Value value; 592 // This code comes from older "OrthancSlicesLoader::ParseSliceImageJpeg()"
580 Json::Reader reader; 593
581 if (!reader.parse(answer, value)) 594 Json::Value encoded;
595
596 {
597 Json::Reader reader;
598 if (!reader.parse(answer, encoded))
599 {
600 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
601 }
602 }
603
604 if (encoded.type() != Json::objectValue ||
605 !encoded.isMember("Orthanc") ||
606 encoded["Orthanc"].type() != Json::objectValue)
582 { 607 {
583 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 608 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
584 } 609 }
585 610
586 //GetOrthancWebViewerJpegCommand::SuccessMessage message(command, image.release(), contentType); 611 const Json::Value& info = encoded["Orthanc"];
587 //emitter.EmitMessage(receiver, message); 612 if (!info.isMember("PixelData") ||
613 !info.isMember("Stretched") ||
614 !info.isMember("Compression") ||
615 info["Compression"].type() != Json::stringValue ||
616 info["PixelData"].type() != Json::stringValue ||
617 info["Stretched"].type() != Json::booleanValue ||
618 info["Compression"].asString() != "Jpeg")
619 {
620 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
621 }
622
623 bool isSigned = false;
624 bool isStretched = info["Stretched"].asBool();
625
626 if (info.isMember("IsSigned"))
627 {
628 if (info["IsSigned"].type() != Json::booleanValue)
629 {
630 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
631 }
632 else
633 {
634 isSigned = info["IsSigned"].asBool();
635 }
636 }
637
638 std::auto_ptr<Orthanc::ImageAccessor> reader;
639
640 {
641 std::string jpeg;
642 Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
643
644 reader.reset(new Orthanc::JpegReader);
645 dynamic_cast<Orthanc::JpegReader&>(*reader).ReadFromMemory(jpeg);
646 }
647
648 if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image
649 {
650 if (expectedFormat_ != Orthanc::PixelFormat_RGB24)
651 {
652 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
653 }
654
655 if (isSigned || isStretched)
656 {
657 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
658 }
659 else
660 {
661 SuccessMessage message(*this, reader.release());
662 emitter.EmitMessage(receiver, message);
663 return;
664 }
665 }
666
667 if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8)
668 {
669 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
670 }
671
672 if (!isStretched)
673 {
674 if (expectedFormat_ != reader->GetFormat())
675 {
676 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
677 }
678 else
679 {
680 SuccessMessage message(*this, reader.release());
681 emitter.EmitMessage(receiver, message);
682 return;
683 }
684 }
685
686 int32_t stretchLow = 0;
687 int32_t stretchHigh = 0;
688
689 if (!info.isMember("StretchLow") ||
690 !info.isMember("StretchHigh") ||
691 info["StretchLow"].type() != Json::intValue ||
692 info["StretchHigh"].type() != Json::intValue)
693 {
694 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
695 }
696
697 stretchLow = info["StretchLow"].asInt();
698 stretchHigh = info["StretchHigh"].asInt();
699
700 if (stretchLow < -32768 ||
701 stretchHigh > 65535 ||
702 (stretchLow < 0 && stretchHigh > 32767))
703 {
704 // This range cannot be represented with a uint16_t or an int16_t
705 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
706 }
707
708 // Decode a grayscale JPEG 8bpp image coming from the Web viewer
709 std::auto_ptr<Orthanc::ImageAccessor> image
710 (new Orthanc::Image(expectedFormat_, reader->GetWidth(), reader->GetHeight(), false));
711
712 Orthanc::ImageProcessing::Convert(*image, *reader);
713 reader.reset();
714
715 float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
716
717 if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling))
718 {
719 float offset = static_cast<float>(stretchLow) / scaling;
720 Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
721 }
722
723 SuccessMessage message(*this, image.release());
724 emitter.EmitMessage(receiver, message);
588 } 725 }
589 }; 726 };
590 727
591 728
592 729
669 { 806 {
670 contentEncoding = Orthanc::HttpCompression_Gzip; 807 contentEncoding = Orthanc::HttpCompression_Gzip;
671 } 808 }
672 else 809 else
673 { 810 {
674 // TODO - Emit error message?
675 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, 811 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
676 "Unsupported HTTP Content-Encoding: " + it->second); 812 "Unsupported HTTP Content-Encoding: " + it->second);
677 } 813 }
678 814
679 break; 815 break;
757 { 893 {
758 std::auto_ptr<Orthanc::IDynamicObject> object(queue_.Dequeue(100)); 894 std::auto_ptr<Orthanc::IDynamicObject> object(queue_.Dequeue(100));
759 895
760 if (object.get() != NULL) 896 if (object.get() != NULL)
761 { 897 {
898 printf("===========================> REQUEST\n");
899
762 const Item& item = dynamic_cast<Item&>(*object); 900 const Item& item = dynamic_cast<Item&>(*object);
763 901
764 try 902 try
765 { 903 {
766 switch (item.GetCommand().GetType()) 904 switch (item.GetCommand().GetType())
1461 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message) 1599 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message)
1462 { 1600 {
1463 printf("IMAGE %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight()); 1601 printf("IMAGE %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
1464 } 1602 }
1465 1603
1604 void Handle(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
1605 {
1606 printf("WebViewer %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
1607 }
1608
1466 void Handle(const Refactoring::OracleCommandExceptionMessage& message) 1609 void Handle(const Refactoring::OracleCommandExceptionMessage& message)
1467 { 1610 {
1468 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType()); 1611 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType());
1469 1612
1470 switch (message.GetCommand().GetType()) 1613 switch (message.GetCommand().GetType())
1491 (new OrthancStone::Callable 1634 (new OrthancStone::Callable
1492 <Toto, Refactoring::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle)); 1635 <Toto, Refactoring::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle));
1493 1636
1494 oracle.RegisterObserverCallback 1637 oracle.RegisterObserverCallback
1495 (new OrthancStone::Callable 1638 (new OrthancStone::Callable
1639 <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle));
1640
1641 oracle.RegisterObserverCallback
1642 (new OrthancStone::Callable
1496 <Toto, Refactoring::OracleCommandExceptionMessage>(*this, &Toto::Handle)); 1643 <Toto, Refactoring::OracleCommandExceptionMessage>(*this, &Toto::Handle));
1497 } 1644 }
1498 }; 1645 };
1499 1646
1500 1647
1519 oracle.SetOrthancParameters(p); 1666 oracle.SetOrthancParameters(p);
1520 } 1667 }
1521 1668
1522 oracle.Start(); 1669 oracle.Start();
1523 1670
1524 if (0) 1671 if (1)
1525 { 1672 {
1526 Json::Value v = Json::objectValue; 1673 Json::Value v = Json::objectValue;
1527 v["Level"] = "Series"; 1674 v["Level"] = "Series";
1528 v["Query"] = Json::objectValue; 1675 v["Query"] = Json::objectValue;
1529 1676
1533 command->SetBody(v); 1680 command->SetBody(v);
1534 1681
1535 oracle.Schedule(*toto, command.release()); 1682 oracle.Schedule(*toto, command.release());
1536 } 1683 }
1537 1684
1538 if (0) 1685 if (1)
1539 { 1686 {
1540 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand); 1687 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1541 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg))); 1688 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg)));
1542 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview"); 1689 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
1543 oracle.Schedule(*toto, command.release()); 1690 oracle.Schedule(*toto, command.release());
1544 } 1691 }
1545 1692
1546 if (0) 1693 if (1)
1547 { 1694 {
1548 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand); 1695 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(new Refactoring::GetOrthancImageCommand);
1549 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png))); 1696 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
1550 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview"); 1697 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
1551 oracle.Schedule(*toto, command.release()); 1698 oracle.Schedule(*toto, command.release());
1588 1735
1589 // 2017-11-17-Anonymized 1736 // 2017-11-17-Anonymized
1590 loader1->LoadSeries(oracle, "cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT 1737 loader1->LoadSeries(oracle, "cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
1591 loader2->LoadInstance(oracle, "41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE 1738 loader2->LoadInstance(oracle, "41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
1592 1739
1593 boost::this_thread::sleep(boost::posix_time::seconds(1)); 1740 LOG(WARNING) << "...Waiting for Ctrl-C...";
1741 Orthanc::SystemToolbox::ServerBarrier();
1742 //boost::this_thread::sleep(boost::posix_time::seconds(1));
1594 1743
1595 oracle.Stop(); 1744 oracle.Stop();
1596 } 1745 }
1597 1746
1598 1747