comparison Plugins/Engine/OrthancPlugins.cpp @ 3956:6e14f2da7c7e

integration transcoding->mainline
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 20 May 2020 16:42:44 +0200
parents 5fe8c6d3212e
children 821715370890
comparison
equal deleted inserted replaced
3892:fe0e4ef52a72 3956:6e14f2da7c7e
60 #include "../../Core/Logging.h" 60 #include "../../Core/Logging.h"
61 #include "../../Core/MetricsRegistry.h" 61 #include "../../Core/MetricsRegistry.h"
62 #include "../../Core/OrthancException.h" 62 #include "../../Core/OrthancException.h"
63 #include "../../Core/SerializationToolbox.h" 63 #include "../../Core/SerializationToolbox.h"
64 #include "../../Core/Toolbox.h" 64 #include "../../Core/Toolbox.h"
65 #include "../../OrthancServer/DefaultDicomImageDecoder.h"
66 #include "../../OrthancServer/OrthancConfiguration.h" 65 #include "../../OrthancServer/OrthancConfiguration.h"
67 #include "../../OrthancServer/OrthancFindRequestHandler.h" 66 #include "../../OrthancServer/OrthancFindRequestHandler.h"
68 #include "../../OrthancServer/Search/HierarchicalMatcher.h" 67 #include "../../OrthancServer/Search/HierarchicalMatcher.h"
69 #include "../../OrthancServer/ServerContext.h" 68 #include "../../OrthancServer/ServerContext.h"
70 #include "../../OrthancServer/ServerToolbox.h" 69 #include "../../OrthancServer/ServerToolbox.h"
71 #include "PluginsEnumerations.h" 70 #include "PluginsEnumerations.h"
72 #include "PluginsJob.h" 71 #include "PluginsJob.h"
73 72
74 #include <boost/regex.hpp> 73 #include <boost/regex.hpp>
75 #include <dcmtk/dcmdata/dcdict.h> 74 #include <dcmtk/dcmdata/dcdict.h>
76 #include <dcmtk/dcmdata/dcdicent.h> 75 #include <dcmtk/dcmdata/dcdicent.h>
77 76
78 #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc API is necessary" 77 #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc API is necessary"
78
79 79
80 namespace Orthanc 80 namespace Orthanc
81 { 81 {
82 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, 82 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target,
83 const void* data, 83 const void* data,
328 328
329 329
330 class DicomWebBinaryFormatter : public DicomWebJsonVisitor::IBinaryFormatter 330 class DicomWebBinaryFormatter : public DicomWebJsonVisitor::IBinaryFormatter
331 { 331 {
332 private: 332 private:
333 OrthancPluginDicomWebBinaryCallback callback_; 333 OrthancPluginDicomWebBinaryCallback oldCallback_;
334 DicomWebJsonVisitor::BinaryMode currentMode_; 334 OrthancPluginDicomWebBinaryCallback2 newCallback_; // New in Orthanc 1.7.0
335 std::string currentBulkDataUri_; 335 void* newPayload_; // New in Orthanc 1.7.0
336 DicomWebJsonVisitor::BinaryMode currentMode_;
337 std::string currentBulkDataUri_;
336 338
337 static void Setter(OrthancPluginDicomWebNode* node, 339 static void Setter(OrthancPluginDicomWebNode* node,
338 OrthancPluginDicomWebBinaryMode mode, 340 OrthancPluginDicomWebBinaryMode mode,
339 const char* bulkDataUri) 341 const char* bulkDataUri)
340 { 342 {
364 throw OrthancException(ErrorCode_ParameterOutOfRange); 366 throw OrthancException(ErrorCode_ParameterOutOfRange);
365 } 367 }
366 } 368 }
367 369
368 public: 370 public:
369 DicomWebBinaryFormatter(const _OrthancPluginEncodeDicomWeb& parameters) : 371 DicomWebBinaryFormatter(OrthancPluginDicomWebBinaryCallback callback) :
370 callback_(parameters.callback) 372 oldCallback_(callback),
373 newCallback_(NULL),
374 newPayload_(NULL)
375 {
376 }
377
378 DicomWebBinaryFormatter(OrthancPluginDicomWebBinaryCallback2 callback,
379 void* payload) :
380 oldCallback_(NULL),
381 newCallback_(callback),
382 newPayload_(payload)
371 { 383 {
372 } 384 }
373 385
374 virtual DicomWebJsonVisitor::BinaryMode Format(std::string& bulkDataUri, 386 virtual DicomWebJsonVisitor::BinaryMode Format(std::string& bulkDataUri,
375 const std::vector<DicomTag>& parentTags, 387 const std::vector<DicomTag>& parentTags,
376 const std::vector<size_t>& parentIndexes, 388 const std::vector<size_t>& parentIndexes,
377 const DicomTag& tag, 389 const DicomTag& tag,
378 ValueRepresentation vr) 390 ValueRepresentation vr)
379 { 391 {
380 if (callback_ == NULL) 392 if (oldCallback_ == NULL &&
393 newCallback_ == NULL)
381 { 394 {
382 return DicomWebJsonVisitor::BinaryMode_InlineBinary; 395 return DicomWebJsonVisitor::BinaryMode_InlineBinary;
383 } 396 }
384 else 397 else
385 { 398 {
396 } 409 }
397 bool empty = parentTags.empty(); 410 bool empty = parentTags.empty();
398 411
399 currentMode_ = DicomWebJsonVisitor::BinaryMode_Ignore; 412 currentMode_ = DicomWebJsonVisitor::BinaryMode_Ignore;
400 413
401 callback_(reinterpret_cast<OrthancPluginDicomWebNode*>(this), 414 if (oldCallback_ != NULL)
402 DicomWebBinaryFormatter::Setter, 415 {
403 static_cast<uint32_t>(parentTags.size()), 416 oldCallback_(reinterpret_cast<OrthancPluginDicomWebNode*>(this),
404 (empty ? NULL : &groups[0]), 417 DicomWebBinaryFormatter::Setter,
405 (empty ? NULL : &elements[0]), 418 static_cast<uint32_t>(parentTags.size()),
406 (empty ? NULL : &indexes[0]), 419 (empty ? NULL : &groups[0]),
407 tag.GetGroup(), 420 (empty ? NULL : &elements[0]),
408 tag.GetElement(), 421 (empty ? NULL : &indexes[0]),
409 Plugins::Convert(vr)); 422 tag.GetGroup(),
423 tag.GetElement(),
424 Plugins::Convert(vr));
425 }
426 else
427 {
428 assert(newCallback_ != NULL);
429 newCallback_(reinterpret_cast<OrthancPluginDicomWebNode*>(this),
430 DicomWebBinaryFormatter::Setter,
431 static_cast<uint32_t>(parentTags.size()),
432 (empty ? NULL : &groups[0]),
433 (empty ? NULL : &elements[0]),
434 (empty ? NULL : &indexes[0]),
435 tag.GetGroup(),
436 tag.GetElement(),
437 Plugins::Convert(vr),
438 newPayload_);
439 }
410 440
411 bulkDataUri = currentBulkDataUri_; 441 bulkDataUri = currentBulkDataUri_;
412 return currentMode_; 442 return currentMode_;
413 } 443 }
444 }
445
446 void Apply(char** target,
447 bool isJson,
448 ParsedDicomFile& dicom)
449 {
450 DicomWebJsonVisitor visitor;
451 visitor.SetFormatter(*this);
452
453 dicom.Apply(visitor);
454
455 std::string s;
456
457 if (isJson)
458 {
459 s = visitor.GetResult().toStyledString();
460 }
461 else
462 {
463 visitor.FormatXml(s);
464 }
465
466 *target = CopyString(s);
467 }
468
469
470 void Apply(char** target,
471 bool isJson,
472 const void* dicom,
473 size_t dicomSize)
474 {
475 ParsedDicomFile parsed(dicom, dicomSize);
476 Apply(target, isJson, parsed);
414 } 477 }
415 }; 478 };
416 } 479 }
417 480
418 481
825 typedef std::list<OrthancPluginOnChangeCallback> OnChangeCallbacks; 888 typedef std::list<OrthancPluginOnChangeCallback> OnChangeCallbacks;
826 typedef std::list<OrthancPluginIncomingHttpRequestFilter> IncomingHttpRequestFilters; 889 typedef std::list<OrthancPluginIncomingHttpRequestFilter> IncomingHttpRequestFilters;
827 typedef std::list<OrthancPluginIncomingHttpRequestFilter2> IncomingHttpRequestFilters2; 890 typedef std::list<OrthancPluginIncomingHttpRequestFilter2> IncomingHttpRequestFilters2;
828 typedef std::list<OrthancPluginIncomingDicomInstanceFilter> IncomingDicomInstanceFilters; 891 typedef std::list<OrthancPluginIncomingDicomInstanceFilter> IncomingDicomInstanceFilters;
829 typedef std::list<OrthancPluginDecodeImageCallback> DecodeImageCallbacks; 892 typedef std::list<OrthancPluginDecodeImageCallback> DecodeImageCallbacks;
893 typedef std::list<OrthancPluginTranscoderCallback> TranscoderCallbacks;
830 typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers; 894 typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers;
831 typedef std::list<OrthancPluginRefreshMetricsCallback> RefreshMetricsCallbacks; 895 typedef std::list<OrthancPluginRefreshMetricsCallback> RefreshMetricsCallbacks;
832 typedef std::list<StorageCommitmentScp*> StorageCommitmentScpCallbacks; 896 typedef std::list<StorageCommitmentScp*> StorageCommitmentScpCallbacks;
833 typedef std::map<Property, std::string> Properties; 897 typedef std::map<Property, std::string> Properties;
834 898
839 OnStoredCallbacks onStoredCallbacks_; 903 OnStoredCallbacks onStoredCallbacks_;
840 OnChangeCallbacks onChangeCallbacks_; 904 OnChangeCallbacks onChangeCallbacks_;
841 OrthancPluginFindCallback findCallback_; 905 OrthancPluginFindCallback findCallback_;
842 OrthancPluginWorklistCallback worklistCallback_; 906 OrthancPluginWorklistCallback worklistCallback_;
843 DecodeImageCallbacks decodeImageCallbacks_; 907 DecodeImageCallbacks decodeImageCallbacks_;
908 TranscoderCallbacks transcoderCallbacks_;
844 JobsUnserializers jobsUnserializers_; 909 JobsUnserializers jobsUnserializers_;
845 _OrthancPluginMoveCallback moveCallbacks_; 910 _OrthancPluginMoveCallback moveCallbacks_;
846 IncomingHttpRequestFilters incomingHttpRequestFilters_; 911 IncomingHttpRequestFilters incomingHttpRequestFilters_;
847 IncomingHttpRequestFilters2 incomingHttpRequestFilters2_; 912 IncomingHttpRequestFilters2 incomingHttpRequestFilters2_;
848 IncomingDicomInstanceFilters incomingDicomInstanceFilters_; 913 IncomingDicomInstanceFilters incomingDicomInstanceFilters_;
853 boost::recursive_mutex restCallbackMutex_; 918 boost::recursive_mutex restCallbackMutex_;
854 boost::recursive_mutex storedCallbackMutex_; 919 boost::recursive_mutex storedCallbackMutex_;
855 boost::recursive_mutex changeCallbackMutex_; 920 boost::recursive_mutex changeCallbackMutex_;
856 boost::mutex findCallbackMutex_; 921 boost::mutex findCallbackMutex_;
857 boost::mutex worklistCallbackMutex_; 922 boost::mutex worklistCallbackMutex_;
858 boost::mutex decodeImageCallbackMutex_; 923 boost::shared_mutex decoderTranscoderMutex_; // Changed from "boost::mutex" in Orthanc 1.7.0
859 boost::mutex jobsUnserializersMutex_; 924 boost::mutex jobsUnserializersMutex_;
860 boost::mutex refreshMetricsMutex_; 925 boost::mutex refreshMetricsMutex_;
861 boost::mutex storageCommitmentScpMutex_; 926 boost::mutex storageCommitmentScpMutex_;
862 boost::recursive_mutex invokeServiceMutex_; 927 boost::recursive_mutex invokeServiceMutex_;
863 928
1759 pluginOutput.Close(error, GetErrorDictionary()); 1824 pluginOutput.Close(error, GetErrorDictionary());
1760 return true; 1825 return true;
1761 } 1826 }
1762 1827
1763 1828
1829 class OrthancPlugins::IDicomInstance : public boost::noncopyable
1830 {
1831 public:
1832 virtual ~IDicomInstance()
1833 {
1834 }
1835
1836 virtual bool CanBeFreed() const = 0;
1837
1838 virtual const DicomInstanceToStore& GetInstance() const = 0;
1839 };
1840
1841
1842 class OrthancPlugins::DicomInstanceFromCallback : public IDicomInstance
1843 {
1844 private:
1845 const DicomInstanceToStore& instance_;
1846
1847 public:
1848 DicomInstanceFromCallback(const DicomInstanceToStore& instance) :
1849 instance_(instance)
1850 {
1851 }
1852
1853 virtual bool CanBeFreed() const ORTHANC_OVERRIDE
1854 {
1855 return false;
1856 }
1857
1858 virtual const DicomInstanceToStore& GetInstance() const ORTHANC_OVERRIDE
1859 {
1860 return instance_;
1861 };
1862 };
1863
1864
1865 class OrthancPlugins::DicomInstanceFromBuffer : public IDicomInstance
1866 {
1867 private:
1868 std::string buffer_;
1869 DicomInstanceToStore instance_;
1870
1871 public:
1872 DicomInstanceFromBuffer(const void* buffer,
1873 size_t size)
1874 {
1875 buffer_.assign(reinterpret_cast<const char*>(buffer), size);
1876 instance_.SetBuffer(buffer_.empty() ? NULL : buffer_.c_str(), buffer_.size());
1877 instance_.SetOrigin(DicomInstanceOrigin::FromPlugins());
1878 }
1879
1880 virtual bool CanBeFreed() const ORTHANC_OVERRIDE
1881 {
1882 return true;
1883 }
1884
1885 virtual const DicomInstanceToStore& GetInstance() const ORTHANC_OVERRIDE
1886 {
1887 return instance_;
1888 };
1889 };
1890
1891
1892 class OrthancPlugins::DicomInstanceFromTranscoded : public IDicomInstance
1893 {
1894 private:
1895 std::unique_ptr<ParsedDicomFile> parsed_;
1896 DicomInstanceToStore instance_;
1897
1898 public:
1899 DicomInstanceFromTranscoded(IDicomTranscoder::DicomImage& transcoded) :
1900 parsed_(transcoded.ReleaseAsParsedDicomFile())
1901 {
1902 instance_.SetParsedDicomFile(*parsed_);
1903 instance_.SetOrigin(DicomInstanceOrigin::FromPlugins());
1904 }
1905
1906 virtual bool CanBeFreed() const ORTHANC_OVERRIDE
1907 {
1908 return true;
1909 }
1910
1911 virtual const DicomInstanceToStore& GetInstance() const ORTHANC_OVERRIDE
1912 {
1913 return instance_;
1914 };
1915 };
1916
1917
1764 void OrthancPlugins::SignalStoredInstance(const std::string& instanceId, 1918 void OrthancPlugins::SignalStoredInstance(const std::string& instanceId,
1765 DicomInstanceToStore& instance, 1919 const DicomInstanceToStore& instance,
1766 const Json::Value& simplifiedTags) 1920 const Json::Value& simplifiedTags)
1767 { 1921 {
1922 DicomInstanceFromCallback wrapped(instance);
1923
1768 boost::recursive_mutex::scoped_lock lock(pimpl_->storedCallbackMutex_); 1924 boost::recursive_mutex::scoped_lock lock(pimpl_->storedCallbackMutex_);
1769 1925
1770 for (PImpl::OnStoredCallbacks::const_iterator 1926 for (PImpl::OnStoredCallbacks::const_iterator
1771 callback = pimpl_->onStoredCallbacks_.begin(); 1927 callback = pimpl_->onStoredCallbacks_.begin();
1772 callback != pimpl_->onStoredCallbacks_.end(); ++callback) 1928 callback != pimpl_->onStoredCallbacks_.end(); ++callback)
1773 { 1929 {
1774 OrthancPluginErrorCode error = (*callback) 1930 OrthancPluginErrorCode error = (*callback) (
1775 (reinterpret_cast<OrthancPluginDicomInstance*>(&instance), 1931 reinterpret_cast<OrthancPluginDicomInstance*>(&wrapped),
1776 instanceId.c_str()); 1932 instanceId.c_str());
1777 1933
1778 if (error != OrthancPluginErrorCode_Success) 1934 if (error != OrthancPluginErrorCode_Success)
1779 { 1935 {
1780 GetErrorDictionary().LogError(error, true); 1936 GetErrorDictionary().LogError(error, true);
1781 throw OrthancException(static_cast<ErrorCode>(error)); 1937 throw OrthancException(static_cast<ErrorCode>(error));
1785 1941
1786 1942
1787 bool OrthancPlugins::FilterIncomingInstance(const DicomInstanceToStore& instance, 1943 bool OrthancPlugins::FilterIncomingInstance(const DicomInstanceToStore& instance,
1788 const Json::Value& simplified) 1944 const Json::Value& simplified)
1789 { 1945 {
1946 DicomInstanceFromCallback wrapped(instance);
1947
1790 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); 1948 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_);
1791 1949
1792 for (PImpl::IncomingDicomInstanceFilters::const_iterator 1950 for (PImpl::IncomingDicomInstanceFilters::const_iterator
1793 filter = pimpl_->incomingDicomInstanceFilters_.begin(); 1951 filter = pimpl_->incomingDicomInstanceFilters_.begin();
1794 filter != pimpl_->incomingDicomInstanceFilters_.end(); ++filter) 1952 filter != pimpl_->incomingDicomInstanceFilters_.end(); ++filter)
1795 { 1953 {
1796 int32_t allowed = (*filter) ( 1954 int32_t allowed = (*filter) (reinterpret_cast<const OrthancPluginDicomInstance*>(&wrapped));
1797 reinterpret_cast<const OrthancPluginDicomInstance*>(&instance));
1798 1955
1799 if (allowed == 0) 1956 if (allowed == 0)
1800 { 1957 {
1801 return false; 1958 return false;
1802 } 1959 }
1952 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) 2109 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters)
1953 { 2110 {
1954 const _OrthancPluginDecodeImageCallback& p = 2111 const _OrthancPluginDecodeImageCallback& p =
1955 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); 2112 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters);
1956 2113
1957 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); 2114 boost::unique_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
1958 2115
1959 pimpl_->decodeImageCallbacks_.push_back(p.callback); 2116 pimpl_->decodeImageCallbacks_.push_back(p.callback);
1960 LOG(INFO) << "Plugin has registered a callback to decode DICOM images (" 2117 LOG(INFO) << "Plugin has registered a callback to decode DICOM images ("
1961 << pimpl_->decodeImageCallbacks_.size() << " decoder(s) now active)"; 2118 << pimpl_->decodeImageCallbacks_.size() << " decoder(s) now active)";
2119 }
2120
2121
2122 void OrthancPlugins::RegisterTranscoderCallback(const void* parameters)
2123 {
2124 const _OrthancPluginTranscoderCallback& p =
2125 *reinterpret_cast<const _OrthancPluginTranscoderCallback*>(parameters);
2126
2127 boost::unique_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
2128
2129 pimpl_->transcoderCallbacks_.push_back(p.callback);
2130 LOG(INFO) << "Plugin has registered a callback to transcode DICOM images ("
2131 << pimpl_->transcoderCallbacks_.size() << " transcoder(s) now active)";
1962 } 2132 }
1963 2133
1964 2134
1965 void OrthancPlugins::RegisterJobsUnserializer(const void* parameters) 2135 void OrthancPlugins::RegisterJobsUnserializer(const void* parameters)
1966 { 2136 {
2449 } 2619 }
2450 } 2620 }
2451 } 2621 }
2452 2622
2453 2623
2454 static void AccessDicomInstance(_OrthancPluginService service, 2624 void OrthancPlugins::AccessDicomInstance(_OrthancPluginService service,
2455 const void* parameters) 2625 const void* parameters)
2456 { 2626 {
2457 const _OrthancPluginAccessDicomInstance& p = 2627 const _OrthancPluginAccessDicomInstance& p =
2458 *reinterpret_cast<const _OrthancPluginAccessDicomInstance*>(parameters); 2628 *reinterpret_cast<const _OrthancPluginAccessDicomInstance*>(parameters);
2459 2629
2630 if (p.instance == NULL)
2631 {
2632 throw OrthancException(ErrorCode_NullPointer);
2633 }
2634
2460 const DicomInstanceToStore& instance = 2635 const DicomInstanceToStore& instance =
2461 *reinterpret_cast<const DicomInstanceToStore*>(p.instance); 2636 reinterpret_cast<const IDicomInstance*>(p.instance)->GetInstance();
2462 2637
2463 switch (service) 2638 switch (service)
2464 { 2639 {
2465 case _OrthancPluginService_GetInstanceRemoteAet: 2640 case _OrthancPluginService_GetInstanceRemoteAet:
2466 *p.resultString = instance.GetOrigin().GetRemoteAetC(); 2641 *p.resultString = instance.GetOrigin().GetRemoteAetC();
2521 2696
2522 case _OrthancPluginService_HasInstancePixelData: // New in Orthanc 1.6.1 2697 case _OrthancPluginService_HasInstancePixelData: // New in Orthanc 1.6.1
2523 *p.resultInt64 = instance.HasPixelData(); 2698 *p.resultInt64 = instance.HasPixelData();
2524 return; 2699 return;
2525 2700
2701 case _OrthancPluginService_GetInstanceFramesCount: // New in Orthanc 1.7.0
2702 *p.resultInt64 = instance.GetParsedDicomFile().GetFramesCount();
2703 return;
2704
2526 default: 2705 default:
2527 throw OrthancException(ErrorCode_InternalError); 2706 throw OrthancException(ErrorCode_InternalError);
2528 } 2707 }
2529 } 2708 }
2530 2709
2590 static OrthancPluginImage* ReturnImage(std::unique_ptr<ImageAccessor>& image) 2769 static OrthancPluginImage* ReturnImage(std::unique_ptr<ImageAccessor>& image)
2591 { 2770 {
2592 // Images returned to plugins are assumed to be writeable. If the 2771 // Images returned to plugins are assumed to be writeable. If the
2593 // input image is read-only, we return a copy so that it can be modified. 2772 // input image is read-only, we return a copy so that it can be modified.
2594 2773
2774 if (image.get() == NULL)
2775 {
2776 throw OrthancException(ErrorCode_NullPointer);
2777 }
2778
2595 if (image->IsReadOnly()) 2779 if (image->IsReadOnly())
2596 { 2780 {
2597 std::unique_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight(), false)); 2781 std::unique_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight(), false));
2598 ImageProcessing::Copy(*copy, *image); 2782 ImageProcessing::Copy(*copy, *image);
2599 image.reset(NULL); 2783 image.reset(NULL);
2600 return reinterpret_cast<OrthancPluginImage*>(copy.release()); 2784 return reinterpret_cast<OrthancPluginImage*>(copy.release());
2601 } 2785 }
2602 else 2786 else
2603 { 2787 {
2604 return reinterpret_cast<OrthancPluginImage*>(image.release()); 2788 return reinterpret_cast<OrthancPluginImage*>(image.release());
2789 }
2790 }
2791
2792
2793 void OrthancPlugins::AccessDicomInstance2(_OrthancPluginService service,
2794 const void* parameters)
2795 {
2796 const _OrthancPluginAccessDicomInstance2& p =
2797 *reinterpret_cast<const _OrthancPluginAccessDicomInstance2*>(parameters);
2798
2799 if (p.instance == NULL)
2800 {
2801 throw OrthancException(ErrorCode_NullPointer);
2802 }
2803
2804 const DicomInstanceToStore& instance =
2805 reinterpret_cast<const IDicomInstance*>(p.instance)->GetInstance();
2806
2807 switch (service)
2808 {
2809 case _OrthancPluginService_GetInstanceFramesCount:
2810 *p.targetUint32 = instance.GetParsedDicomFile().GetFramesCount();
2811 return;
2812
2813 case _OrthancPluginService_GetInstanceRawFrame:
2814 {
2815 if (p.targetBuffer == NULL)
2816 {
2817 throw OrthancException(ErrorCode_NullPointer);
2818 }
2819
2820 p.targetBuffer->data = NULL;
2821 p.targetBuffer->size = 0;
2822
2823 MimeType mime;
2824 std::string frame;
2825 instance.GetParsedDicomFile().GetRawFrame(frame, mime, p.frameIndex);
2826 CopyToMemoryBuffer(*p.targetBuffer, frame);
2827 return;
2828 }
2829
2830 case _OrthancPluginService_GetInstanceDecodedFrame:
2831 {
2832 if (p.targetImage == NULL)
2833 {
2834 throw OrthancException(ErrorCode_NullPointer);
2835 }
2836
2837 std::unique_ptr<ImageAccessor> decoded;
2838 {
2839 PImpl::ServerContextLock lock(*pimpl_);
2840 decoded.reset(lock.GetContext().DecodeDicomFrame(instance, p.frameIndex));
2841 }
2842
2843 *(p.targetImage) = ReturnImage(decoded);
2844 return;
2845 }
2846
2847 case _OrthancPluginService_SerializeDicomInstance:
2848 {
2849 if (p.targetBuffer == NULL)
2850 {
2851 throw OrthancException(ErrorCode_NullPointer);
2852 }
2853
2854 p.targetBuffer->data = NULL;
2855 p.targetBuffer->size = 0;
2856
2857 std::string serialized;
2858 instance.GetParsedDicomFile().SaveToMemoryBuffer(serialized);
2859 CopyToMemoryBuffer(*p.targetBuffer, serialized);
2860 return;
2861 }
2862
2863 case _OrthancPluginService_GetInstanceAdvancedJson:
2864 {
2865 if (p.targetStringToFree == NULL)
2866 {
2867 throw OrthancException(ErrorCode_NullPointer);
2868 }
2869
2870 Json::Value json;
2871 instance.GetParsedDicomFile().DatasetToJson(
2872 json, Plugins::Convert(p.format),
2873 static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength);
2874
2875 Json::FastWriter writer;
2876 *p.targetStringToFree = CopyString(writer.write(json));
2877 return;
2878 }
2879
2880 case _OrthancPluginService_GetInstanceDicomWebJson:
2881 case _OrthancPluginService_GetInstanceDicomWebXml:
2882 {
2883 if (p.targetStringToFree == NULL)
2884 {
2885 throw OrthancException(ErrorCode_NullPointer);
2886 }
2887
2888 DicomWebBinaryFormatter formatter(p.dicomWebCallback, p.dicomWebPayload);
2889 formatter.Apply(p.targetStringToFree,
2890 (service == _OrthancPluginService_GetInstanceDicomWebJson),
2891 instance.GetParsedDicomFile());
2892 return;
2893 }
2894
2895 default:
2896 throw OrthancException(ErrorCode_InternalError);
2605 } 2897 }
2606 } 2898 }
2607 2899
2608 2900
2609 void OrthancPlugins::UncompressImage(const void* parameters) 2901 void OrthancPlugins::UncompressImage(const void* parameters)
3479 case _OrthancPluginService_GetInstanceTransferSyntaxUid: 3771 case _OrthancPluginService_GetInstanceTransferSyntaxUid:
3480 case _OrthancPluginService_HasInstancePixelData: 3772 case _OrthancPluginService_HasInstancePixelData:
3481 AccessDicomInstance(service, parameters); 3773 AccessDicomInstance(service, parameters);
3482 return true; 3774 return true;
3483 3775
3776 case _OrthancPluginService_GetInstanceFramesCount:
3777 case _OrthancPluginService_GetInstanceRawFrame:
3778 case _OrthancPluginService_GetInstanceDecodedFrame:
3779 case _OrthancPluginService_SerializeDicomInstance:
3780 case _OrthancPluginService_GetInstanceAdvancedJson:
3781 case _OrthancPluginService_GetInstanceDicomWebJson:
3782 case _OrthancPluginService_GetInstanceDicomWebXml:
3783 AccessDicomInstance2(service, parameters);
3784 return true;
3785
3484 case _OrthancPluginService_SetGlobalProperty: 3786 case _OrthancPluginService_SetGlobalProperty:
3485 { 3787 {
3486 const _OrthancPluginGlobalProperty& p = 3788 const _OrthancPluginGlobalProperty& p =
3487 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); 3789 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters);
3488 if (p.property < 1024) 3790 if (p.property < 1024)
3996 case _OrthancPluginService_EncodeDicomWebXml: 4298 case _OrthancPluginService_EncodeDicomWebXml:
3997 { 4299 {
3998 const _OrthancPluginEncodeDicomWeb& p = 4300 const _OrthancPluginEncodeDicomWeb& p =
3999 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb*>(parameters); 4301 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb*>(parameters);
4000 4302
4001 DicomWebBinaryFormatter formatter(p); 4303 DicomWebBinaryFormatter formatter(p.callback);
4002 4304 formatter.Apply(p.target,
4003 DicomWebJsonVisitor visitor; 4305 (service == _OrthancPluginService_EncodeDicomWebJson),
4004 visitor.SetFormatter(formatter); 4306 p.dicom, p.dicomSize);
4005 4307 return true;
4006 { 4308 }
4007 ParsedDicomFile dicom(p.dicom, p.dicomSize); 4309
4008 dicom.Apply(visitor); 4310 case _OrthancPluginService_EncodeDicomWebJson2:
4009 } 4311 case _OrthancPluginService_EncodeDicomWebXml2:
4010 4312 {
4011 std::string s; 4313 const _OrthancPluginEncodeDicomWeb2& p =
4012 4314 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb2*>(parameters);
4013 if (service == _OrthancPluginService_EncodeDicomWebJson) 4315
4014 { 4316 DicomWebBinaryFormatter formatter(p.callback, p.payload);
4015 s = visitor.GetResult().toStyledString(); 4317 formatter.Apply(p.target,
4016 } 4318 (service == _OrthancPluginService_EncodeDicomWebJson2),
4017 else 4319 p.dicom, p.dicomSize);
4018 {
4019 visitor.FormatXml(s);
4020 }
4021
4022 *p.target = CopyString(s);
4023 return true; 4320 return true;
4024 } 4321 }
4025 4322
4026 case _OrthancPluginService_GetTagName: 4323 case _OrthancPluginService_GetTagName:
4027 GetTagName(parameters); 4324 GetTagName(parameters);
4028 return true; 4325 return true;
4029 4326
4327 case _OrthancPluginService_CreateDicomInstance:
4328 {
4329 const _OrthancPluginCreateDicomInstance& p =
4330 *reinterpret_cast<const _OrthancPluginCreateDicomInstance*>(parameters);
4331 *(p.target) = reinterpret_cast<OrthancPluginDicomInstance*>(
4332 new DicomInstanceFromBuffer(p.buffer, p.size));
4333 return true;
4334 }
4335
4336 case _OrthancPluginService_FreeDicomInstance:
4337 {
4338 const _OrthancPluginFreeDicomInstance& p =
4339 *reinterpret_cast<const _OrthancPluginFreeDicomInstance*>(parameters);
4340
4341 if (p.dicom != NULL)
4342 {
4343 IDicomInstance* obj = reinterpret_cast<IDicomInstance*>(p.dicom);
4344
4345 if (obj->CanBeFreed())
4346 {
4347 delete obj;
4348 }
4349 else
4350 {
4351 throw OrthancException(ErrorCode_Plugin, "Cannot free a DICOM instance provided to a callback");
4352 }
4353 }
4354
4355 return true;
4356 }
4357
4358 case _OrthancPluginService_TranscodeDicomInstance:
4359 {
4360 const _OrthancPluginCreateDicomInstance& p =
4361 *reinterpret_cast<const _OrthancPluginCreateDicomInstance*>(parameters);
4362
4363 DicomTransferSyntax transferSyntax;
4364 if (p.transferSyntax == NULL ||
4365 !LookupTransferSyntax(transferSyntax, p.transferSyntax))
4366 {
4367 throw OrthancException(ErrorCode_ParameterOutOfRange, "Unsupported transfer syntax: " +
4368 std::string(p.transferSyntax == NULL ? "(null)" : p.transferSyntax));
4369 }
4370 else
4371 {
4372 std::set<DicomTransferSyntax> syntaxes;
4373 syntaxes.insert(transferSyntax);
4374
4375 IDicomTranscoder::DicomImage source;
4376 source.SetExternalBuffer(p.buffer, p.size);
4377
4378 IDicomTranscoder::DicomImage transcoded;
4379 bool success;
4380
4381 {
4382 PImpl::ServerContextLock lock(*pimpl_);
4383 success = lock.GetContext().Transcode(
4384 transcoded, source, syntaxes, true /* allow new sop */);
4385 }
4386
4387 if (success)
4388 {
4389 *(p.target) = reinterpret_cast<OrthancPluginDicomInstance*>(
4390 new DicomInstanceFromTranscoded(transcoded));
4391 return true;
4392 }
4393 else
4394 {
4395 throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode image");
4396 }
4397 }
4398 }
4399
4400 case _OrthancPluginService_CreateMemoryBuffer:
4401 {
4402 const _OrthancPluginCreateMemoryBuffer& p =
4403 *reinterpret_cast<const _OrthancPluginCreateMemoryBuffer*>(parameters);
4404
4405 p.target->size = p.size;
4406
4407 if (p.size == 0)
4408 {
4409 p.target->data = NULL;
4410 }
4411 else
4412 {
4413 p.target->data = malloc(p.size);
4414 }
4415
4416 return true;
4417 }
4418
4030 default: 4419 default:
4031 return false; 4420 return false;
4032 } 4421 }
4033 } 4422 }
4034 4423
4076 RegisterMoveCallback(parameters); 4465 RegisterMoveCallback(parameters);
4077 return true; 4466 return true;
4078 4467
4079 case _OrthancPluginService_RegisterDecodeImageCallback: 4468 case _OrthancPluginService_RegisterDecodeImageCallback:
4080 RegisterDecodeImageCallback(parameters); 4469 RegisterDecodeImageCallback(parameters);
4470 return true;
4471
4472 case _OrthancPluginService_RegisterTranscoderCallback:
4473 RegisterTranscoderCallback(parameters);
4081 return true; 4474 return true;
4082 4475
4083 case _OrthancPluginService_RegisterJobsUnserializer: 4476 case _OrthancPluginService_RegisterJobsUnserializer:
4084 RegisterJobsUnserializer(parameters); 4477 RegisterJobsUnserializer(parameters);
4085 return true; 4478 return true;
4462 } 4855 }
4463 4856
4464 4857
4465 bool OrthancPlugins::HasCustomImageDecoder() 4858 bool OrthancPlugins::HasCustomImageDecoder()
4466 { 4859 {
4467 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); 4860 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
4468 return !pimpl_->decodeImageCallbacks_.empty(); 4861 return !pimpl_->decodeImageCallbacks_.empty();
4469 } 4862 }
4470 4863
4471 4864
4472 ImageAccessor* OrthancPlugins::DecodeUnsafe(const void* dicom, 4865 bool OrthancPlugins::HasCustomTranscoder()
4473 size_t size, 4866 {
4474 unsigned int frame) 4867 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
4475 { 4868 return !pimpl_->transcoderCallbacks_.empty();
4476 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); 4869 }
4870
4871
4872 ImageAccessor* OrthancPlugins::Decode(const void* dicom,
4873 size_t size,
4874 unsigned int frame)
4875 {
4876 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
4477 4877
4478 for (PImpl::DecodeImageCallbacks::const_iterator 4878 for (PImpl::DecodeImageCallbacks::const_iterator
4479 decoder = pimpl_->decodeImageCallbacks_.begin(); 4879 decoder = pimpl_->decodeImageCallbacks_.begin();
4480 decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder) 4880 decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder)
4481 { 4881 {
4486 return reinterpret_cast<ImageAccessor*>(pluginImage); 4886 return reinterpret_cast<ImageAccessor*>(pluginImage);
4487 } 4887 }
4488 } 4888 }
4489 4889
4490 return NULL; 4890 return NULL;
4491 }
4492
4493
4494 ImageAccessor* OrthancPlugins::Decode(const void* dicom,
4495 size_t size,
4496 unsigned int frame)
4497 {
4498 ImageAccessor* result = DecodeUnsafe(dicom, size, frame);
4499
4500 if (result != NULL)
4501 {
4502 return result;
4503 }
4504 else
4505 {
4506 LOG(INFO) << "The installed image decoding plugins cannot handle an image, fallback to the built-in decoder";
4507 DefaultDicomImageDecoder defaultDecoder;
4508 return defaultDecoder.Decode(dicom, size, frame);
4509 }
4510 } 4891 }
4511 4892
4512 4893
4513 bool OrthancPlugins::IsAllowed(HttpMethod method, 4894 bool OrthancPlugins::IsAllowed(HttpMethod method,
4514 const char* uri, 4895 const char* uri,
4791 } 5172 }
4792 } 5173 }
4793 5174
4794 return NULL; 5175 return NULL;
4795 } 5176 }
5177
5178
5179 class MemoryBufferRaii : public boost::noncopyable
5180 {
5181 private:
5182 OrthancPluginMemoryBuffer buffer_;
5183
5184 public:
5185 MemoryBufferRaii()
5186 {
5187 buffer_.size = 0;
5188 buffer_.data = NULL;
5189 }
5190
5191 ~MemoryBufferRaii()
5192 {
5193 if (buffer_.size != 0)
5194 {
5195 free(buffer_.data);
5196 }
5197 }
5198
5199 OrthancPluginMemoryBuffer* GetObject()
5200 {
5201 return &buffer_;
5202 }
5203
5204 void ToString(std::string& target) const
5205 {
5206 target.resize(buffer_.size);
5207
5208 if (buffer_.size != 0)
5209 {
5210 memcpy(&target[0], buffer_.data, buffer_.size);
5211 }
5212 }
5213 };
5214
5215
5216 bool OrthancPlugins::TranscodeBuffer(std::string& target,
5217 const void* buffer,
5218 size_t size,
5219 const std::set<DicomTransferSyntax>& allowedSyntaxes,
5220 bool allowNewSopInstanceUid)
5221 {
5222 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
5223
5224 if (pimpl_->transcoderCallbacks_.empty())
5225 {
5226 return NULL;
5227 }
5228
5229 std::vector<const char*> uids;
5230 uids.reserve(allowedSyntaxes.size());
5231 for (std::set<DicomTransferSyntax>::const_iterator
5232 it = allowedSyntaxes.begin(); it != allowedSyntaxes.end(); ++it)
5233 {
5234 uids.push_back(GetTransferSyntaxUid(*it));
5235 }
5236
5237 for (PImpl::TranscoderCallbacks::const_iterator
5238 transcoder = pimpl_->transcoderCallbacks_.begin();
5239 transcoder != pimpl_->transcoderCallbacks_.end(); ++transcoder)
5240 {
5241 MemoryBufferRaii a;
5242
5243 if ((*transcoder) (a.GetObject(), buffer, size, uids.empty() ? NULL : &uids[0],
5244 static_cast<uint32_t>(uids.size()), allowNewSopInstanceUid) ==
5245 OrthancPluginErrorCode_Success)
5246 {
5247 a.ToString(target);
5248 return true;
5249 }
5250 }
5251
5252 return false;
5253 }
4796 } 5254 }