# HG changeset patch # User Sebastien Jodogne # Date 1559026189 -7200 # Node ID 4fe4b221a31fa2444d449205c19750c0e95571df # Parent 907189734acd16a4fac956b11730bd67f11d5762 deprecating MessagingToolbox diff -r 907189734acd -r 4fe4b221a31f Applications/Generic/NativeStoneApplicationRunner.cpp --- a/Applications/Generic/NativeStoneApplicationRunner.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Applications/Generic/NativeStoneApplicationRunner.cpp Tue May 28 08:49:49 2019 +0200 @@ -25,7 +25,7 @@ #include "NativeStoneApplicationRunner.h" -#include "../../Framework/Toolbox/MessagingToolbox.h" +#include "../../Framework/Deprecated/Toolbox/MessagingToolbox.h" #include "../../Platforms/Generic/OracleWebService.h" #include "../../Platforms/Generic/OracleDelayedCallExecutor.h" #include "NativeStoneApplicationContext.h" @@ -180,7 +180,7 @@ { OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters); - if (!MessagingToolbox::CheckOrthancVersion(orthanc)) + if (!Deprecated::MessagingToolbox::CheckOrthancVersion(orthanc)) { LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of " << "Orthanc, please upgrade"; diff -r 907189734acd -r 4fe4b221a31f Applications/Sdl/SdlStoneApplicationRunner.cpp --- a/Applications/Sdl/SdlStoneApplicationRunner.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Applications/Sdl/SdlStoneApplicationRunner.cpp Tue May 28 08:49:49 2019 +0200 @@ -25,7 +25,6 @@ #include "SdlStoneApplicationRunner.h" -#include "../../Framework/Toolbox/MessagingToolbox.h" #include "../../Platforms/Generic/OracleWebService.h" #include "SdlEngine.h" diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Toolbox/MessagingToolbox.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/MessagingToolbox.cpp Tue May 28 08:49:49 2019 +0200 @@ -0,0 +1,456 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "MessagingToolbox.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace Deprecated +{ + namespace MessagingToolbox + { + static bool ParseVersion(std::string& version, + unsigned int& major, + unsigned int& minor, + unsigned int& patch, + const Json::Value& info) + { + if (info.type() != Json::objectValue || + !info.isMember("Version") || + info["Version"].type() != Json::stringValue) + { + return false; + } + + version = info["Version"].asString(); + if (version == "mainline") + { + // Some arbitrary high values Orthanc versions will never reach ;) + major = 999; + minor = 999; + patch = 999; + return true; + } + + std::vector tokens; + Orthanc::Toolbox::TokenizeString(tokens, version, '.'); + + if (tokens.size() != 2 && + tokens.size() != 3) + { + return false; + } + + int a, b, c; + try + { + a = boost::lexical_cast(tokens[0]); + b = boost::lexical_cast(tokens[1]); + + if (tokens.size() == 3) + { + c = boost::lexical_cast(tokens[2]); + } + else + { + c = 0; + } + } + catch (boost::bad_lexical_cast&) + { + return false; + } + + if (a < 0 || + b < 0 || + c < 0) + { + return false; + } + else + { + major = static_cast(a); + minor = static_cast(b); + patch = static_cast(c); + return true; + } + } + + + bool ParseJson(Json::Value& target, + const void* content, + size_t size) + { + Json::Reader reader; + return reader.parse(reinterpret_cast(content), + reinterpret_cast(content) + size, + target); + } + + void JsonToString(std::string& target, + const Json::Value& source) + { + Json::FastWriter writer; + target = writer.write(source); + } + + static void ParseJsonException(Json::Value& target, + const std::string& source) + { + Json::Reader reader; + if (!reader.parse(source, target)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + + + void RestApiGet(Json::Value& target, + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& uri) + { + std::string tmp; + orthanc.RestApiGet(tmp, uri); + ParseJsonException(target, tmp); + } + + + void RestApiPost(Json::Value& target, + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& uri, + const std::string& body) + { + std::string tmp; + orthanc.RestApiPost(tmp, uri, body); + ParseJsonException(target, tmp); + } + + + bool HasWebViewerInstalled(OrthancPlugins::IOrthancConnection& orthanc) + { + try + { + Json::Value json; + RestApiGet(json, orthanc, "/plugins/web-viewer"); + return json.type() == Json::objectValue; + } + catch (Orthanc::OrthancException&) + { + return false; + } + } + + + bool CheckOrthancVersion(OrthancPlugins::IOrthancConnection& orthanc) + { + Json::Value json; + std::string version; + unsigned int major, minor, patch; + + try + { + RestApiGet(json, orthanc, "/system"); + } + catch (Orthanc::OrthancException&) + { + LOG(ERROR) << "Cannot connect to your Orthanc server"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + if (!ParseVersion(version, major, minor, patch, json)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + LOG(WARNING) << "Version of the Orthanc core (must be above 1.3.1): " << version; + + // Stone is only compatible with Orthanc >= 1.3.1 + if (major < 1 || + (major == 1 && minor < 3) || + (major == 1 && minor == 3 && patch < 1)) + { + return false; + } + + try + { + RestApiGet(json, orthanc, "/plugins/web-viewer"); + } + catch (Orthanc::OrthancException&) + { + // The Web viewer is not installed, this is OK + LOG(WARNING) << "The Web viewer plugin is not installed, progressive download is disabled"; + return true; + } + + if (!ParseVersion(version, major, minor, patch, json)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + LOG(WARNING) << "Version of the Web viewer plugin (must be above 2.2): " << version; + + return (major >= 3 || + (major == 2 && minor >= 2)); + } + + + Orthanc::ImageAccessor* DecodeFrame(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instance, + unsigned int frame, + Orthanc::PixelFormat targetFormat) + { + std::string uri = ("instances/" + instance + "/frames/" + + boost::lexical_cast(frame)); + + std::string compressed; + + switch (targetFormat) + { + case Orthanc::PixelFormat_RGB24: + orthanc.RestApiGet(compressed, uri + "/preview"); + break; + + case Orthanc::PixelFormat_Grayscale16: + orthanc.RestApiGet(compressed, uri + "/image-uint16"); + break; + + case Orthanc::PixelFormat_SignedGrayscale16: + orthanc.RestApiGet(compressed, uri + "/image-int16"); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + std::auto_ptr result(new Orthanc::PngReader); + result->ReadFromMemory(compressed); + + if (targetFormat == Orthanc::PixelFormat_SignedGrayscale16) + { + if (result->GetFormat() == Orthanc::PixelFormat_Grayscale16) + { + result->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + } + + return result.release(); + } + + + Orthanc::ImageAccessor* DecodeJpegFrame(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instance, + unsigned int frame, + unsigned int quality, + Orthanc::PixelFormat targetFormat) + { + if (quality <= 0 || + quality > 100) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + // This requires the official Web viewer plugin to be installed! + std::string uri = ("web-viewer/instances/jpeg" + + boost::lexical_cast(quality) + + "-" + instance + "_" + + boost::lexical_cast(frame)); + + Json::Value encoded; + RestApiGet(encoded, orthanc, uri); + + if (encoded.type() != Json::objectValue || + !encoded.isMember("Orthanc") || + encoded["Orthanc"].type() != Json::objectValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + Json::Value& info = encoded["Orthanc"]; + if (!info.isMember("PixelData") || + !info.isMember("Stretched") || + !info.isMember("Compression") || + info["Compression"].type() != Json::stringValue || + info["PixelData"].type() != Json::stringValue || + info["Stretched"].type() != Json::booleanValue || + info["Compression"].asString() != "Jpeg") + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + bool isSigned = false; + bool isStretched = info["Stretched"].asBool(); + + if (info.isMember("IsSigned")) + { + if (info["IsSigned"].type() != Json::booleanValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + else + { + isSigned = info["IsSigned"].asBool(); + } + } + + std::string jpeg; + Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString()); + + std::auto_ptr reader(new Orthanc::JpegReader); + reader->ReadFromMemory(jpeg); + + if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image + { + if (targetFormat != Orthanc::PixelFormat_RGB24) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + if (isSigned || isStretched) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + else + { + return reader.release(); + } + } + + if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + if (!isStretched) + { + if (targetFormat != reader->GetFormat()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + return reader.release(); + } + + int32_t stretchLow = 0; + int32_t stretchHigh = 0; + + if (!info.isMember("StretchLow") || + !info.isMember("StretchHigh") || + info["StretchLow"].type() != Json::intValue || + info["StretchHigh"].type() != Json::intValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + stretchLow = info["StretchLow"].asInt(); + stretchHigh = info["StretchHigh"].asInt(); + + if (stretchLow < -32768 || + stretchHigh > 65535 || + (stretchLow < 0 && stretchHigh > 32767)) + { + // This range cannot be represented with a uint16_t or an int16_t + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + // Decode a grayscale JPEG 8bpp image coming from the Web viewer + std::auto_ptr image + (new Orthanc::Image(targetFormat, reader->GetWidth(), reader->GetHeight(), false)); + + float scaling = static_cast(stretchHigh - stretchLow) / 255.0f; + float offset = static_cast(stretchLow) / scaling; + + Orthanc::ImageProcessing::Convert(*image, *reader); + Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); + +#if 0 + /*info.removeMember("PixelData"); + std::cout << info.toStyledString();*/ + + int64_t a, b; + Orthanc::ImageProcessing::GetMinMaxValue(a, b, *image); + std::cout << stretchLow << "->" << stretchHigh << " = " << a << "->" << b << std::endl; +#endif + + return image.release(); + } + + + static void AddTag(Orthanc::DicomMap& target, + const OrthancPlugins::IDicomDataset& source, + const Orthanc::DicomTag& tag) + { + OrthancPlugins::DicomTag key(tag.GetGroup(), tag.GetElement()); + + std::string value; + if (source.GetStringValue(value, key)) + { + target.SetValue(tag, value, false); + } + } + + + void ConvertDataset(Orthanc::DicomMap& target, + const OrthancPlugins::IDicomDataset& source) + { + target.Clear(); + + AddTag(target, source, Orthanc::DICOM_TAG_BITS_ALLOCATED); + AddTag(target, source, Orthanc::DICOM_TAG_BITS_STORED); + AddTag(target, source, Orthanc::DICOM_TAG_COLUMNS); + AddTag(target, source, Orthanc::DICOM_TAG_DOSE_GRID_SCALING); + AddTag(target, source, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER); + AddTag(target, source, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); + AddTag(target, source, Orthanc::DICOM_TAG_HIGH_BIT); + AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT); + AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT); + AddTag(target, source, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES); + AddTag(target, source, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION); + AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION); + AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_SPACING); + AddTag(target, source, Orthanc::DICOM_TAG_PLANAR_CONFIGURATION); + AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_INTERCEPT); + AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_SLOPE); + AddTag(target, source, Orthanc::DICOM_TAG_ROWS); + AddTag(target, source, Orthanc::DICOM_TAG_SAMPLES_PER_PIXEL); + AddTag(target, source, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID); + AddTag(target, source, Orthanc::DICOM_TAG_SLICE_THICKNESS); + AddTag(target, source, Orthanc::DICOM_TAG_SOP_CLASS_UID); + AddTag(target, source, Orthanc::DICOM_TAG_SOP_INSTANCE_UID); + AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_CENTER); + AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_WIDTH); + } + } +} diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Toolbox/MessagingToolbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/MessagingToolbox.h Tue May 28 08:49:49 2019 +0200 @@ -0,0 +1,75 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../../StoneEnumerations.h" + +#include +#include +#include +#include + +#include + +namespace Deprecated +{ + namespace MessagingToolbox + { + bool ParseJson(Json::Value& target, + const void* content, + size_t size); + + void JsonToString(std::string& target, + const Json::Value& source); + + + void RestApiGet(Json::Value& target, + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& uri); + + void RestApiPost(Json::Value& target, + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& uri, + const std::string& body); + + bool HasWebViewerInstalled(OrthancPlugins::IOrthancConnection& orthanc); + + bool CheckOrthancVersion(OrthancPlugins::IOrthancConnection& orthanc); + + // This downloads the image from Orthanc and keeps its pixel + // format unchanged (will be either Grayscale8, Grayscale16, + // SignedGrayscale16, or RGB24) + Orthanc::ImageAccessor* DecodeFrame(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instance, + unsigned int frame, + Orthanc::PixelFormat targetFormat); + + Orthanc::ImageAccessor* DecodeJpegFrame(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instance, + unsigned int frame, + unsigned int quality, + Orthanc::PixelFormat targetFormat); + + void ConvertDataset(Orthanc::DicomMap& target, + const OrthancPlugins::IDicomDataset& source); + } +} diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Toolbox/OrthancApiClient.cpp --- a/Framework/Deprecated/Toolbox/OrthancApiClient.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp Tue May 28 08:49:49 2019 +0200 @@ -20,7 +20,7 @@ #include "OrthancApiClient.h" -#include "../../Toolbox/MessagingToolbox.h" +#include "../Toolbox/MessagingToolbox.h" #include @@ -139,7 +139,7 @@ else if (jsonHandler_.get() != NULL) { Json::Value response; - if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) + if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) { jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage (message.GetUri(), response, userPayload_.get())); @@ -270,7 +270,7 @@ Orthanc::IDynamicObject* payload) { std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); + MessagingToolbox::JsonToString(body, data); return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload); } @@ -279,7 +279,7 @@ const Json::Value& data) { std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); + MessagingToolbox::JsonToString(body, data); return PostBinaryAsync(uri, body); } @@ -291,7 +291,7 @@ Orthanc::IDynamicObject* payload /* takes ownership */) { std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); + MessagingToolbox::JsonToString(body, data); return PostBinaryAsync(uri, body, successCallback, failureCallback, payload); } diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp --- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Tue May 28 08:49:49 2019 +0200 @@ -21,7 +21,7 @@ #include "OrthancSlicesLoader.h" -#include "../../Toolbox/MessagingToolbox.h" +#include "../Toolbox/MessagingToolbox.h" #include #include @@ -231,7 +231,7 @@ OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]); Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + MessagingToolbox::ConvertDataset(dicom, dataset); unsigned int frames; if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) @@ -265,7 +265,7 @@ OrthancPlugins::FullOrthancDataset dataset(tags); Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + MessagingToolbox::ConvertDataset(dicom, dataset); unsigned int frames; if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) @@ -306,7 +306,7 @@ state_ = State_GeometryReady; Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + MessagingToolbox::ConvertDataset(dicom, dataset); std::auto_ptr slice(new Slice); if (slice->ParseOrthancFrame(dicom, instanceId, frame)) diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Volumes/StructureSetLoader.cpp --- a/Framework/Deprecated/Volumes/StructureSetLoader.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp Tue May 28 08:49:49 2019 +0200 @@ -21,7 +21,7 @@ #include "StructureSetLoader.h" -#include "../../Toolbox/MessagingToolbox.h" +#include "../Toolbox/MessagingToolbox.h" #include @@ -41,7 +41,7 @@ OrthancPlugins::FullOrthancDataset dataset(message.GetJson()); Orthanc::DicomMap slice; - OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset); + MessagingToolbox::ConvertDataset(slice, dataset); structureSet_->AddReferencedSlice(slice); BroadcastMessage(ContentChangedMessage(*this)); @@ -113,4 +113,47 @@ return *structureSet_; } } + + + OrthancStone::DicomStructureSet* StructureSetLoader::SynchronousLoad( + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instanceId) + { + const std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; + OrthancPlugins::FullOrthancDataset dataset(orthanc, uri); + + std::auto_ptr result + (new OrthancStone::DicomStructureSet(dataset)); + + std::set instances; + result->GetReferencedInstances(instances); + + for (std::set::const_iterator it = instances.begin(); + it != instances.end(); ++it) + { + Json::Value lookup; + MessagingToolbox::RestApiPost(lookup, orthanc, "/tools/lookup", *it); + + if (lookup.type() != Json::arrayValue || + lookup.size() != 1 || + !lookup[0].isMember("Type") || + !lookup[0].isMember("Path") || + lookup[0]["Type"].type() != Json::stringValue || + lookup[0]["ID"].type() != Json::stringValue || + lookup[0]["Type"].asString() != "Instance") + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); + } + + OrthancPlugins::FullOrthancDataset slice + (orthanc, "/instances/" + lookup[0]["ID"].asString() + "/tags"); + Orthanc::DicomMap m; + MessagingToolbox::ConvertDataset(m, slice); + result->AddReferencedSlice(m); + } + + result->CheckReferencedSlices(); + + return result.release(); + } } diff -r 907189734acd -r 4fe4b221a31f Framework/Deprecated/Volumes/StructureSetLoader.h --- a/Framework/Deprecated/Volumes/StructureSetLoader.h Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.h Tue May 28 08:49:49 2019 +0200 @@ -53,5 +53,9 @@ } OrthancStone::DicomStructureSet& GetStructureSet(); + + static OrthancStone::DicomStructureSet* SynchronousLoad( + OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instanceId); }; } diff -r 907189734acd -r 4fe4b221a31f Framework/Toolbox/DicomStructureSet.cpp --- a/Framework/Toolbox/DicomStructureSet.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Toolbox/DicomStructureSet.cpp Tue May 28 08:49:49 2019 +0200 @@ -22,7 +22,6 @@ #include "DicomStructureSet.h" #include "../Toolbox/GeometryToolbox.h" -#include "../Toolbox/MessagingToolbox.h" #include #include @@ -678,47 +677,6 @@ } - DicomStructureSet* DicomStructureSet::SynchronousLoad(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instanceId) - { - const std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; - OrthancPlugins::FullOrthancDataset dataset(orthanc, uri); - - std::auto_ptr result(new DicomStructureSet(dataset)); - - std::set instances; - result->GetReferencedInstances(instances); - - for (std::set::const_iterator it = instances.begin(); - it != instances.end(); ++it) - { - Json::Value lookup; - MessagingToolbox::RestApiPost(lookup, orthanc, "/tools/lookup", *it); - - if (lookup.type() != Json::arrayValue || - lookup.size() != 1 || - !lookup[0].isMember("Type") || - !lookup[0].isMember("Path") || - lookup[0]["Type"].type() != Json::stringValue || - lookup[0]["ID"].type() != Json::stringValue || - lookup[0]["Type"].asString() != "Instance") - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); - } - - OrthancPlugins::FullOrthancDataset slice - (orthanc, "/instances/" + lookup[0]["ID"].asString() + "/tags"); - Orthanc::DicomMap m; - MessagingToolbox::ConvertDataset(m, slice); - result->AddReferencedSlice(m); - } - - result->CheckReferencedSlices(); - - return result.release(); - } - - bool DicomStructureSet::ProjectStructure(std::vector< std::vector >& polygons, Structure& structure, const CoordinateSystem3D& slice) diff -r 907189734acd -r 4fe4b221a31f Framework/Toolbox/DicomStructureSet.h --- a/Framework/Toolbox/DicomStructureSet.h Tue May 28 08:29:24 2019 +0200 +++ b/Framework/Toolbox/DicomStructureSet.h Tue May 28 08:49:49 2019 +0200 @@ -170,10 +170,6 @@ Vector GetNormal() const; - // TODO - Remove - static DicomStructureSet* SynchronousLoad(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instanceId); - bool ProjectStructure(std::vector< std::vector >& polygons, size_t index, const CoordinateSystem3D& slice) diff -r 907189734acd -r 4fe4b221a31f Framework/Toolbox/MessagingToolbox.cpp --- a/Framework/Toolbox/MessagingToolbox.cpp Tue May 28 08:29:24 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,456 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - **/ - - -#include "MessagingToolbox.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace OrthancStone -{ - namespace MessagingToolbox - { - static bool ParseVersion(std::string& version, - unsigned int& major, - unsigned int& minor, - unsigned int& patch, - const Json::Value& info) - { - if (info.type() != Json::objectValue || - !info.isMember("Version") || - info["Version"].type() != Json::stringValue) - { - return false; - } - - version = info["Version"].asString(); - if (version == "mainline") - { - // Some arbitrary high values Orthanc versions will never reach ;) - major = 999; - minor = 999; - patch = 999; - return true; - } - - std::vector tokens; - Orthanc::Toolbox::TokenizeString(tokens, version, '.'); - - if (tokens.size() != 2 && - tokens.size() != 3) - { - return false; - } - - int a, b, c; - try - { - a = boost::lexical_cast(tokens[0]); - b = boost::lexical_cast(tokens[1]); - - if (tokens.size() == 3) - { - c = boost::lexical_cast(tokens[2]); - } - else - { - c = 0; - } - } - catch (boost::bad_lexical_cast&) - { - return false; - } - - if (a < 0 || - b < 0 || - c < 0) - { - return false; - } - else - { - major = static_cast(a); - minor = static_cast(b); - patch = static_cast(c); - return true; - } - } - - - bool ParseJson(Json::Value& target, - const void* content, - size_t size) - { - Json::Reader reader; - return reader.parse(reinterpret_cast(content), - reinterpret_cast(content) + size, - target); - } - - void JsonToString(std::string& target, - const Json::Value& source) - { - Json::FastWriter writer; - target = writer.write(source); - } - - static void ParseJsonException(Json::Value& target, - const std::string& source) - { - Json::Reader reader; - if (!reader.parse(source, target)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - } - - - void RestApiGet(Json::Value& target, - OrthancPlugins::IOrthancConnection& orthanc, - const std::string& uri) - { - std::string tmp; - orthanc.RestApiGet(tmp, uri); - ParseJsonException(target, tmp); - } - - - void RestApiPost(Json::Value& target, - OrthancPlugins::IOrthancConnection& orthanc, - const std::string& uri, - const std::string& body) - { - std::string tmp; - orthanc.RestApiPost(tmp, uri, body); - ParseJsonException(target, tmp); - } - - - bool HasWebViewerInstalled(OrthancPlugins::IOrthancConnection& orthanc) - { - try - { - Json::Value json; - RestApiGet(json, orthanc, "/plugins/web-viewer"); - return json.type() == Json::objectValue; - } - catch (Orthanc::OrthancException&) - { - return false; - } - } - - - bool CheckOrthancVersion(OrthancPlugins::IOrthancConnection& orthanc) - { - Json::Value json; - std::string version; - unsigned int major, minor, patch; - - try - { - RestApiGet(json, orthanc, "/system"); - } - catch (Orthanc::OrthancException&) - { - LOG(ERROR) << "Cannot connect to your Orthanc server"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - if (!ParseVersion(version, major, minor, patch, json)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - LOG(WARNING) << "Version of the Orthanc core (must be above 1.3.1): " << version; - - // Stone is only compatible with Orthanc >= 1.3.1 - if (major < 1 || - (major == 1 && minor < 3) || - (major == 1 && minor == 3 && patch < 1)) - { - return false; - } - - try - { - RestApiGet(json, orthanc, "/plugins/web-viewer"); - } - catch (Orthanc::OrthancException&) - { - // The Web viewer is not installed, this is OK - LOG(WARNING) << "The Web viewer plugin is not installed, progressive download is disabled"; - return true; - } - - if (!ParseVersion(version, major, minor, patch, json)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - LOG(WARNING) << "Version of the Web viewer plugin (must be above 2.2): " << version; - - return (major >= 3 || - (major == 2 && minor >= 2)); - } - - - Orthanc::ImageAccessor* DecodeFrame(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instance, - unsigned int frame, - Orthanc::PixelFormat targetFormat) - { - std::string uri = ("instances/" + instance + "/frames/" + - boost::lexical_cast(frame)); - - std::string compressed; - - switch (targetFormat) - { - case Orthanc::PixelFormat_RGB24: - orthanc.RestApiGet(compressed, uri + "/preview"); - break; - - case Orthanc::PixelFormat_Grayscale16: - orthanc.RestApiGet(compressed, uri + "/image-uint16"); - break; - - case Orthanc::PixelFormat_SignedGrayscale16: - orthanc.RestApiGet(compressed, uri + "/image-int16"); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - std::auto_ptr result(new Orthanc::PngReader); - result->ReadFromMemory(compressed); - - if (targetFormat == Orthanc::PixelFormat_SignedGrayscale16) - { - if (result->GetFormat() == Orthanc::PixelFormat_Grayscale16) - { - result->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - } - - return result.release(); - } - - - Orthanc::ImageAccessor* DecodeJpegFrame(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instance, - unsigned int frame, - unsigned int quality, - Orthanc::PixelFormat targetFormat) - { - if (quality <= 0 || - quality > 100) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - // This requires the official Web viewer plugin to be installed! - std::string uri = ("web-viewer/instances/jpeg" + - boost::lexical_cast(quality) + - "-" + instance + "_" + - boost::lexical_cast(frame)); - - Json::Value encoded; - RestApiGet(encoded, orthanc, uri); - - if (encoded.type() != Json::objectValue || - !encoded.isMember("Orthanc") || - encoded["Orthanc"].type() != Json::objectValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - Json::Value& info = encoded["Orthanc"]; - if (!info.isMember("PixelData") || - !info.isMember("Stretched") || - !info.isMember("Compression") || - info["Compression"].type() != Json::stringValue || - info["PixelData"].type() != Json::stringValue || - info["Stretched"].type() != Json::booleanValue || - info["Compression"].asString() != "Jpeg") - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - bool isSigned = false; - bool isStretched = info["Stretched"].asBool(); - - if (info.isMember("IsSigned")) - { - if (info["IsSigned"].type() != Json::booleanValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - else - { - isSigned = info["IsSigned"].asBool(); - } - } - - std::string jpeg; - Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString()); - - std::auto_ptr reader(new Orthanc::JpegReader); - reader->ReadFromMemory(jpeg); - - if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image - { - if (targetFormat != Orthanc::PixelFormat_RGB24) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - if (isSigned || isStretched) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - else - { - return reader.release(); - } - } - - if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - if (!isStretched) - { - if (targetFormat != reader->GetFormat()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - return reader.release(); - } - - int32_t stretchLow = 0; - int32_t stretchHigh = 0; - - if (!info.isMember("StretchLow") || - !info.isMember("StretchHigh") || - info["StretchLow"].type() != Json::intValue || - info["StretchHigh"].type() != Json::intValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - stretchLow = info["StretchLow"].asInt(); - stretchHigh = info["StretchHigh"].asInt(); - - if (stretchLow < -32768 || - stretchHigh > 65535 || - (stretchLow < 0 && stretchHigh > 32767)) - { - // This range cannot be represented with a uint16_t or an int16_t - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - // Decode a grayscale JPEG 8bpp image coming from the Web viewer - std::auto_ptr image - (new Orthanc::Image(targetFormat, reader->GetWidth(), reader->GetHeight(), false)); - - float scaling = static_cast(stretchHigh - stretchLow) / 255.0f; - float offset = static_cast(stretchLow) / scaling; - - Orthanc::ImageProcessing::Convert(*image, *reader); - Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); - -#if 0 - /*info.removeMember("PixelData"); - std::cout << info.toStyledString();*/ - - int64_t a, b; - Orthanc::ImageProcessing::GetMinMaxValue(a, b, *image); - std::cout << stretchLow << "->" << stretchHigh << " = " << a << "->" << b << std::endl; -#endif - - return image.release(); - } - - - static void AddTag(Orthanc::DicomMap& target, - const OrthancPlugins::IDicomDataset& source, - const Orthanc::DicomTag& tag) - { - OrthancPlugins::DicomTag key(tag.GetGroup(), tag.GetElement()); - - std::string value; - if (source.GetStringValue(value, key)) - { - target.SetValue(tag, value, false); - } - } - - - void ConvertDataset(Orthanc::DicomMap& target, - const OrthancPlugins::IDicomDataset& source) - { - target.Clear(); - - AddTag(target, source, Orthanc::DICOM_TAG_BITS_ALLOCATED); - AddTag(target, source, Orthanc::DICOM_TAG_BITS_STORED); - AddTag(target, source, Orthanc::DICOM_TAG_COLUMNS); - AddTag(target, source, Orthanc::DICOM_TAG_DOSE_GRID_SCALING); - AddTag(target, source, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER); - AddTag(target, source, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); - AddTag(target, source, Orthanc::DICOM_TAG_HIGH_BIT); - AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT); - AddTag(target, source, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT); - AddTag(target, source, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES); - AddTag(target, source, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION); - AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION); - AddTag(target, source, Orthanc::DICOM_TAG_PIXEL_SPACING); - AddTag(target, source, Orthanc::DICOM_TAG_PLANAR_CONFIGURATION); - AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_INTERCEPT); - AddTag(target, source, Orthanc::DICOM_TAG_RESCALE_SLOPE); - AddTag(target, source, Orthanc::DICOM_TAG_ROWS); - AddTag(target, source, Orthanc::DICOM_TAG_SAMPLES_PER_PIXEL); - AddTag(target, source, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID); - AddTag(target, source, Orthanc::DICOM_TAG_SLICE_THICKNESS); - AddTag(target, source, Orthanc::DICOM_TAG_SOP_CLASS_UID); - AddTag(target, source, Orthanc::DICOM_TAG_SOP_INSTANCE_UID); - AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_CENTER); - AddTag(target, source, Orthanc::DICOM_TAG_WINDOW_WIDTH); - } - } -} diff -r 907189734acd -r 4fe4b221a31f Framework/Toolbox/MessagingToolbox.h --- a/Framework/Toolbox/MessagingToolbox.h Tue May 28 08:29:24 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../StoneEnumerations.h" - -#include -#include -#include -#include - -#include - -namespace OrthancStone -{ - namespace MessagingToolbox - { - bool ParseJson(Json::Value& target, - const void* content, - size_t size); - - void JsonToString(std::string& target, - const Json::Value& source); - - - void RestApiGet(Json::Value& target, - OrthancPlugins::IOrthancConnection& orthanc, - const std::string& uri); - - void RestApiPost(Json::Value& target, - OrthancPlugins::IOrthancConnection& orthanc, - const std::string& uri, - const std::string& body); - - bool HasWebViewerInstalled(OrthancPlugins::IOrthancConnection& orthanc); - - bool CheckOrthancVersion(OrthancPlugins::IOrthancConnection& orthanc); - - // This downloads the image from Orthanc and keeps its pixel - // format unchanged (will be either Grayscale8, Grayscale16, - // SignedGrayscale16, or RGB24) - Orthanc::ImageAccessor* DecodeFrame(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instance, - unsigned int frame, - Orthanc::PixelFormat targetFormat); - - Orthanc::ImageAccessor* DecodeJpegFrame(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instance, - unsigned int frame, - unsigned int quality, - Orthanc::PixelFormat targetFormat); - - void ConvertDataset(Orthanc::DicomMap& target, - const OrthancPlugins::IDicomDataset& source); - } -} diff -r 907189734acd -r 4fe4b221a31f Platforms/Wasm/WasmPlatformApplicationAdapter.cpp --- a/Platforms/Wasm/WasmPlatformApplicationAdapter.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Platforms/Wasm/WasmPlatformApplicationAdapter.cpp Tue May 28 08:49:49 2019 +0200 @@ -1,6 +1,5 @@ #include "WasmPlatformApplicationAdapter.h" -#include "Framework/Toolbox/MessagingToolbox.h" #include "Framework/StoneException.h" #include #include "Platforms/Wasm/Defaults.h" @@ -57,4 +56,4 @@ } } -} \ No newline at end of file +} diff -r 907189734acd -r 4fe4b221a31f Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Tue May 28 08:29:24 2019 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue May 28 08:49:49 2019 +0200 @@ -330,6 +330,7 @@ ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/DownloadStack.cpp ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IWebService.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/MessagingToolbox.cpp ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancApiClient.cpp ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/Slice.cpp @@ -478,7 +479,6 @@ ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/MessagingToolbox.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlices.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlicesCursor.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp diff -r 907189734acd -r 4fe4b221a31f Samples/Sdl/Loader.cpp --- a/Samples/Sdl/Loader.cpp Tue May 28 08:29:24 2019 +0200 +++ b/Samples/Sdl/Loader.cpp Tue May 28 08:49:49 2019 +0200 @@ -1220,7 +1220,6 @@ { ImageBuffer3D& target = volume_->GetPixelData(); - const Orthanc::PixelFormat format = target.GetFormat(); const unsigned int bpp = target.GetBytesPerPixel(); const unsigned int width = target.GetWidth(); const unsigned int height = target.GetHeight(); @@ -1248,7 +1247,7 @@ for (unsigned int y = 0; y < height; y++) { - assert(sizeof(T) == Orthanc::GetBytesPerPixel(format)); + assert(sizeof(T) == Orthanc::GetBytesPerPixel(target.GetFormat())); T* target = reinterpret_cast(writer.GetAccessor().GetRow(y)); diff -r 907189734acd -r 4fe4b221a31f UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Tue May 28 08:29:24 2019 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Tue May 28 08:49:49 2019 +0200 @@ -23,10 +23,10 @@ #include "../Framework/Deprecated/Layers/FrameRenderer.h" #include "../Framework/Deprecated/Toolbox/DownloadStack.h" +#include "../Framework/Deprecated/Toolbox/MessagingToolbox.h" #include "../Framework/Deprecated/Toolbox/OrthancSlicesLoader.h" #include "../Framework/Toolbox/FiniteProjectiveCamera.h" #include "../Framework/Toolbox/GeometryToolbox.h" -#include "../Framework/Toolbox/MessagingToolbox.h" #include "../Framework/Volumes/ImageBuffer3D.h" #include "../Platforms/Generic/OracleWebService.h" @@ -636,7 +636,7 @@ { Json::Value response; std::string source = "{\"command\":\"panel:takeDarkImage\",\"commandType\":\"simple\",\"args\":{}}"; - ASSERT_TRUE(OrthancStone::MessagingToolbox::ParseJson(response, source.c_str(), source.size())); + ASSERT_TRUE(Deprecated::MessagingToolbox::ParseJson(response, source.c_str(), source.size())); } TEST(VolumeImageGeometry, Basic)