Mercurial > hg > orthanc
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 } |