comparison Plugins/Engine/OrthancPlugins.cpp @ 3958:596912ebab5f c-get

integration mainline->c-get
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 20 May 2020 17:03:24 +0200
parents 5fe8c6d3212e
children 821715370890
comparison
equal deleted inserted replaced
3955:66879215cbf3 3958:596912ebab5f
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
1829 private: 1894 private:
1830 std::unique_ptr<ParsedDicomFile> parsed_; 1895 std::unique_ptr<ParsedDicomFile> parsed_;
1831 DicomInstanceToStore instance_; 1896 DicomInstanceToStore instance_;
1832 1897
1833 public: 1898 public:
1834 DicomInstanceFromTranscoded(IDicomTranscoder::TranscodedDicom& transcoded) : 1899 DicomInstanceFromTranscoded(IDicomTranscoder::DicomImage& transcoded) :
1835 parsed_(ParsedDicomFile::AcquireDcmtkObject(transcoded.ReleaseDicom())) 1900 parsed_(transcoded.ReleaseAsParsedDicomFile())
1836 { 1901 {
1837 instance_.SetParsedDicomFile(*parsed_); 1902 instance_.SetParsedDicomFile(*parsed_);
1838 instance_.SetOrigin(DicomInstanceOrigin::FromPlugins()); 1903 instance_.SetOrigin(DicomInstanceOrigin::FromPlugins());
1839 } 1904 }
1840 1905
2044 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) 2109 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters)
2045 { 2110 {
2046 const _OrthancPluginDecodeImageCallback& p = 2111 const _OrthancPluginDecodeImageCallback& p =
2047 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); 2112 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters);
2048 2113
2049 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); 2114 boost::unique_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
2050 2115
2051 pimpl_->decodeImageCallbacks_.push_back(p.callback); 2116 pimpl_->decodeImageCallbacks_.push_back(p.callback);
2052 LOG(INFO) << "Plugin has registered a callback to decode DICOM images (" 2117 LOG(INFO) << "Plugin has registered a callback to decode DICOM images ("
2053 << 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)";
2054 } 2132 }
2055 2133
2056 2134
2057 void OrthancPlugins::RegisterJobsUnserializer(const void* parameters) 2135 void OrthancPlugins::RegisterJobsUnserializer(const void* parameters)
2058 { 2136 {
2691 static OrthancPluginImage* ReturnImage(std::unique_ptr<ImageAccessor>& image) 2769 static OrthancPluginImage* ReturnImage(std::unique_ptr<ImageAccessor>& image)
2692 { 2770 {
2693 // Images returned to plugins are assumed to be writeable. If the 2771 // Images returned to plugins are assumed to be writeable. If the
2694 // 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.
2695 2773
2774 if (image.get() == NULL)
2775 {
2776 throw OrthancException(ErrorCode_NullPointer);
2777 }
2778
2696 if (image->IsReadOnly()) 2779 if (image->IsReadOnly())
2697 { 2780 {
2698 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));
2699 ImageProcessing::Copy(*copy, *image); 2782 ImageProcessing::Copy(*copy, *image);
2700 image.reset(NULL); 2783 image.reset(NULL);
2744 return; 2827 return;
2745 } 2828 }
2746 2829
2747 case _OrthancPluginService_GetInstanceDecodedFrame: 2830 case _OrthancPluginService_GetInstanceDecodedFrame:
2748 { 2831 {
2749 bool hasDecoderPlugin; 2832 if (p.targetImage == NULL)
2750 2833 {
2751 { 2834 throw OrthancException(ErrorCode_NullPointer);
2752 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
2753 hasDecoderPlugin = !pimpl_->decodeImageCallbacks_.empty();
2754 } 2835 }
2755 2836
2756 std::unique_ptr<ImageAccessor> decoded; 2837 std::unique_ptr<ImageAccessor> decoded;
2757 if (p.targetImage == NULL) 2838 {
2758 { 2839 PImpl::ServerContextLock lock(*pimpl_);
2759 throw OrthancException(ErrorCode_NullPointer); 2840 decoded.reset(lock.GetContext().DecodeDicomFrame(instance, p.frameIndex));
2760 } 2841 }
2761 else if (hasDecoderPlugin) 2842
2762 {
2763 // TODO - This call could be speeded up the future, if a
2764 // "decoding context" gets introduced in the decoder plugins
2765
2766 decoded.reset(Decode(instance.GetBufferData(), instance.GetBufferSize(), p.frameIndex));
2767 }
2768 else
2769 {
2770 decoded.reset(DicomImageDecoder::Decode(instance.GetParsedDicomFile(), p.frameIndex));
2771 }
2772
2773 *(p.targetImage) = ReturnImage(decoded); 2843 *(p.targetImage) = ReturnImage(decoded);
2774 return; 2844 return;
2775 } 2845 }
2776 2846
2777 case _OrthancPluginService_SerializeDicomInstance: 2847 case _OrthancPluginService_SerializeDicomInstance:
2787 std::string serialized; 2857 std::string serialized;
2788 instance.GetParsedDicomFile().SaveToMemoryBuffer(serialized); 2858 instance.GetParsedDicomFile().SaveToMemoryBuffer(serialized);
2789 CopyToMemoryBuffer(*p.targetBuffer, serialized); 2859 CopyToMemoryBuffer(*p.targetBuffer, serialized);
2790 return; 2860 return;
2791 } 2861 }
2862
2863 case _OrthancPluginService_GetInstanceAdvancedJson:
2864 {
2865 if (p.targetStringToFree == NULL)
2866 {
2867 throw OrthancException(ErrorCode_NullPointer);
2868 }
2792 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
2793 default: 2895 default:
2794 throw OrthancException(ErrorCode_InternalError); 2896 throw OrthancException(ErrorCode_InternalError);
2795 } 2897 }
2796 } 2898 }
2797 2899
3673 3775
3674 case _OrthancPluginService_GetInstanceFramesCount: 3776 case _OrthancPluginService_GetInstanceFramesCount:
3675 case _OrthancPluginService_GetInstanceRawFrame: 3777 case _OrthancPluginService_GetInstanceRawFrame:
3676 case _OrthancPluginService_GetInstanceDecodedFrame: 3778 case _OrthancPluginService_GetInstanceDecodedFrame:
3677 case _OrthancPluginService_SerializeDicomInstance: 3779 case _OrthancPluginService_SerializeDicomInstance:
3780 case _OrthancPluginService_GetInstanceAdvancedJson:
3781 case _OrthancPluginService_GetInstanceDicomWebJson:
3782 case _OrthancPluginService_GetInstanceDicomWebXml:
3678 AccessDicomInstance2(service, parameters); 3783 AccessDicomInstance2(service, parameters);
3679 return true; 3784 return true;
3680 3785
3681 case _OrthancPluginService_SetGlobalProperty: 3786 case _OrthancPluginService_SetGlobalProperty:
3682 { 3787 {
4193 case _OrthancPluginService_EncodeDicomWebXml: 4298 case _OrthancPluginService_EncodeDicomWebXml:
4194 { 4299 {
4195 const _OrthancPluginEncodeDicomWeb& p = 4300 const _OrthancPluginEncodeDicomWeb& p =
4196 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb*>(parameters); 4301 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb*>(parameters);
4197 4302
4198 DicomWebBinaryFormatter formatter(p); 4303 DicomWebBinaryFormatter formatter(p.callback);
4199 4304 formatter.Apply(p.target,
4200 DicomWebJsonVisitor visitor; 4305 (service == _OrthancPluginService_EncodeDicomWebJson),
4201 visitor.SetFormatter(formatter); 4306 p.dicom, p.dicomSize);
4202 4307 return true;
4203 { 4308 }
4204 ParsedDicomFile dicom(p.dicom, p.dicomSize); 4309
4205 dicom.Apply(visitor); 4310 case _OrthancPluginService_EncodeDicomWebJson2:
4206 } 4311 case _OrthancPluginService_EncodeDicomWebXml2:
4207 4312 {
4208 std::string s; 4313 const _OrthancPluginEncodeDicomWeb2& p =
4209 4314 *reinterpret_cast<const _OrthancPluginEncodeDicomWeb2*>(parameters);
4210 if (service == _OrthancPluginService_EncodeDicomWebJson) 4315
4211 { 4316 DicomWebBinaryFormatter formatter(p.callback, p.payload);
4212 s = visitor.GetResult().toStyledString(); 4317 formatter.Apply(p.target,
4213 } 4318 (service == _OrthancPluginService_EncodeDicomWebJson2),
4214 else 4319 p.dicom, p.dicomSize);
4215 {
4216 visitor.FormatXml(s);
4217 }
4218
4219 *p.target = CopyString(s);
4220 return true; 4320 return true;
4221 } 4321 }
4222 4322
4223 case _OrthancPluginService_GetTagName: 4323 case _OrthancPluginService_GetTagName:
4224 GetTagName(parameters); 4324 GetTagName(parameters);
4267 throw OrthancException(ErrorCode_ParameterOutOfRange, "Unsupported transfer syntax: " + 4367 throw OrthancException(ErrorCode_ParameterOutOfRange, "Unsupported transfer syntax: " +
4268 std::string(p.transferSyntax == NULL ? "(null)" : p.transferSyntax)); 4368 std::string(p.transferSyntax == NULL ? "(null)" : p.transferSyntax));
4269 } 4369 }
4270 else 4370 else
4271 { 4371 {
4272 ParsedDicomFile dicom(p.buffer, p.size);
4273
4274 std::set<DicomTransferSyntax> syntaxes; 4372 std::set<DicomTransferSyntax> syntaxes;
4275 syntaxes.insert(transferSyntax); 4373 syntaxes.insert(transferSyntax);
4276 4374
4277 std::unique_ptr<IDicomTranscoder::TranscodedDicom> transcoded; 4375 IDicomTranscoder::DicomImage source;
4376 source.SetExternalBuffer(p.buffer, p.size);
4377
4378 IDicomTranscoder::DicomImage transcoded;
4379 bool success;
4278 4380
4279 { 4381 {
4280 PImpl::ServerContextLock lock(*pimpl_); 4382 PImpl::ServerContextLock lock(*pimpl_);
4281 transcoded.reset(lock.GetContext().GetTranscoder().TranscodeToParsed( 4383 success = lock.GetContext().Transcode(
4282 dicom.GetDcmtkObject(), p.buffer, p.size, 4384 transcoded, source, syntaxes, true /* allow new sop */);
4283 syntaxes, true /* allow new sop */));
4284 } 4385 }
4285 4386
4286 if (transcoded.get() == NULL) 4387 if (success)
4388 {
4389 *(p.target) = reinterpret_cast<OrthancPluginDicomInstance*>(
4390 new DicomInstanceFromTranscoded(transcoded));
4391 return true;
4392 }
4393 else
4287 { 4394 {
4288 throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode image"); 4395 throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode image");
4289 } 4396 }
4290 else 4397 }
4291 { 4398 }
4292 *(p.target) = reinterpret_cast<OrthancPluginDicomInstance*>( 4399
4293 new DicomInstanceFromTranscoded(*transcoded)); 4400 case _OrthancPluginService_CreateMemoryBuffer:
4294 return true; 4401 {
4295 } 4402 const _OrthancPluginCreateMemoryBuffer& p =
4296 } 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;
4297 } 4417 }
4298 4418
4299 default: 4419 default:
4300 return false; 4420 return false;
4301 } 4421 }
4345 RegisterMoveCallback(parameters); 4465 RegisterMoveCallback(parameters);
4346 return true; 4466 return true;
4347 4467
4348 case _OrthancPluginService_RegisterDecodeImageCallback: 4468 case _OrthancPluginService_RegisterDecodeImageCallback:
4349 RegisterDecodeImageCallback(parameters); 4469 RegisterDecodeImageCallback(parameters);
4470 return true;
4471
4472 case _OrthancPluginService_RegisterTranscoderCallback:
4473 RegisterTranscoderCallback(parameters);
4350 return true; 4474 return true;
4351 4475
4352 case _OrthancPluginService_RegisterJobsUnserializer: 4476 case _OrthancPluginService_RegisterJobsUnserializer:
4353 RegisterJobsUnserializer(parameters); 4477 RegisterJobsUnserializer(parameters);
4354 return true; 4478 return true;
4731 } 4855 }
4732 4856
4733 4857
4734 bool OrthancPlugins::HasCustomImageDecoder() 4858 bool OrthancPlugins::HasCustomImageDecoder()
4735 { 4859 {
4736 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); 4860 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
4737 return !pimpl_->decodeImageCallbacks_.empty(); 4861 return !pimpl_->decodeImageCallbacks_.empty();
4738 } 4862 }
4739 4863
4740 4864
4741 ImageAccessor* OrthancPlugins::DecodeUnsafe(const void* dicom, 4865 bool OrthancPlugins::HasCustomTranscoder()
4742 size_t size, 4866 {
4743 unsigned int frame) 4867 boost::shared_lock<boost::shared_mutex> lock(pimpl_->decoderTranscoderMutex_);
4744 { 4868 return !pimpl_->transcoderCallbacks_.empty();
4745 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_);
4746 4877
4747 for (PImpl::DecodeImageCallbacks::const_iterator 4878 for (PImpl::DecodeImageCallbacks::const_iterator
4748 decoder = pimpl_->decodeImageCallbacks_.begin(); 4879 decoder = pimpl_->decodeImageCallbacks_.begin();
4749 decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder) 4880 decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder)
4750 { 4881 {
4755 return reinterpret_cast<ImageAccessor*>(pluginImage); 4886 return reinterpret_cast<ImageAccessor*>(pluginImage);
4756 } 4887 }
4757 } 4888 }
4758 4889
4759 return NULL; 4890 return NULL;
4760 }
4761
4762
4763 ImageAccessor* OrthancPlugins::Decode(const void* dicom,
4764 size_t size,
4765 unsigned int frame)
4766 {
4767 ImageAccessor* result = DecodeUnsafe(dicom, size, frame);
4768
4769 if (result != NULL)
4770 {
4771 return result;
4772 }
4773 else
4774 {
4775 LOG(INFO) << "The installed image decoding plugins cannot handle an image, fallback to the built-in decoder";
4776 DefaultDicomImageDecoder defaultDecoder;
4777 return defaultDecoder.Decode(dicom, size, frame);
4778 }
4779 } 4891 }
4780 4892
4781 4893
4782 bool OrthancPlugins::IsAllowed(HttpMethod method, 4894 bool OrthancPlugins::IsAllowed(HttpMethod method,
4783 const char* uri, 4895 const char* uri,
5062 5174
5063 return NULL; 5175 return NULL;
5064 } 5176 }
5065 5177
5066 5178
5067 bool OrthancPlugins::Transcode(std::string& target, 5179 class MemoryBufferRaii : public boost::noncopyable
5068 DicomTransferSyntax& sourceSyntax /* out */, 5180 {
5069 DicomTransferSyntax& targetSyntax /* out */, 5181 private:
5070 bool& hasSopInstanceUidChanged /* out */, 5182 OrthancPluginMemoryBuffer buffer_;
5071 const void* buffer, 5183
5072 size_t size, 5184 public:
5073 const std::set<DicomTransferSyntax>& allowedSyntaxes, 5185 MemoryBufferRaii()
5074 bool allowNewSopInstanceUid) 5186 {
5075 { 5187 buffer_.size = 0;
5076 // TODO 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
5077 return false; 5252 return false;
5078 } 5253 }
5079 } 5254 }