# HG changeset patch # User Sebastien Jodogne # Date 1404304917 -7200 # Node ID 501880d764741689bd427c1bd30e98cb15d23ce4 # Parent af014624dac1a0301f42d4f529dd0b50194f3e58 improvements to GDCM plugin diff -r af014624dac1 -r 501880d76474 Core/ImageFormats/ImageProcessing.cpp --- a/Core/ImageFormats/ImageProcessing.cpp Wed Jul 02 13:53:56 2014 +0200 +++ b/Core/ImageFormats/ImageProcessing.cpp Wed Jul 02 14:41:57 2014 +0200 @@ -75,6 +75,44 @@ } + template + static void ConvertColorToGrayscale(ImageAccessor& target, + const ImageAccessor& source) + { + assert(source.GetFormat() == PixelFormat_RGB24); + + const TargetType minValue = std::numeric_limits::min(); + const TargetType maxValue = std::numeric_limits::max(); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + TargetType* t = reinterpret_cast(target.GetRow(y)); + const uint8_t* s = reinterpret_cast(source.GetConstRow(y)); + + for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s += 3) + { + // Y = 0.2126 R + 0.7152 G + 0.0722 B + int32_t v = (2126 * static_cast(s[0]) + + 7152 * static_cast(s[1]) + + 0722 * static_cast(s[2])) / 1000; + + if (static_cast(v) < static_cast(minValue)) + { + *t = minValue; + } + else if (static_cast(v) > static_cast(maxValue)) + { + *t = maxValue; + } + else + { + *t = static_cast(v); + } + } + } + } + + template static void SetInternal(ImageAccessor& image, int64_t constant) @@ -319,6 +357,27 @@ return; } + if (target.GetFormat() == PixelFormat_Grayscale8 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale16 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_SignedGrayscale16 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale(target, source); + return; + } + throw OrthancException(ErrorCode_NotImplemented); } diff -r af014624dac1 -r 501880d76474 Plugins/Engine/PluginsHttpHandler.cpp --- a/Plugins/Engine/PluginsHttpHandler.cpp Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/Engine/PluginsHttpHandler.cpp Wed Jul 02 14:41:57 2014 +0200 @@ -287,6 +287,16 @@ } + void PluginsHttpHandler::Redirect(const void* parameters) + { + const _OrthancPluginRedirect& p = + *reinterpret_cast(parameters); + + HttpOutput* translatedOutput = reinterpret_cast(p.output); + translatedOutput->Redirect(p.redirection); + } + + void PluginsHttpHandler::CompressAndAnswerPngImage(const void* parameters) { const _OrthancPluginCompressAndAnswerPngImage& p = @@ -469,6 +479,10 @@ RestApiPostPut(false, parameters); return true; + case _OrthancPluginService_Redirect: + Redirect(parameters); + return true; + default: return false; } diff -r af014624dac1 -r 501880d76474 Plugins/Engine/PluginsHttpHandler.h --- a/Plugins/Engine/PluginsHttpHandler.h Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/Engine/PluginsHttpHandler.h Wed Jul 02 14:41:57 2014 +0200 @@ -54,6 +54,8 @@ void AnswerBuffer(const void* parameters); + void Redirect(const void* parameters); + void CompressAndAnswerPngImage(const void* parameters); void GetDicomForInstance(const void* parameters); diff -r af014624dac1 -r 501880d76474 Plugins/OrthancCPlugin/OrthancCPlugin.h --- a/Plugins/OrthancCPlugin/OrthancCPlugin.h Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/OrthancCPlugin/OrthancCPlugin.h Wed Jul 02 14:41:57 2014 +0200 @@ -213,6 +213,7 @@ /* Sending answers to REST calls */ _OrthancPluginService_AnswerBuffer = 2000, _OrthancPluginService_CompressAndAnswerPngImage = 2001, + _OrthancPluginService_Redirect = 2002, /* Access to the Orthanc database and API */ _OrthancPluginService_GetDicomForInstance = 3000, @@ -664,6 +665,34 @@ } + typedef struct + { + OrthancPluginRestOutput* output; + const char* redirection; + } _OrthancPluginRedirect; + + /** + * @brief Redirect a GET request. + * + * This function answers to a REST request by redirecting the user + * to another URI using HTTP status 301. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param redirection Where to redirect. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRedirect( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* redirection) + { + _OrthancPluginRedirect params; + params.output = output; + params.redirection = redirection; + context->InvokeService(context, _OrthancPluginService_Redirect, ¶ms); + } + + #ifdef __cplusplus } #endif diff -r af014624dac1 -r 501880d76474 Plugins/Samples/GdcmDecoding/OrthancContext.cpp --- a/Plugins/Samples/GdcmDecoding/OrthancContext.cpp Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/Samples/GdcmDecoding/OrthancContext.cpp Wed Jul 02 14:41:57 2014 +0200 @@ -156,3 +156,12 @@ OrthancPluginCompressAndAnswerPngImage(context_, output, format, accessor.GetWidth(), accessor.GetHeight(), accessor.GetPitch(), accessor.GetConstBuffer()); } + + + +void OrthancContext::Redirect(OrthancPluginRestOutput* output, + const std::string& s) +{ + Check(); + OrthancPluginRedirect(context_, output, s.c_str()); +} diff -r af014624dac1 -r 501880d76474 Plugins/Samples/GdcmDecoding/OrthancContext.h --- a/Plugins/Samples/GdcmDecoding/OrthancContext.h Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/Samples/GdcmDecoding/OrthancContext.h Wed Jul 02 14:41:57 2014 +0200 @@ -81,4 +81,7 @@ void CompressAndAnswerPngImage(OrthancPluginRestOutput* output, const Orthanc::ImageAccessor& accessor); + + void Redirect(OrthancPluginRestOutput* output, + const std::string& s); }; diff -r af014624dac1 -r 501880d76474 Plugins/Samples/GdcmDecoding/Plugin.cpp --- a/Plugins/Samples/GdcmDecoding/Plugin.cpp Wed Jul 02 13:53:56 2014 +0200 +++ b/Plugins/Samples/GdcmDecoding/Plugin.cpp Wed Jul 02 14:41:57 2014 +0200 @@ -35,6 +35,13 @@ #include #include +#include + + +static void AnswerUnsupportedImage(OrthancPluginRestOutput* output) +{ + OrthancContext::GetInstance().Redirect(output, "/app/images/unsupported.png"); +} static bool GetOrthancPixelFormat(Orthanc::PixelFormat& format, @@ -105,23 +112,39 @@ if (!imageReader.Read()) { OrthancContext::GetInstance().LogError("GDCM cannot extract an image from this DICOM instance"); - return -1; // Error + AnswerUnsupportedImage(output); + return 0; } gdcm::Image& image = imageReader.GetImage(); + // Log information about the decoded image char tmp[1024]; sprintf(tmp, "Image format: %dx%d %s with %d color channel(s)", image.GetRows(), image.GetColumns(), image.GetPixelFormat().GetScalarTypeAsString(), image.GetPixelFormat().GetSamplesPerPixel()); OrthancContext::GetInstance().LogWarning(tmp); + + // Convert planar configuration + gdcm::ImageChangePlanarConfiguration planar; + if (image.GetPlanarConfiguration() != 0 && + image.GetPixelFormat().GetSamplesPerPixel() != 1) + { + OrthancContext::GetInstance().LogWarning("Converting planar configuration to interleaved"); + planar.SetInput(imageReader.GetImage()); + planar.Change(); + image = planar.GetOutput(); + } + + // Create a read-only accessor to the bitmap decoded by GDCM Orthanc::PixelFormat format; if (!GetOrthancPixelFormat(format, image)) { OrthancContext::GetInstance().LogError("This sample plugin does not support this image format"); - return -1; // Error + AnswerUnsupportedImage(output); + return 0; } Orthanc::ImageAccessor decodedImage; @@ -166,28 +189,39 @@ Orthanc::ImageProcessing::ShiftScale(decodedImage, offset, scaling); } } - else if (outputFormat == "image-uint8") - { - converted.SetFormat(Orthanc::PixelFormat_Grayscale8); - } - else if (outputFormat == "image-uint16") - { - converted.SetFormat(Orthanc::PixelFormat_Grayscale16); - } - else if (outputFormat == "image-int16") - { - converted.SetFormat(Orthanc::PixelFormat_SignedGrayscale16); - } else { - OrthancContext::GetInstance().LogError("Unknown output format: " + outputFormat); - return -1; + if (format == Orthanc::PixelFormat_RGB24 || + format == Orthanc::PixelFormat_RGBA32) + { + // Do not convert color images to grayscale values (this is Orthanc convention) + AnswerUnsupportedImage(output); + return 0; + } + + if (outputFormat == "image-uint8") + { + converted.SetFormat(Orthanc::PixelFormat_Grayscale8); + } + else if (outputFormat == "image-uint16") + { + converted.SetFormat(Orthanc::PixelFormat_Grayscale16); + } + else if (outputFormat == "image-int16") + { + converted.SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + } + else + { + OrthancContext::GetInstance().LogError("Unknown output format: " + outputFormat); + AnswerUnsupportedImage(output); + return 0; + } } Orthanc::ImageAccessor convertedAccessor(converted.GetAccessor()); Orthanc::ImageProcessing::Convert(convertedAccessor, decodedImage); - // Compress the converted image as a PNG file OrthancContext::GetInstance().CompressAndAnswerPngImage(output, convertedAccessor);