Mercurial > hg > orthanc
changeset 1826:ac5b0b4e2434
refactoring of DicomImageDecoder
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 25 Nov 2015 16:00:57 +0100 |
parents | f0f8a94c0858 |
children | 4b6673e828f4 |
files | NEWS OrthancServer/IDicomImageDecoder.h OrthancServer/Internals/DicomImageDecoder.cpp OrthancServer/Internals/DicomImageDecoder.h OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/ParsedDicomFile.cpp OrthancServer/ParsedDicomFile.h Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Plugins/Include/orthanc/OrthancCPlugin.h |
diffstat | 10 files changed, 225 insertions(+), 146 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Wed Nov 25 14:24:26 2015 +0100 +++ b/NEWS Wed Nov 25 16:00:57 2015 +0100 @@ -37,6 +37,7 @@ ------- * New functions: + - "OrthancPluginRegisterDecodeImageCallback()" to replace the built-in image decoder - "OrthancPluginDicomInstanceToJson()" to convert DICOM to JSON - "OrthancPluginDicomBufferToJson()" to convert DICOM to JSON - "OrthancPluginRegisterErrorCode()" to declare custom error codes
--- a/OrthancServer/IDicomImageDecoder.h Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/IDicomImageDecoder.h Wed Nov 25 16:00:57 2015 +0100 @@ -47,8 +47,7 @@ { } - virtual bool Decode(ImageBuffer& target, - ParsedDicomFile& dicom, - unsigned int frame) = 0; + virtual ImageAccessor* Decode(ParsedDicomFile& dicom, + unsigned int frame) = 0; }; }
--- a/OrthancServer/Internals/DicomImageDecoder.cpp Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/Internals/DicomImageDecoder.cpp Wed Nov 25 16:00:57 2015 +0100 @@ -82,8 +82,8 @@ #include "../../Core/Logging.h" #include "../../Core/OrthancException.h" +#include "../../Core/Images/Image.h" #include "../../Core/Images/ImageProcessing.h" -#include "../../Core/Images/PngWriter.h" // TODO REMOVE THIS #include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h" #include "../ToDcmtkBridge.h" #include "../FromDcmtkBridge.h" @@ -91,6 +91,8 @@ #include <boost/lexical_cast.hpp> +#include <dcmtk/dcmdata/dcfilefo.h> + #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 #include <dcmtk/dcmjpls/djcodecd.h> #include <dcmtk/dcmjpls/djcparam.h> @@ -304,8 +306,7 @@ }; - void DicomImageDecoder::SetupImageBuffer(ImageBuffer& target, - DcmDataset& dataset) + ImageAccessor* DicomImageDecoder::CreateImage(DcmDataset& dataset) { DicomMap m; FromDcmtkBridge::Convert(m, dataset); @@ -324,9 +325,7 @@ throw OrthancException(ErrorCode_NotImplemented); } - target.SetHeight(info.GetHeight()); - target.SetWidth(info.GetWidth()); - target.SetFormat(format); + return new Image(format, info.GetWidth(), info.GetHeight()); } @@ -374,22 +373,20 @@ } - void DicomImageDecoder::DecodeUncompressedImage(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame) + ImageAccessor* DicomImageDecoder::DecodeUncompressedImage(DcmDataset& dataset, + unsigned int frame) { if (!IsUncompressedImage(dataset)) { throw OrthancException(ErrorCode_BadParameterType); } - DecodeUncompressedImageInternal(target, dataset, frame); + return DecodeUncompressedImageInternal(dataset, frame); } - void DicomImageDecoder::DecodeUncompressedImageInternal(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame) + ImageAccessor* DicomImageDecoder::DecodeUncompressedImageInternal(DcmDataset& dataset, + unsigned int frame) { ImageSource source; source.Setup(dataset, frame); @@ -399,10 +396,10 @@ * Resize the target image. **/ - SetupImageBuffer(target, dataset); + std::auto_ptr<ImageAccessor> target(CreateImage(dataset)); - if (source.GetWidth() != target.GetWidth() || - source.GetHeight() != target.GetHeight()) + if (source.GetWidth() != target->GetWidth() || + source.GetHeight() != target->GetHeight()) { throw OrthancException(ErrorCode_InternalError); } @@ -413,7 +410,6 @@ * direct access to copy its values. **/ - ImageAccessor targetAccessor(target.GetAccessor()); const DicomImageInformation& info = source.GetAccessor().GetInformation(); bool fastVersionSuccess = false; @@ -435,8 +431,8 @@ info.GetWidth() * GetBytesPerPixel(sourceFormat), buffer + frame * frameSize); - ImageProcessing::Convert(targetAccessor, sourceImage); - ImageProcessing::ShiftRight(targetAccessor, info.GetShift()); + ImageProcessing::Convert(*target, sourceImage); + ImageProcessing::ShiftRight(*target, info.GetShift()); fastVersionSuccess = true; } } @@ -453,33 +449,34 @@ if (!fastVersionSuccess) { - switch (target.GetFormat()) + switch (target->GetFormat()) { case PixelFormat_RGB24: case PixelFormat_RGBA32: case PixelFormat_Grayscale8: - CopyPixels<uint8_t>(targetAccessor, source.GetAccessor()); + CopyPixels<uint8_t>(*target, source.GetAccessor()); break; case PixelFormat_Grayscale16: - CopyPixels<uint16_t>(targetAccessor, source.GetAccessor()); + CopyPixels<uint16_t>(*target, source.GetAccessor()); break; case PixelFormat_SignedGrayscale16: - CopyPixels<int16_t>(targetAccessor, source.GetAccessor()); + CopyPixels<int16_t>(*target, source.GetAccessor()); break; default: throw OrthancException(ErrorCode_InternalError); } } + + return target.release(); } #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 - void DicomImageDecoder::DecodeJpegLossless(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame) + ImageAccessor* DicomImageDecoder::DecodeJpegLossless(DcmDataset& dataset, + unsigned int frame) { if (!IsJpegLossless(dataset)) { @@ -500,9 +497,7 @@ throw OrthancException(ErrorCode_BadFileFormat); } - SetupImageBuffer(target, dataset); - - ImageAccessor targetAccessor(target.GetAccessor()); + std::auto_ptr<ImageAccessor> target(CreateImage(dataset)); /** * The "DJLSLosslessDecoder" and "DJLSNearLosslessDecoder" in DCMTK @@ -518,38 +513,36 @@ OFString decompressedColorModel; // Out DJ_RPLossless representationParameter; OFCondition c = decoder.decodeFrame(&representationParameter, pixelSequence, ¶meters, - &dataset, frame, startFragment, targetAccessor.GetBuffer(), - targetAccessor.GetSize(), decompressedColorModel); + &dataset, frame, startFragment, target->GetBuffer(), + target->GetSize(), decompressedColorModel); if (!c.good()) { throw OrthancException(ErrorCode_InternalError); } + + return target.release(); } #endif - bool DicomImageDecoder::Decode(ImageBuffer& target, - ParsedDicomFile& dicom, - unsigned int frame) + ImageAccessor* DicomImageDecoder::Decode(ParsedDicomFile& dicom, + unsigned int frame) { DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset(); if (IsUncompressedImage(dataset)) { - DecodeUncompressedImage(target, dataset, frame); - return true; + return DecodeUncompressedImage(dataset, frame); } - #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 if (IsJpegLossless(dataset)) { LOG(INFO) << "Decoding a JPEG-LS image"; - DecodeJpegLossless(target, dataset, frame); - return true; + return DecodeJpegLossless(dataset, frame); } #endif @@ -558,7 +551,6 @@ // TODO Implement this part to speed up JPEG decompression #endif - /** * This DICOM image format is not natively supported by * Orthanc. As a last resort, try and decode it through @@ -575,12 +567,11 @@ if (converted->canWriteXfer(EXS_LittleEndianExplicit)) { - DecodeUncompressedImageInternal(target, *converted, frame); - return true; + return DecodeUncompressedImageInternal(*converted, frame); } } - return false; + return NULL; } @@ -591,14 +582,13 @@ } - bool DicomImageDecoder::TruncateDecodedImage(ImageBuffer& target, - ImageBuffer& source, + bool DicomImageDecoder::TruncateDecodedImage(std::auto_ptr<ImageAccessor>& image, PixelFormat format, bool allowColorConversion) { // If specified, prevent the conversion between color and // grayscale images - bool isSourceColor = IsColorImage(source.GetFormat()); + bool isSourceColor = IsColorImage(image->GetFormat()); bool isTargetColor = IsColorImage(format); if (!allowColorConversion) @@ -609,34 +599,25 @@ } } - if (source.GetFormat() == format) + if (image->GetFormat() != format) { - // No conversion is required, return the temporary image - target.AcquireOwnership(source); - return true; + // A conversion is required + std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight())); + ImageProcessing::Convert(*target, *image); + image = target; } - target.SetFormat(format); - target.SetWidth(source.GetWidth()); - target.SetHeight(source.GetHeight()); - - ImageAccessor targetAccessor(target.GetAccessor()); - ImageAccessor sourceAccessor(source.GetAccessor()); - ImageProcessing::Convert(targetAccessor, sourceAccessor); - return true; } - bool DicomImageDecoder::PreviewDecodedImage(ImageBuffer& target, - ImageBuffer& source) + bool DicomImageDecoder::PreviewDecodedImage(std::auto_ptr<ImageAccessor>& image) { - switch (source.GetFormat()) + switch (image->GetFormat()) { case PixelFormat_RGB24: { - // Directly return color images (RGB) - target.AcquireOwnership(source); + // Directly return color images without modification (RGB) return true; } @@ -645,32 +626,24 @@ case PixelFormat_SignedGrayscale16: { // Grayscale image: Stretch its dynamics to the [0,255] range - target.SetFormat(PixelFormat_Grayscale8); - target.SetWidth(source.GetWidth()); - target.SetHeight(source.GetHeight()); + int64_t a, b; + ImageProcessing::GetMinMaxValue(a, b, *image); - ImageAccessor targetAccessor(target.GetAccessor()); - ImageAccessor sourceAccessor(source.GetAccessor()); - - int64_t a, b; - ImageProcessing::GetMinMaxValue(a, b, sourceAccessor); - if (a == b) { - ImageProcessing::Set(targetAccessor, 0); + ImageProcessing::Set(*image, 0); } else { - ImageProcessing::ShiftScale(sourceAccessor, static_cast<float>(-a), 255.0f / static_cast<float>(b - a)); + ImageProcessing::ShiftScale(*image, static_cast<float>(-a), 255.0f / static_cast<float>(b - a)); + } - if (source.GetFormat() == PixelFormat_Grayscale8) - { - target.AcquireOwnership(source); - } - else - { - ImageProcessing::Convert(targetAccessor, sourceAccessor); - } + // If the source image is not grayscale 8bpp, convert it + if (image->GetFormat() != PixelFormat_Grayscale8) + { + std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight())); + ImageProcessing::Convert(*target, *image); + image = target; } return true;
--- a/OrthancServer/Internals/DicomImageDecoder.h Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/Internals/DicomImageDecoder.h Wed Nov 25 16:00:57 2015 +0100 @@ -32,10 +32,12 @@ #pragma once -#include <dcmtk/dcmdata/dcfilefo.h> +#include <memory> #include "../IDicomImageDecoder.h" +class DcmDataset; + namespace Orthanc { class DicomImageDecoder : public IDicomImageDecoder @@ -43,38 +45,31 @@ private: class ImageSource; - static void DecodeUncompressedImageInternal(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame); + static ImageAccessor* DecodeUncompressedImageInternal(DcmDataset& dataset, + unsigned int frame); static bool IsPsmctRle1(DcmDataset& dataset); - static void SetupImageBuffer(ImageBuffer& target, - DcmDataset& dataset); + static ImageAccessor* CreateImage(DcmDataset& dataset); static bool IsUncompressedImage(const DcmDataset& dataset); - static void DecodeUncompressedImage(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame); + static ImageAccessor* DecodeUncompressedImage(DcmDataset& dataset, + unsigned int frame); #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 - static void DecodeJpegLossless(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame); + static ImageAccessor* DecodeJpegLossless(DcmDataset& dataset, + unsigned int frame); #endif public: - virtual bool Decode(ImageBuffer& target, - ParsedDicomFile& dicom, - unsigned int frame); + virtual ImageAccessor *Decode(ParsedDicomFile& dicom, + unsigned int frame); - static bool TruncateDecodedImage(ImageBuffer& target, - ImageBuffer& source, + static bool TruncateDecodedImage(std::auto_ptr<ImageAccessor>& image, PixelFormat format, bool allowColorConversion); - static bool PreviewDecodedImage(ImageBuffer& target, - ImageBuffer& source); + static bool PreviewDecodedImage(std::auto_ptr<ImageAccessor>& image); }; }
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Nov 25 16:00:57 2015 +0100 @@ -410,7 +410,12 @@ try { - DicomImageDecoder decoder; // TODO plugins +#if ORTHANC_PLUGINS_ENABLED == 1 + IDicomImageDecoder& decoder = context.GetPlugins(); +#else + DicomImageDecoder decoder; // This is Orthanc's built-in decoder +#endif + ImageToEncode image(decoder, dicom, frame, mode); HttpContentNegociation negociation; @@ -463,15 +468,17 @@ std::string dicomContent; context.ReadFile(dicomContent, publicId, FileContentType_Dicom); +#if ORTHANC_PLUGINS_ENABLED == 1 + IDicomImageDecoder& decoder = context.GetPlugins(); +#else + DicomImageDecoder decoder; // This is Orthanc's built-in decoder +#endif + ParsedDicomFile dicom(dicomContent); - ImageBuffer buffer; - DicomImageDecoder decoder; // TODO plugin - dicom.ExtractImage(buffer, decoder, frame); - - ImageAccessor accessor(buffer.GetConstAccessor()); + std::auto_ptr<ImageAccessor> decoded(dicom.ExtractImage(decoder, frame)); std::string result; - accessor.ToMatlabString(result); + decoded->ToMatlabString(result); call.GetOutput().AnswerBuffer(result, "text/plain"); }
--- a/OrthancServer/ParsedDicomFile.cpp Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.cpp Wed Nov 25 16:00:57 2015 +0100 @@ -1048,53 +1048,59 @@ } - void ParsedDicomFile::ExtractImage(ImageBuffer& result, - IDicomImageDecoder& decoder, - unsigned int frame) + ImageAccessor* ParsedDicomFile::ExtractImage(IDicomImageDecoder& decoder, + unsigned int frame) { - if (!decoder.Decode(result, *this, frame)) + std::auto_ptr<ImageAccessor> decoded(decoder.Decode(*this, frame)); + + if (decoded.get() == NULL) { + LOG(ERROR) << "Cannot decode a DICOM image"; throw OrthancException(ErrorCode_BadFileFormat); } + else + { + return decoded.release(); + } } - void ParsedDicomFile::ExtractImage(ImageBuffer& result, - IDicomImageDecoder& decoder, - unsigned int frame, - ImageExtractionMode mode) + ImageAccessor* ParsedDicomFile::ExtractImage(IDicomImageDecoder& decoder, + unsigned int frame, + ImageExtractionMode mode) { - ImageBuffer source; - if (!decoder.Decode(source, *this, frame)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } + std::auto_ptr<ImageAccessor> decoded(ExtractImage(decoder, frame)); bool ok = false; switch (mode) { case ImageExtractionMode_UInt8: - ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_Grayscale8, false); + ok = DicomImageDecoder::TruncateDecodedImage(decoded, PixelFormat_Grayscale8, false); break; case ImageExtractionMode_UInt16: - ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_Grayscale16, false); + ok = DicomImageDecoder::TruncateDecodedImage(decoded, PixelFormat_Grayscale16, false); break; case ImageExtractionMode_Int16: - ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_SignedGrayscale16, false); + ok = DicomImageDecoder::TruncateDecodedImage(decoded, PixelFormat_SignedGrayscale16, false); break; case ImageExtractionMode_Preview: - ok = DicomImageDecoder::PreviewDecodedImage(result, source); + ok = DicomImageDecoder::PreviewDecodedImage(decoded); break; default: throw OrthancException(ErrorCode_ParameterOutOfRange); } - if (!ok) + if (ok) + { + assert(decoded.get() != NULL); + return decoded.release(); + } + else { throw OrthancException(ErrorCode_NotImplemented); } @@ -1106,12 +1112,11 @@ unsigned int frame, ImageExtractionMode mode) { - ImageBuffer buffer; - ExtractImage(buffer, decoder, frame, mode); + std::auto_ptr<ImageAccessor> decoded(ExtractImage(decoder, frame, mode)); + assert(decoded.get() != NULL); - ImageAccessor accessor(buffer.GetConstAccessor()); PngWriter writer; - writer.WriteToMemory(result, accessor); + writer.WriteToMemory(result, *decoded); } @@ -1127,13 +1132,12 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } - ImageBuffer buffer; - ExtractImage(buffer, decoder, frame, mode); + std::auto_ptr<ImageAccessor> decoded(ExtractImage(decoder, frame, mode)); + assert(decoded.get() != NULL); - ImageAccessor accessor(buffer.GetConstAccessor()); JpegWriter writer; writer.SetQuality(quality); - writer.WriteToMemory(result, accessor); + writer.WriteToMemory(result, *decoded); }
--- a/OrthancServer/ParsedDicomFile.h Wed Nov 25 14:24:26 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.h Wed Nov 25 16:00:57 2015 +0100 @@ -126,14 +126,12 @@ void EmbedImage(const std::string& mime, const std::string& content); - void ExtractImage(ImageBuffer& result, - IDicomImageDecoder& decoder, - unsigned int frame); + ImageAccessor* ExtractImage(IDicomImageDecoder& decoder, + unsigned int frame); - void ExtractImage(ImageBuffer& result, - IDicomImageDecoder& decoder, - unsigned int frame, - ImageExtractionMode mode); + ImageAccessor* ExtractImage(IDicomImageDecoder& decoder, + unsigned int frame, + ImageExtractionMode mode); void ExtractPngImage(std::string& result, IDicomImageDecoder& decoder,
--- a/Plugins/Engine/OrthancPlugins.cpp Wed Nov 25 14:24:26 2015 +0100 +++ b/Plugins/Engine/OrthancPlugins.cpp Wed Nov 25 16:00:57 2015 +0100 @@ -48,6 +48,7 @@ #include "../../OrthancServer/ServerContext.h" #include "../../OrthancServer/ServerToolbox.h" #include "../../OrthancServer/Search/HierarchicalMatcher.h" +#include "../../OrthancServer/Internals/DicomImageDecoder.h" #include "../../Core/Compression/ZlibCompressor.h" #include "../../Core/Compression/GzipCompressor.h" #include "../../Core/Images/Image.h" @@ -286,11 +287,13 @@ OnStoredCallbacks onStoredCallbacks_; OnChangeCallbacks onChangeCallbacks_; OrthancPluginWorklistCallback worklistCallback_; + OrthancPluginDecodeImageCallback decodeImageCallback_; std::auto_ptr<StorageAreaFactory> storageArea_; boost::recursive_mutex restCallbackMutex_; boost::recursive_mutex storedCallbackMutex_; boost::recursive_mutex changeCallbackMutex_; boost::mutex worklistCallbackMutex_; + boost::mutex decodeImageCallbackMutex_; boost::recursive_mutex invokeServiceMutex_; Properties properties_; int argc_; @@ -301,6 +304,7 @@ PImpl() : context_(NULL), worklistCallback_(NULL), + decodeImageCallback_(NULL), argc_(1), argv_(NULL) { @@ -725,12 +729,32 @@ } else { - LOG(INFO) << "Plugin has registered an modality worklist callback"; + LOG(INFO) << "Plugin has registered a callback to handle modality worklists"; pimpl_->worklistCallback_ = p.callback; } } + void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) + { + const _OrthancPluginDecodeImageCallback& p = + *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); + + boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); + + if (pimpl_->decodeImageCallback_ != NULL) + { + LOG(ERROR) << "Can only register one plugin to handle the decompression of DICOM images"; + throw OrthancException(ErrorCode_Plugin); + } + else + { + LOG(INFO) << "Plugin has registered a callback to decode DICOM images"; + pimpl_->decodeImageCallback_ = p.callback; + } + } + + void OrthancPlugins::AnswerBuffer(const void* parameters) @@ -1544,6 +1568,10 @@ RegisterWorklistCallback(parameters); return true; + case _OrthancPluginService_RegisterDecodeImageCallback: + RegisterDecodeImageCallback(parameters); + return true; + case _OrthancPluginService_AnswerBuffer: AnswerBuffer(parameters); return true; @@ -2149,4 +2177,31 @@ return pimpl_->worklistCallback_ != NULL; } + + ImageAccessor* OrthancPlugins::Decode(ParsedDicomFile& dicom, + unsigned int frame) + { + { + boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); + if (pimpl_->decodeImageCallback_ != NULL) + { + std::string s; + dicom.SaveToMemoryBuffer(s); + + OrthancPluginImage* pluginImage = NULL; + if (pimpl_->decodeImageCallback_(&pluginImage, s.c_str(), s.size(), frame) == OrthancPluginErrorCode_Success && + pluginImage != NULL) + { + return reinterpret_cast<ImageAccessor*>(pluginImage); + } + else + { + LOG(WARNING) << "The custom image decoder cannot handle an image, trying with the built-in decoder"; + } + } + } + + DicomImageDecoder defaultDecoder; + return defaultDecoder.Decode(dicom, frame); + } }
--- a/Plugins/Engine/OrthancPlugins.h Wed Nov 25 14:24:26 2015 +0100 +++ b/Plugins/Engine/OrthancPlugins.h Wed Nov 25 16:00:57 2015 +0100 @@ -50,6 +50,7 @@ #include "../../Core/FileStorage/IStorageArea.h" #include "../../Core/HttpServer/IHttpHandler.h" #include "../../OrthancServer/IServerListener.h" +#include "../../OrthancServer/IDicomImageDecoder.h" #include "../../OrthancServer/DicomProtocol/IWorklistRequestHandlerFactory.h" #include "OrthancPluginDatabase.h" #include "PluginsManager.h" @@ -65,7 +66,8 @@ public IHttpHandler, public IPluginServiceProvider, public IServerListener, - public IWorklistRequestHandlerFactory + public IWorklistRequestHandlerFactory, + public IDicomImageDecoder { private: struct PImpl; @@ -84,6 +86,8 @@ void RegisterWorklistCallback(const void* parameters); + void RegisterDecodeImageCallback(const void* parameters); + void AnswerBuffer(const void* parameters); void Redirect(const void* parameters); @@ -217,6 +221,9 @@ bool HasWorklistHandler(); virtual IWorklistRequestHandler* ConstructWorklistRequestHandler(); + + virtual ImageAccessor* Decode(ParsedDicomFile& dicom, + unsigned int frame); }; }
--- a/Plugins/Include/orthanc/OrthancCPlugin.h Wed Nov 25 14:24:26 2015 +0100 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Wed Nov 25 16:00:57 2015 +0100 @@ -19,6 +19,7 @@ * - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea(). * - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV2(). * - Possibly register a handler for C-Find SCP against DICOM worklists using OrthancPluginRegisterWorklistCallback(). + * - Possibly register a custom decoder for DICOM images using OrthancPluginRegisterDecodeImageCallback(). * -# <tt>void OrthancPluginFinalize()</tt>: * This function is invoked by Orthanc during its shutdown. The plugin * must free all its memory. @@ -405,6 +406,7 @@ _OrthancPluginService_RegisterOnChangeCallback = 1003, _OrthancPluginService_RegisterRestCallbackNoLock = 1004, _OrthancPluginService_RegisterWorklistCallback = 1005, + _OrthancPluginService_RegisterDecodeImageCallback = 1006, /* Sending answers to REST calls */ _OrthancPluginService_AnswerBuffer = 2000, @@ -843,6 +845,18 @@ /** + * @brief Signature of a callback function to decode a DICOM instance as an image. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginDecodeImageCallback) ( + OrthancPluginImage** target, + const void* dicom, + const uint32_t size, + uint32_t frameIndex); + + + + /** * @brief Signature of a function to free dynamic memory. **/ typedef void (*OrthancPluginFree) (void* buffer); @@ -4351,6 +4365,32 @@ return context->InvokeService(context, _OrthancPluginService_DicomFromJson, ¶ms); } + + typedef struct + { + OrthancPluginDecodeImageCallback callback; + } _OrthancPluginDecodeImageCallback; + + /** + * @brief Register a callback to handle the decoding of DICOM images. + * + * This function registers a custom callback to the decoding of + * DICOM images, replacing the built-in decoder of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterDecodeImageCallback( + OrthancPluginContext* context, + OrthancPluginDecodeImageCallback callback) + { + _OrthancPluginDecodeImageCallback params; + params.callback = callback; + + context->InvokeService(context, _OrthancPluginService_RegisterDecodeImageCallback, ¶ms); + } + #ifdef __cplusplus } #endif