Mercurial > hg > orthanc-webviewer
diff Plugin/DecodedImageAdapter.cpp @ 96:a6ba21a083e5 refactoring
major refactoring
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 27 Nov 2015 18:26:55 +0100 |
parents | 111689a2c177 |
children | ef1b27ba7dfc |
line wrap: on
line diff
--- a/Plugin/DecodedImageAdapter.cpp Fri Nov 27 16:19:09 2015 +0100 +++ b/Plugin/DecodedImageAdapter.cpp Fri Nov 27 18:26:55 2015 +0100 @@ -20,8 +20,13 @@ #include "DecodedImageAdapter.h" +#include "../Orthanc/Core/Images/ImageBuffer.h" +#include "../Orthanc/Core/Images/ImageProcessing.h" +#include "../Orthanc/Core/OrthancException.h" +#include "../Orthanc/Plugins/Samples/GdcmDecoder/OrthancImageWrapper.h" +#include "../Orthanc/Resources/ThirdParty/base64/base64.h" +#include "ParsedDicomImage.h" #include "ViewerToolbox.h" -#include "ParsedDicomImage.h" #include <boost/lexical_cast.hpp> #include <boost/algorithm/string/predicate.hpp> @@ -84,10 +89,38 @@ return false; } + + bool ok = false; + +#if 1 + Json::Value tags; + std::string dicom; + if (!GetStringFromOrthanc(dicom, context_, "/instances/" + instanceId + "/file") || + !GetJsonFromOrthanc(tags, context_, "/instances/" + instanceId + "/tags")) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); + } + + std::auto_ptr<OrthancImageWrapper> image(decoderCache_.Decode(context_, dicom.c_str(), dicom.size(), 0 /* TODO Frame */)); + + Json::Value json; + if (GetCornerstoneMetadata(json, tags, *image)) + { + if (type == CompressionType_Deflate) + { + ok = EncodeUsingDeflate(json, *image, 9); + } + else if (type == CompressionType_Jpeg) + { + ok = EncodeUsingJpeg(json, *image, level); + } + } + +#else + ParsedDicomImage image(context_, instanceId); Json::Value json; - bool ok = false; if (type == CompressionType_Deflate) { @@ -97,6 +130,7 @@ { ok = image.EncodeUsingJpeg(json, level); } +#endif if (ok) { @@ -112,4 +146,266 @@ return false; } } + + + static bool GetTagValue(std::string& value, + const Json::Value& tags, + const std::string& tag) + { + if (tags.type() == Json::objectValue && + tags.isMember(tag) && + tags[tag].type() == Json::objectValue && + tags[tag].isMember("Type") && + tags[tag].isMember("Value") && + tags[tag]["Type"].type() == Json::stringValue && + tags[tag]["Value"].type() == Json::stringValue && + tags[tag]["Type"].asString() == "String") + { + value = tags[tag]["Value"].asString(); + return true; + } + else + { + return false; + } + } + + + + bool DecodedImageAdapter::GetCornerstoneMetadata(Json::Value& result, + const Json::Value& tags, + OrthancImageWrapper& image) + { + using namespace Orthanc; + + float windowCenter, windowWidth; + + Orthanc::ImageAccessor accessor; + accessor.AssignReadOnly(OrthancPlugins::Convert(image.GetFormat()), image.GetWidth(), + image.GetHeight(), image.GetPitch(), image.GetBuffer()); + + switch (accessor.GetFormat()) + { + case PixelFormat_Grayscale8: + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + { + int64_t a, b; + Orthanc::ImageProcessing::GetMinMaxValue(a, b, accessor); + result["minPixelValue"] = (a < 0 ? static_cast<int32_t>(a) : 0); + result["maxPixelValue"] = (b > 0 ? static_cast<int32_t>(b) : 1); + result["color"] = false; + + windowCenter = static_cast<float>(a + b) / 2.0f; + + if (a == b) + { + windowWidth = 256.0f; // Arbitrary value + } + else + { + windowWidth = static_cast<float>(b - a) / 2.0f; + } + + break; + } + + case PixelFormat_RGB24: + result["minPixelValue"] = 0; + result["maxPixelValue"] = 255; + result["color"] = true; + windowCenter = 127.5f; + windowWidth = 256.0f; + break; + + default: + return false; + } + + result["slope"] = image.GetSlope(); + result["intercept"] = image.GetIntercept(); + result["rows"] = image.GetHeight(); + result["columns"] = image.GetWidth(); + result["height"] = image.GetHeight(); + result["width"] = image.GetWidth(); + result["columnPixelSpacing"] = image.GetColumnPixelSpacing(); + result["rowPixelSpacing"] = image.GetRowPixelSpacing(); + + result["windowCenter"] = windowCenter * image.GetSlope() + image.GetIntercept(); + result["windowWidth"] = windowWidth * image.GetSlope(); + + try + { + std::string width, center; + if (GetTagValue(center, tags, "0028,1050" /*DICOM_TAG_WINDOW_CENTER*/) && + GetTagValue(width, tags, "0028,1051" /*DICOM_TAG_WINDOW_WIDTH*/)) + { + float a = boost::lexical_cast<float>(width); + float b = boost::lexical_cast<float>(center); + result["windowWidth"] = a; + result["windowCenter"] = b; + } + } + catch (boost::bad_lexical_cast&) + { + } + + return true; + } + + + + bool DecodedImageAdapter::EncodeUsingDeflate(Json::Value& result, + OrthancImageWrapper& image, + uint8_t compressionLevel /* between 0 and 9 */) + { + Orthanc::ImageAccessor accessor; + accessor.AssignReadOnly(OrthancPlugins::Convert(image.GetFormat()), image.GetWidth(), + image.GetHeight(), image.GetPitch(), image.GetBuffer()); + + Orthanc::ImageBuffer buffer; + buffer.SetMinimalPitchForced(true); + + Orthanc::ImageAccessor converted; + + switch (accessor.GetFormat()) + { + case Orthanc::PixelFormat_RGB24: + converted = accessor; + break; + + case Orthanc::PixelFormat_Grayscale8: + case Orthanc::PixelFormat_Grayscale16: + buffer.SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + buffer.SetWidth(accessor.GetWidth()); + buffer.SetHeight(accessor.GetHeight()); + converted = buffer.GetAccessor(); + Orthanc::ImageProcessing::Convert(converted, accessor); + break; + + case Orthanc::PixelFormat_SignedGrayscale16: + converted = accessor; + break; + + default: + // Unsupported pixel format + return false; + } + + // Sanity check: The pitch must be minimal + assert(converted.GetSize() == converted.GetWidth() * converted.GetHeight() * + GetBytesPerPixel(converted.GetFormat())); + result["Orthanc"]["Compression"] = "Deflate"; + result["sizeInBytes"] = converted.GetSize(); + + std::string z; + CompressUsingDeflate(z, image.GetContext(), converted.GetConstBuffer(), converted.GetSize()); + + result["Orthanc"]["PixelData"] = base64_encode(z); + + return true; + } + + + + template <typename TargetType, typename SourceType> + static void ChangeDynamics(Orthanc::ImageAccessor& target, + const Orthanc::ImageAccessor& source, + SourceType source1, TargetType target1, + SourceType source2, TargetType target2) + { + if (source.GetWidth() != target.GetWidth() || + source.GetHeight() != target.GetHeight()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); + } + + float scale = static_cast<float>(target2 - target1) / static_cast<float>(source2 - source1); + float offset = static_cast<float>(target1) - scale * static_cast<float>(source1); + + const float minValue = static_cast<float>(std::numeric_limits<TargetType>::min()); + const float maxValue = static_cast<float>(std::numeric_limits<TargetType>::max()); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const SourceType* p = reinterpret_cast<const SourceType*>(source.GetConstRow(y)); + TargetType* q = reinterpret_cast<TargetType*>(target.GetRow(y)); + + for (unsigned int x = 0; x < source.GetWidth(); x++, p++, q++) + { + float v = (scale * static_cast<float>(*p)) + offset; + + if (v > maxValue) + { + *q = std::numeric_limits<TargetType>::max(); + } + else if (v < minValue) + { + *q = std::numeric_limits<TargetType>::min(); + } + else + { + *q = static_cast<TargetType>(boost::math::iround(v)); + } + } + } + } + + + bool DecodedImageAdapter::EncodeUsingJpeg(Json::Value& result, + OrthancImageWrapper& image, + uint8_t quality /* between 0 and 100 */) + { + Orthanc::ImageAccessor accessor; + accessor.AssignReadOnly(OrthancPlugins::Convert(image.GetFormat()), image.GetWidth(), + image.GetHeight(), image.GetPitch(), image.GetBuffer()); + + Orthanc::ImageBuffer buffer; + buffer.SetMinimalPitchForced(true); + + Orthanc::ImageAccessor converted; + + if (accessor.GetFormat() == Orthanc::PixelFormat_Grayscale8 || + accessor.GetFormat() == Orthanc::PixelFormat_RGB24) + { + result["Orthanc"]["Stretched"] = false; + converted = accessor; + } + else if (accessor.GetFormat() == Orthanc::PixelFormat_Grayscale16 || + accessor.GetFormat() == Orthanc::PixelFormat_SignedGrayscale16) + { + result["Orthanc"]["Stretched"] = true; + buffer.SetFormat(Orthanc::PixelFormat_Grayscale8); + buffer.SetWidth(accessor.GetWidth()); + buffer.SetHeight(accessor.GetHeight()); + converted = buffer.GetAccessor(); + + int64_t a, b; + Orthanc::ImageProcessing::GetMinMaxValue(a, b, accessor); + result["Orthanc"]["StretchLow"] = static_cast<int32_t>(a); + result["Orthanc"]["StretchHigh"] = static_cast<int32_t>(b); + + if (accessor.GetFormat() == Orthanc::PixelFormat_Grayscale16) + { + ChangeDynamics<uint8_t, uint16_t>(converted, accessor, a, 0, b, 255); + } + else + { + ChangeDynamics<uint8_t, int16_t>(converted, accessor, a, 0, b, 255); + } + } + else + { + return false; + } + + result["Orthanc"]["Compression"] = "Jpeg"; + result["sizeInBytes"] = converted.GetSize(); + + std::string jpeg; + WriteJpegToMemory(jpeg, image.GetContext(), converted, quality); + + result["Orthanc"]["PixelData"] = base64_encode(jpeg); + return true; + } }