# HG changeset patch # User Sebastien Jodogne # Date 1575021821 -3600 # Node ID 54cbffabdc451017b051153bb1a481a94fc2a1d6 # Parent 4cc997207d8a50ed8f116a4ae887fc7ea4256831# Parent 922d2e61aa5d74bb8be701a8b4520561f2085d38 integration mainline->broker diff -r 4cc997207d8a -r 54cbffabdc45 Applications/Qt/QCairoWidget.cpp --- a/Applications/Qt/QCairoWidget.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Applications/Qt/QCairoWidget.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -185,6 +185,16 @@ break; } } + else if (keyChar == 127) + { + switch (event->key()) + { + CASE_QT_KEY_TO_ORTHANC(Qt::Key_Delete, KeyboardKeys_Delete); + CASE_QT_KEY_TO_ORTHANC(Qt::Key_Backspace, KeyboardKeys_Backspace); + default: + break; + } + } { OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_); diff -r 4cc997207d8a -r 54cbffabdc45 Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Applications/Samples/SingleFrameEditorApplication.h Fri Nov 29 11:03:41 2019 +0100 @@ -425,7 +425,6 @@ private: boost::shared_ptr scene_; RadiographyEditorInteractor interactor_; - Orthanc::FontRegistry fontRegistry_; RadiographyMaskLayer* maskLayer_; public: @@ -480,8 +479,6 @@ std::string instance = parameters["instance"].as(); //int frame = parameters["frame"].as(); - fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); - scene_.reset(new RadiographyScene); RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(*context->GetOrthancApiClient(), instance, 0, false, NULL); @@ -507,10 +504,11 @@ std::auto_ptr renderedTextAlpha(TextRenderer::Render(Orthanc::EmbeddedResources::UBUNTU_FONT, 100, "%öÇaA&#")); RadiographyLayer& layer = scene_->LoadAlphaBitmap(renderedTextAlpha.release(), NULL); - dynamic_cast(layer).SetForegroundValue(200); + dynamic_cast(layer).SetForegroundValue(200.0f * 256.0f); } { + RadiographyTextLayer::SetFont(Orthanc::EmbeddedResources::UBUNTU_FONT); RadiographyLayer& layer = scene_->LoadText("Hello\nworld", 20, 128, NULL); layer.SetResizeable(true); } diff -r 4cc997207d8a -r 54cbffabdc45 Applications/Sdl/SdlEngine.cpp --- a/Applications/Sdl/SdlEngine.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Applications/Sdl/SdlEngine.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -255,6 +255,10 @@ case SDLK_KP_MINUS: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '-', modifiers); break; + case SDLK_DELETE: + locker.GetCentralViewport().KeyPressed(KeyboardKeys_Delete, 0, modifiers); break; + case SDLK_BACKSPACE: + locker.GetCentralViewport().KeyPressed(KeyboardKeys_Backspace, 0, modifiers); break; case SDLK_RIGHT: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Right, 0, modifiers); break; case SDLK_LEFT: diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyAlphaLayer.cpp --- a/Framework/Radiography/RadiographyAlphaLayer.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyAlphaLayer.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -25,6 +25,7 @@ #include #include +#include "../Toolbox/ImageGeometry.h" namespace OrthancStone { @@ -51,7 +52,10 @@ void RadiographyAlphaLayer::Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const { if (alpha_.get() == NULL) { @@ -77,27 +81,37 @@ t.Apply(tmp, cropped, interpolation, true /* clear */); - // Blit - const unsigned int width = buffer.GetWidth(); - const unsigned int height = buffer.GetHeight(); + unsigned int x1, y1, x2, y2; + OrthancStone::GetProjectiveTransformExtent(x1, y1, x2, y2, + t.GetHomogeneousMatrix(), + cropped.GetWidth(), + cropped.GetHeight(), + buffer.GetWidth(), + buffer.GetHeight()); float value = foreground_; - if (useWindowing_) + if (!applyWindowing) // if applying the windowing, it means we are ie rendering the image for a realtime visualization -> the foreground_ value is the value we want to see on the screen -> don't change it { - float center, width; - if (GetScene().GetWindowing(center, width)) + // if not applying the windowing, it means ie that we are saving a dicom image to file and the windowing will be applied by a viewer later on -> we want the "foreground" value to be correct once the windowing will be applied + value = windowCenter - windowWidth/2 + (foreground_ / 65535.0f) * windowWidth; + + if (value < 0.0f) { - value = center + width / 2.0f; // set it to the maximum pixel value of the image + value = 0.0f; + } + if (value > 65535.0f) + { + value = 65535.0f; } } - for (unsigned int y = 0; y < height; y++) + for (unsigned int y = y1; y <= y2; y++) { - float *q = reinterpret_cast(buffer.GetRow(y)); - const uint8_t *p = reinterpret_cast(tmp.GetRow(y)); + float *q = reinterpret_cast(buffer.GetRow(y)) + x1; + const uint8_t *p = reinterpret_cast(tmp.GetRow(y)) + x1; - for (unsigned int x = 0; x < width; x++, p++, q++) + for (unsigned int x = x1; x <= x2; x++, p++, q++) { float a = static_cast(*p) / 255.0f; @@ -109,26 +123,19 @@ bool RadiographyAlphaLayer::GetRange(float& minValue, float& maxValue) const { - if (useWindowing_) - { - return false; - } - else - { - minValue = 0; - maxValue = 0; + minValue = 0; + maxValue = 0; - if (foreground_ < 0) - { - minValue = foreground_; - } + if (foreground_ < 0) + { + minValue = foreground_; + } - if (foreground_ > 0) - { - maxValue = foreground_; - } + if (foreground_ > 0) + { + maxValue = foreground_; + } - return true; - } + return true; } } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyAlphaLayer.h --- a/Framework/Radiography/RadiographyAlphaLayer.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyAlphaLayer.h Fri Nov 29 11:03:41 2019 +0100 @@ -33,14 +33,12 @@ class RadiographyAlphaLayer : public RadiographyLayer { private: - std::auto_ptr alpha_; // Grayscale8 - bool useWindowing_; - float foreground_; + std::auto_ptr alpha_; // Grayscale8 in the range [0, 255] 0 = transparent, 255 = opaque -> the foreground value will be displayed + float foreground_; // in the range [0.0, 65535.0] public: RadiographyAlphaLayer(const RadiographyScene& scene) : RadiographyLayer(scene), - useWindowing_(true), foreground_(0) { } @@ -48,7 +46,6 @@ void SetForegroundValue(float foreground) { - useWindowing_ = false; foreground_ = foreground; } @@ -57,11 +54,6 @@ return foreground_; } - bool IsUsingWindowing() const - { - return useWindowing_; - } - void SetAlpha(Orthanc::ImageAccessor* image); virtual bool GetDefaultWindowing(float& center, @@ -73,7 +65,10 @@ virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const; + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const; virtual bool GetRange(float& minValue, float& maxValue) const; diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyDicomLayer.cpp --- a/Framework/Radiography/RadiographyDicomLayer.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyDicomLayer.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include "../Toolbox/ImageGeometry.h" static OrthancPlugins::DicomTag ConvertTag(const Orthanc::DicomTag& tag) { @@ -139,7 +140,10 @@ void RadiographyDicomLayer::Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const { if (converted_.get() != NULL) { @@ -159,6 +163,47 @@ converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); t.Apply(buffer, cropped, interpolation, false); + unsigned int x1, y1, x2, y2; + OrthancStone::GetProjectiveTransformExtent(x1, y1, x2, y2, + t.GetHomogeneousMatrix(), + cropped.GetWidth(), + cropped.GetHeight(), + buffer.GetWidth(), + buffer.GetHeight()); + + if (applyWindowing) + { + // apply windowing but stay in the range [0.0, 65535.0] + float w0 = windowCenter - windowWidth / 2.0f; + float w1 = windowCenter + windowWidth / 2.0f; + + if (windowWidth >= 0.001f) // Avoid division by zero at (*) + { + float scaling = 1.0f / (w1 - w0) * 65535.0f; + for (unsigned int y = y1; y <= y2; y++) + { + float* p = reinterpret_cast(buffer.GetRow(y)) + x1; + + for (unsigned int x = x1; x <= x2; x++, p++) + { + if (*p >= w1) + { + *p = 65535.0; + } + else if (*p <= w0) + { + *p = 0; + } + else + { + // https://en.wikipedia.org/wiki/Linear_interpolation + *p = scaling * (*p - w0); // (*) + } + } + } + } + } + } } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyDicomLayer.h --- a/Framework/Radiography/RadiographyDicomLayer.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyDicomLayer.h Fri Nov 29 11:03:41 2019 +0100 @@ -91,7 +91,10 @@ virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const; + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const; virtual bool GetDefaultWindowing(float& center, float& width) const; diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyLayer.h --- a/Framework/Radiography/RadiographyLayer.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyLayer.h Fri Nov 29 11:03:41 2019 +0100 @@ -350,7 +350,10 @@ virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const = 0; + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const = 0; virtual bool GetRange(float& minValue, float& maxValue) const = 0; diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyMaskLayer.cpp --- a/Framework/Radiography/RadiographyMaskLayer.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyMaskLayer.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -26,10 +26,11 @@ #include "Core/Images/Image.h" #include "Core/Images/ImageProcessing.h" #include +#include "../Toolbox/ImageGeometry.h" namespace OrthancStone { - const unsigned char IN_MASK_VALUE = 0x00; + const unsigned char IN_MASK_VALUE = 0x77; const unsigned char OUT_MASK_VALUE = 0xFF; const AffineTransform2D& RadiographyMaskLayer::GetTransform() const @@ -76,7 +77,10 @@ void RadiographyMaskLayer::Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const { if (dicomLayer_.GetWidth() == 0) // nothing to do if the DICOM layer is not displayed (or not loaded) return; @@ -108,20 +112,36 @@ Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false); - t.Apply(tmp, cropped, interpolation, true /* clear */); + t.Apply(tmp, cropped, ImageInterpolation_Nearest, true /* clear */); + + unsigned int x1, y1, x2, y2; + OrthancStone::GetProjectiveTransformExtent(x1, y1, x2, y2, + t.GetHomogeneousMatrix(), + cropped.GetWidth(), + cropped.GetHeight(), + buffer.GetWidth(), + buffer.GetHeight()); + + // we have observed vertical lines at the image border (probably due to bilinear filtering of the DICOM image when it is not aligned with the buffer pixels) + // -> draw the mask one line further on each side + if (x1 >= 1) + { + x1 = x1 - 1; + } + if (x2 < buffer.GetWidth() - 2) + { + x2 = x2 + 1; + } // Blit - const unsigned int width = buffer.GetWidth(); - const unsigned int height = buffer.GetHeight(); - - for (unsigned int y = 0; y < height; y++) + for (unsigned int y = y1; y <= y2; y++) { - float *q = reinterpret_cast(buffer.GetRow(y)); - const uint8_t *p = reinterpret_cast(tmp.GetRow(y)); + float *q = reinterpret_cast(buffer.GetRow(y)) + x1; + const uint8_t *p = reinterpret_cast(tmp.GetRow(y)) + x1; - for (unsigned int x = 0; x < width; x++, p++, q++) + for (unsigned int x = x1; x <= x2; x++, p++, q++) { - if (*p == OUT_MASK_VALUE) + if (*p != IN_MASK_VALUE) *q = foreground_; // else keep the underlying pixel value } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyMaskLayer.h --- a/Framework/Radiography/RadiographyMaskLayer.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyMaskLayer.h Fri Nov 29 11:03:41 2019 +0100 @@ -76,7 +76,10 @@ virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const; + ImageInterpolation interpolation, + float windowCenter, + float windowWidth, + bool applyWindowing) const; std::string GetInstanceId() const; diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyScene.cpp --- a/Framework/Radiography/RadiographyScene.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyScene.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -134,9 +134,7 @@ std::auto_ptr raii(layer); - // LOG(INFO) << "Registering layer: " << countLayers_; - - size_t index = countLayers_++; + size_t index = nextLayerIndex_++; raii->SetIndex(index); layers_[index] = raii.release(); @@ -162,8 +160,9 @@ BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin())); } + RadiographyScene::RadiographyScene() : - countLayers_(0), + nextLayerIndex_(0), hasWindowing_(false), windowingCenter_(0), // Dummy initialization windowingWidth_(0) // Dummy initialization @@ -219,9 +218,8 @@ delete found->second; layers_.erase(found); - countLayers_--; - LOG(INFO) << "Removing layer, there are now : " << countLayers_ << " layers"; + LOG(INFO) << "Removing layer, there are now : " << layers_.size() << " layers"; BroadcastMessage(RadiographyScene::LayerRemovedMessage(*this, layerIndex)); } @@ -281,7 +279,7 @@ RadiographyLayer& RadiographyScene::LoadText(const std::string& utf8, - size_t fontSize, + unsigned int fontSize, uint8_t foreground, RadiographyLayer::Geometry* geometry) { @@ -292,7 +290,10 @@ alpha->SetGeometry(*geometry); } - return RegisterLayer(alpha.release()); + RadiographyLayer& registeredLayer = RegisterLayer(alpha.release()); + + BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, registeredLayer)); + return registeredLayer; } @@ -507,16 +508,17 @@ void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const + ImageInterpolation interpolation, + bool applyWindowing) const { // Render layers in the background-to-foreground order - for (size_t index = 0; index < countLayers_; index++) + for (size_t index = 0; index < nextLayerIndex_; index++) { Layers::const_iterator it = layers_.find(index); if (it != layers_.end()) { assert(it->second != NULL); - it->second->Render(buffer, viewTransform, interpolation); + it->second->Render(buffer, viewTransform, interpolation, windowingCenter_, windowingWidth_, applyWindowing); } } } @@ -527,7 +529,7 @@ double y) const { // Render layers in the foreground-to-background order - for (size_t i = countLayers_; i > 0; i--) + for (size_t i = nextLayerIndex_; i > 0; i--) { index = i - 1; Layers::const_iterator it = layers_.find(index); @@ -597,7 +599,8 @@ double pixelSpacingY, ImageInterpolation interpolation, bool invert, - int64_t maxValue /* for inversion */) + int64_t maxValue /* for inversion */, + bool applyWindowing) { if (pixelSpacingX <= 0 || pixelSpacingY <= 0) @@ -626,7 +629,7 @@ // wipe background before rendering Orthanc::ImageProcessing::Set(layers, 0); - Render(layers, view, interpolation); + Render(layers, view, interpolation, applyWindowing); std::auto_ptr rendered(new Orthanc::Image(Orthanc::PixelFormat_Grayscale16, layers.GetWidth(), layers.GetHeight(), false)); @@ -649,7 +652,7 @@ { LOG(INFO) << "Exporting RadiographyScene to DICOM"; - std::auto_ptr rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags + std::auto_ptr rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags createDicomRequestContent["Tags"] = dicomTags; diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyScene.h --- a/Framework/Radiography/RadiographyScene.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyScene.h Fri Nov 29 11:03:41 2019 +0100 @@ -162,7 +162,7 @@ protected: typedef std::map Layers; - size_t countLayers_; + size_t nextLayerIndex_; bool hasWindowing_; float windowingCenter_; float windowingWidth_; @@ -199,7 +199,7 @@ RadiographyPhotometricDisplayMode GetPreferredPhotomotricDisplayMode() const; RadiographyLayer& LoadText(const std::string& utf8, - size_t fontSize, + unsigned int fontSize, uint8_t foreground, RadiographyLayer::Geometry* geometry); @@ -288,7 +288,8 @@ virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const; + ImageInterpolation interpolation, + bool applyWindowing) const; bool LookupLayer(size_t& index /* out */, double x, @@ -340,15 +341,17 @@ Orthanc::Image* ExportToImage(double pixelSpacingX, double pixelSpacingY, - ImageInterpolation interpolation) + ImageInterpolation interpolation, + bool applyWindowing) { - return ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false, 0); + return ExportToImage(pixelSpacingX, pixelSpacingY, interpolation, false, 0, applyWindowing); } Orthanc::Image* ExportToImage(double pixelSpacingX, double pixelSpacingY, ImageInterpolation interpolation, bool invert, - int64_t maxValue /* for inversion */); + int64_t maxValue /* for inversion */, + bool applyWindowing); // i.e.: when }; } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographySceneWriter.cpp --- a/Framework/Radiography/RadiographySceneWriter.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographySceneWriter.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -97,7 +97,6 @@ Orthanc::Toolbox::EncodeDataUriScheme(pngContentBase64, "image/png", pngContent); output["content"] = pngContentBase64; output["foreground"] = layer.GetForegroundValue(); - output["isUsingWindowing"] = layer.IsUsingWindowing(); } void RadiographySceneWriter::WriteLayer(Json::Value& output, const RadiographyLayer& layer) diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyTextLayer.cpp --- a/Framework/Radiography/RadiographyTextLayer.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyTextLayer.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -30,7 +30,7 @@ Orthanc::EmbeddedResources::FileResourceId RadiographyTextLayer::fontResourceId_; void RadiographyTextLayer::LoadText(const std::string& utf8, - size_t fontSize, + unsigned int fontSize, uint8_t foreground) { if (!fontHasBeenConfigured_) @@ -45,5 +45,6 @@ SetAlpha(TextRenderer::Render(fontResourceId_, fontSize_, text_)); + SetForegroundValue(foreground * 256.0f); } } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyTextLayer.h --- a/Framework/Radiography/RadiographyTextLayer.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyTextLayer.h Fri Nov 29 11:03:41 2019 +0100 @@ -31,7 +31,7 @@ { private: std::string text_; - size_t fontSize_; + unsigned int fontSize_; uint8_t foreground_; static bool fontHasBeenConfigured_; @@ -42,14 +42,14 @@ { } - void LoadText(const std::string& utf8, size_t fontSize, uint8_t foreground); + void LoadText(const std::string& utf8, unsigned int fontSize, uint8_t foreground); const std::string& GetText() const { return text_; } - size_t GetFontSize() const + unsigned int GetFontSize() const { return fontSize_; } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyWidget.cpp --- a/Framework/Radiography/RadiographyWidget.cpp Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyWidget.cpp Fri Nov 29 11:03:41 2019 +0100 @@ -70,83 +70,66 @@ unsigned int height, ImageInterpolation interpolation) { - float windowCenter, windowWidth; - scene_->GetWindowingWithDefault(windowCenter, windowWidth); - - float x0 = windowCenter - windowWidth / 2.0f; - float x1 = windowCenter + windowWidth / 2.0f; + if (floatBuffer_.get() == NULL || + floatBuffer_->GetWidth() != width || + floatBuffer_->GetHeight() != height) + { + floatBuffer_.reset(new Orthanc::Image( + Orthanc::PixelFormat_Float32, width, height, false)); + } - if (windowWidth <= 0.001f) // Avoid division by zero at (*) - { - return false; - } - else + if (cairoBuffer_.get() == NULL || + cairoBuffer_->GetWidth() != width || + cairoBuffer_->GetHeight() != height) { - if (floatBuffer_.get() == NULL || - floatBuffer_->GetWidth() != width || - floatBuffer_->GetHeight() != height) - { - floatBuffer_.reset(new Orthanc::Image( - Orthanc::PixelFormat_Float32, width, height, false)); - } + cairoBuffer_.reset(new CairoSurface(width, height, false /* no alpha */)); + } + + RenderBackground(*floatBuffer_, 0.0, 65535.0); + + scene_->Render(*floatBuffer_, GetView().GetMatrix(), interpolation, true); - if (cairoBuffer_.get() == NULL || - cairoBuffer_->GetWidth() != width || - cairoBuffer_->GetHeight() != height) - { - cairoBuffer_.reset(new CairoSurface(width, height, false /* no alpha */)); - } - - RenderBackground(*floatBuffer_, x0, x1); + // Conversion from Float32 to BGRA32 (cairo). Very similar to + // GrayscaleFrameRenderer => TODO MERGE? + Orthanc::ImageAccessor target; + cairoBuffer_->GetWriteableAccessor(target); - scene_->Render(*floatBuffer_, GetView().GetMatrix(), interpolation); - - // Conversion from Float32 to BGRA32 (cairo). Very similar to - // GrayscaleFrameRenderer => TODO MERGE? - - Orthanc::ImageAccessor target; - cairoBuffer_->GetWriteableAccessor(target); - - float scaling = 255.0f / (x1 - x0); + bool invert = IsInvertedInternal(); - bool invert = IsInvertedInternal(); + for (unsigned int y = 0; y < height; y++) + { + const float* p = reinterpret_cast(floatBuffer_->GetConstRow(y)); + uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int y = 0; y < height; y++) + for (unsigned int x = 0; x < width; x++, p++, q += 4) { - const float* p = reinterpret_cast(floatBuffer_->GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++, q += 4) + uint8_t v = 0; + if (*p >= 65535.0) + { + v = 255; + } + else if (*p <= 0.0) { - uint8_t v = 0; - if (*p >= x1) - { - v = 255; - } - else if (*p <= x0) - { - v = 0; - } - else - { - // https://en.wikipedia.org/wiki/Linear_interpolation - v = static_cast(scaling * (*p - x0)); // (*) - } + v = 0; + } + else + { + v = static_cast(*p / 256.0); + } - if (invert) - { - v = 255 - v; - } + if (invert) + { + v = 255 - v; + } - q[0] = v; - q[1] = v; - q[2] = v; - q[3] = 255; - } + q[0] = v; + q[1] = v; + q[2] = v; + q[3] = 255; } + } - return true; - } + return true; } @@ -199,34 +182,6 @@ selectedLayer_ = layer; } - void RadiographyWidget::ClearSelectedLayer() - { - hasSelection_ = false; - } - - bool RadiographyWidget::SelectMaskLayer(size_t index) - { - std::vector layerIndexes; - size_t count = 0; - scene_->GetLayersIndexes(layerIndexes); - - for (size_t i = 0; i < layerIndexes.size(); ++i) - { - const RadiographyMaskLayer* maskLayer = dynamic_cast(&(scene_->GetLayer(layerIndexes[i]))); - if (maskLayer != NULL) - { - if (count == index) - { - Select(layerIndexes[i]); - return true; - } - count++; - } - } - - return false; - } - bool RadiographyWidget::LookupSelectedLayer(size_t& layer) { if (hasSelection_) @@ -259,8 +214,9 @@ size_t removedLayerIndex = message.GetLayerIndex(); if (hasSelection_ && selectedLayer_ == removedLayerIndex) { - ClearSelectedLayer(); + Unselect(); } + NotifyContentChanged(); } void RadiographyWidget::SetInvert(bool invert) diff -r 4cc997207d8a -r 54cbffabdc45 Framework/Radiography/RadiographyWidget.h --- a/Framework/Radiography/RadiographyWidget.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/Radiography/RadiographyWidget.h Fri Nov 29 11:03:41 2019 +0100 @@ -71,16 +71,14 @@ void SetScene(boost::shared_ptr scene); + void Select(size_t layer); + void Unselect() { hasSelection_ = false; } - void Select(size_t layer); - - void ClearSelectedLayer(); - - bool SelectMaskLayer(size_t index = 0); + template bool SelectLayerByType(size_t index = 0); bool LookupSelectedLayer(size_t& layer); @@ -106,4 +104,27 @@ return interpolation_; } }; + + template bool RadiographyWidget::SelectLayerByType(size_t index) + { + std::vector layerIndexes; + size_t count = 0; + scene_->GetLayersIndexes(layerIndexes); + + for (size_t i = 0; i < layerIndexes.size(); ++i) + { + const LayerType* typedLayer = dynamic_cast(&(scene_->GetLayer(layerIndexes[i]))); + if (typedLayer != NULL) + { + if (count == index) + { + Select(layerIndexes[i]); + return true; + } + count++; + } + } + + return false; + } } diff -r 4cc997207d8a -r 54cbffabdc45 Framework/StoneEnumerations.h --- a/Framework/StoneEnumerations.h Thu Nov 28 17:13:33 2019 +0100 +++ b/Framework/StoneEnumerations.h Fri Nov 29 11:03:41 2019 +0100 @@ -95,10 +95,12 @@ KeyboardKeys_Generic = 0, // let's use the same ids as in javascript to avoid some conversion in WASM: https://css-tricks.com/snippets/javascript/javascript-keycodes/ + KeyboardKeys_Backspace = 8, KeyboardKeys_Left = 37, KeyboardKeys_Up = 38, KeyboardKeys_Right = 39, - KeyboardKeys_Down = 40 + KeyboardKeys_Down = 40, + KeyboardKeys_Delete = 46 }; enum SopClassUid