Mercurial > hg > orthanc-stone
changeset 2222:22975e748165
added configuration options "AnnotationsColor" and "HighlightedAnnotationsColor"
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 23 Apr 2025 13:14:42 +0200 (7 days ago) |
parents | 900fb75351cd |
children | e928629d7df0 |
files | Applications/StoneWebViewer/NEWS Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/configuration.json Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h |
diffstat | 6 files changed, 248 insertions(+), 91 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/NEWS Wed Apr 23 09:31:59 2025 +0200 +++ b/Applications/StoneWebViewer/NEWS Wed Apr 23 13:14:42 2025 +0200 @@ -3,10 +3,12 @@ * Experimental support for DICOM SR "Measurement Report" (TID 1500 - only polylines) * Added "Print" and "Download" buttons in the PDF viewer toolbar -* New configuration "ScreenshotTemplate" to define the filename generated by the - "Download as JPEG" button. New default value is: +* New configuration option "ScreenshotTemplate" to define the filename + generated by the "Download as JPEG" button. New default value is: "{PatientID}-{PatientName}-{StudyDate}-{SeriesDescription}-{InstanceNumber}-{CurrentFrame}.jpg" * Remember the previous layout when re-opening the viewer +* New configuration options "AnnotationsColor" and "HighlightedAnnotationsColor" + to change the color of annotations Maintenance -----------
--- a/Applications/StoneWebViewer/WebApplication/app.js Wed Apr 23 09:31:59 2025 +0200 +++ b/Applications/StoneWebViewer/WebApplication/app.js Wed Apr 23 13:14:42 2025 +0200 @@ -1610,6 +1610,16 @@ alert('Bad value for option "ShowInfoPanelAtStartup": ' + app.globalConfiguration.ShowInfoPanelAtStartup); } + var color = app.globalConfiguration['AnnotationsColor']; + if (color !== undefined) { + stone.SetAnnotationsColor(color[0], color[1], color[2]); + } + + color = app.globalConfiguration['HighlightedAnnotationsColor']; + if (color !== undefined) { + stone.SetHighlightedAnnotationsColor(color[0], color[1], color[2]); + } + console.warn('Stone properly initialized'); app.stoneWebViewerVersion = stone.GetStoneWebViewerVersion();
--- a/Applications/StoneWebViewer/WebApplication/configuration.json Wed Apr 23 09:31:59 2025 +0200 +++ b/Applications/StoneWebViewer/WebApplication/configuration.json Wed Apr 23 13:14:42 2025 +0200 @@ -151,18 +151,28 @@ /* "Authorization" : "Bearer ${USER}" */ }, + /** + * Color that is used to draw the annotations, as a RGB + * triple. (New in Stone Web viewer 2.7) + **/ + "AnnotationsColor" : [ 64, 130, 173 ], + + /** + * Color that is used to draw highlighted annotations, as a RGB + * triple. (New in Stone Web viewer 2.7) + **/ + "HighlightedAnnotationsColor" : [ 64, 173, 121 ], /** - * Define the the filename of the 'Download as Jpeg' screenshots. - * The template can either contain Patient, Study or Series tags + * Define the the filename of the "Download as JPEG" screenshots. + * The template can either contain Patient, Study or Series tags * in the group,element form (e.g. {0008,103e}) or the DICOM tag - * common name (e.g. {SeriesDescription}). A few Instance tags are + * common name (e.g. {SeriesDescription}). Some instance tags are * also available: {InstanceNumber}, {ContentDate}, {ContentTime}. - * {CurrentFrame} is also available although not a DICOM Tag. - * (New in Stone Web viewer 2.7). In prior versions, the filename - * was always "StoneWebViewerScreenshot.jpg". + * {CurrentFrame} is also available although not a DICOM tag. In + * prior versions, the filename was always + * "StoneWebViewerScreenshot.jpg". (New in Stone Web viewer 2.7) **/ "ScreenshotTemplate" : "{PatientID}-{PatientName}-{StudyDate}-{SeriesDescription}-{InstanceNumber}-{CurrentFrame}.jpg" - } }
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Apr 23 09:31:59 2025 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Apr 23 13:14:42 2025 +0200 @@ -405,6 +405,12 @@ } } + static OrthancStone::Color& GetColorInternal() + { + static OrthancStone::Color color_(0, 255, 0); // Default color: green + return color_; + } + public: DicomStructuredReportFrames(const OrthancStone::DicomStructuredReport& sr, const OrthancStone::LoadedDicomResources& instances) : @@ -512,10 +518,9 @@ structure.GetFrameNumber() == frameNumber)) { #if 1 - // Default color: green - const OrthancStone::Color color(0, 255, 0); + const OrthancStone::Color& color = GetColorInternal(); #else - OrthancStone::Color color(0, 0, 255); + OrthancStone::Color color(GetColorInternal()); if (structure.HasProbabilityOfCancer()) { @@ -566,6 +571,17 @@ return layer.release(); } + + + static const OrthancStone::Color& GetAnnotationsColor() + { + return GetColorInternal(); + } + + static void SetAnnotationsColor(const OrthancStone::Color& color) + { + GetColorInternal() = color; + } }; @@ -3210,6 +3226,8 @@ stoneAnnotations_.reset(new OrthancStone::AnnotationsSceneLayer(LAYER_ANNOTATIONS_STONE)); stoneAnnotations_->SetProbedLayer(LAYER_TEXTURE); + stoneAnnotations_->SetColor(GetAnnotationsColorInternal()); + stoneAnnotations_->SetHoverColor(GetHighlightedColorInternal()); } @@ -3347,6 +3365,18 @@ } } + static OrthancStone::Color& GetAnnotationsColorInternal() + { + static OrthancStone::Color color_; + return color_; + } + + static OrthancStone::Color& GetHighlightedColorInternal() + { + static OrthancStone::Color color_; + return color_; + } + public: virtual ~ViewerViewport() { @@ -4169,6 +4199,18 @@ { return pendingSeriesInstanceUid_; } + + + static void SetAnnotationsColor(const OrthancStone::Color& color) + { + GetAnnotationsColorInternal() = color; + } + + + static void SetHighlightedColor(const OrthancStone::Color& color) + { + GetHighlightedColorInternal() = color; + } }; @@ -4240,13 +4282,24 @@ private: // The coordinates of OsiriX annotations are expressed in 3D world coordinates OrthancStone::OsiriX::CollectionOfAnnotations annotations_; + OrthancStone::Color color_; public: + OsiriXLayerSource() : + color_(0, 255, 0) + { + } + OrthancStone::OsiriX::CollectionOfAnnotations& GetAnnotations() { return annotations_; } + void SetColor(const OrthancStone::Color& color) + { + color_ = color; + } + virtual int GetDepth() const ORTHANC_OVERRIDE { return LAYER_ANNOTATIONS_OSIRIX; @@ -4268,7 +4321,7 @@ // layer->Reserve(a.size()); OrthancStone::OsiriXLayerFactory factory; - factory.SetColor(0, 255, 0); + factory.SetColor(color_); for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) { @@ -4754,6 +4807,21 @@ }; + +static void SetAnnotationsColor(const OrthancStone::Color& color) +{ + ViewerViewport::SetAnnotationsColor(color); + DicomStructuredReportFrames::SetAnnotationsColor(color); + osiriXLayerSource_->SetColor(color); +} + + +static void SetHighlightedColor(const OrthancStone::Color& color) +{ + ViewerViewport::SetHighlightedColor(color); +} + + extern "C" { int main(int argc, char const *argv[]) @@ -4774,6 +4842,9 @@ osiriXLayerSource_.reset(new OsiriXLayerSource); orientationMarkersSource_.reset(new OrientationMarkersSource); + SetAnnotationsColor(OrthancStone::Color(0x40, 0x82, 0xad)); // This was COLOR_PRIMITIVES until 2.6 + SetHighlightedColor(OrthancStone::Color(0x40, 0xad, 0x79)); // This was COLOR_HOVER until 2.6 + for (size_t i = 0; pluginsInitializers_[i] != NULL; i++) { std::unique_ptr<IStoneWebViewerPlugin> plugin(pluginsInitializers_[i] (StoneWebViewerContext::GetInstance())); @@ -5557,6 +5628,34 @@ EMSCRIPTEN_KEEPALIVE + void SetAnnotationsColor(int red, + int green, + int blue) + { + try + { + OrthancStone::Color color(red, green, blue); + SetAnnotationsColor(color); + } + EXTERN_CATCH_EXCEPTIONS; + } + + + EMSCRIPTEN_KEEPALIVE + void SetHighlightedAnnotationsColor(int red, + int green, + int blue) + { + try + { + OrthancStone::Color color(red, green, blue); + SetHighlightedColor(color); + } + EXTERN_CATCH_EXCEPTIONS; + } + + + EMSCRIPTEN_KEEPALIVE void *Allocate(size_t size) { return malloc(size);
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Apr 23 09:31:59 2025 +0200 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Apr 23 13:14:42 2025 +0200 @@ -64,18 +64,92 @@ static const char* const VALUE_TEXT_ANNOTATION = "text"; #if 0 -static OrthancStone::Color COLOR_PRIMITIVES(192, 192, 192); -static OrthancStone::Color COLOR_HOVER(0, 255, 0); -static OrthancStone::Color COLOR_TEXT(255, 0, 0); -#else +// Color codes that were used in Stone Web viewer <= 2.6 static OrthancStone::Color COLOR_PRIMITIVES(0x40, 0x82, 0xad); static OrthancStone::Color COLOR_HOVER(0x40, 0xad, 0x79); -static OrthancStone::Color COLOR_TEXT(0x4e, 0xde, 0x99); +static OrthancStone::Color COLOR_TEXT(0x4e, 0xde, 0x99); // This was replaced by COLOR_HOVER in 2.7 #endif namespace OrthancStone { + class AnnotationsSceneLayer::Annotation : public boost::noncopyable + { + private: + typedef std::list<GeometricPrimitive*> GeometricPrimitives; + + AnnotationsSceneLayer& that_; + GeometricPrimitives primitives_; + Color color_; + Color hoverColor_; + + public: + explicit Annotation(AnnotationsSceneLayer& that) : + that_(that), + color_(that.GetColor()), + hoverColor_(that.GetHoverColor()) + { + that.AddAnnotation(this); + } + + virtual ~Annotation() + { + for (GeometricPrimitives::iterator it = primitives_.begin(); it != primitives_.end(); ++it) + { + that_.DeletePrimitive(*it); + } + } + + AnnotationsSceneLayer& GetParentLayer() const + { + return that_; + } + + GeometricPrimitive* AddPrimitive(GeometricPrimitive* primitive) + { + if (primitive == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + assert(that_.primitives_.find(primitive) == that_.primitives_.end()); + primitives_.push_back(primitive); // For automated deallocation + that_.primitives_.insert(primitive); + return primitive; + } + } + + const Color& GetColor() const + { + return color_; + } + + const Color& GetHoverColor() const + { + return hoverColor_; + } + + template <typename T> + T& AddTypedPrimitive(T* primitive) + { + AddPrimitive(primitive); + return *primitive; + } + + virtual unsigned int GetHandlesCount() const = 0; + + virtual Handle& GetHandle(unsigned int index) const = 0; + + virtual void SignalMove(GeometricPrimitive& primitive, + const Scene2D& scene) = 0; + + virtual void UpdateProbe(const Scene2D& scene) = 0; + + virtual void Serialize(Json::Value& target) = 0; + }; + + class AnnotationsSceneLayer::GeometricPrimitive : public boost::noncopyable { private: @@ -91,8 +165,8 @@ int depth) : modified_(true), parentAnnotation_(parentAnnotation), - color_(COLOR_PRIMITIVES), - hoverColor_(COLOR_HOVER), + color_(parentAnnotation.GetColor()), + hoverColor_(parentAnnotation.GetHoverColor()), isHover_(false), depth_(depth) { @@ -182,69 +256,6 @@ }; - class AnnotationsSceneLayer::Annotation : public boost::noncopyable - { - private: - typedef std::list<GeometricPrimitive*> GeometricPrimitives; - - AnnotationsSceneLayer& that_; - GeometricPrimitives primitives_; - - public: - explicit Annotation(AnnotationsSceneLayer& that) : - that_(that) - { - that.AddAnnotation(this); - } - - virtual ~Annotation() - { - for (GeometricPrimitives::iterator it = primitives_.begin(); it != primitives_.end(); ++it) - { - that_.DeletePrimitive(*it); - } - } - - AnnotationsSceneLayer& GetParentLayer() const - { - return that_; - } - - GeometricPrimitive* AddPrimitive(GeometricPrimitive* primitive) - { - if (primitive == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - assert(that_.primitives_.find(primitive) == that_.primitives_.end()); - primitives_.push_back(primitive); // For automated deallocation - that_.primitives_.insert(primitive); - return primitive; - } - } - - template <typename T> - T& AddTypedPrimitive(T* primitive) - { - AddPrimitive(primitive); - return *primitive; - } - - virtual unsigned int GetHandlesCount() const = 0; - - virtual Handle& GetHandle(unsigned int index) const = 0; - - virtual void SignalMove(GeometricPrimitive& primitive, - const Scene2D& scene) = 0; - - virtual void UpdateProbe(const Scene2D& scene) = 0; - - virtual void Serialize(Json::Value& target) = 0; - }; - - class AnnotationsSceneLayer::Handle : public GeometricPrimitive { public: @@ -1123,7 +1134,7 @@ segment_(AddTypedPrimitive<Segment>(new Segment(*this, p1, p2))), label_(AddTypedPrimitive<Text>(new Text(that, *this))) { - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); } virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE @@ -1494,7 +1505,7 @@ content.SetText("?"); label_.SetContent(content); - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); } virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE @@ -1602,7 +1613,7 @@ arc_(AddTypedPrimitive<Arc>(new Arc(*this, start, middle, end))), label_(AddTypedPrimitive<Text>(new Text(that, *this))) { - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); UpdateLabel(); } @@ -1793,7 +1804,7 @@ circle_(AddTypedPrimitive<Circle>(new Circle(*this, p1, p2))), label_(AddTypedPrimitive<Text>(new Text(that, *this))) { - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); UpdateLabel(); } @@ -2007,7 +2018,7 @@ content.SetText("?"); label_.SetContent(content); - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); } virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE @@ -2264,7 +2275,7 @@ content.SetText("?"); label_.SetContent(content); - label_.SetColor(COLOR_TEXT); + label_.SetColor(that.GetHoverColor()); } virtual unsigned int GetHandlesCount() const ORTHANC_OVERRIDE @@ -2655,7 +2666,9 @@ macroLayerIndex_(macroLayerIndex), polylineSubLayer_(0), // dummy initialization units_(Units_Pixels), - probedLayer_(0) + probedLayer_(0), + color_(0, 255, 0), + hoverColor_(255, 0, 0) { }
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Apr 23 09:31:59 2025 +0200 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Apr 23 13:14:42 2025 +0200 @@ -22,8 +22,9 @@ #include "../Messages/IObservable.h" +#include "../Scene2DViewport/IFlexiblePointerTracker.h" +#include "Color.h" #include "Scene2D.h" -#include "../Scene2DViewport/IFlexiblePointerTracker.h" namespace OrthancStone { @@ -116,6 +117,8 @@ SubLayers subLayersToRemove_; Units units_; int probedLayer_; + Color color_; + Color hoverColor_; void AddAnnotation(Annotation* annotation); @@ -189,5 +192,25 @@ void AddTextAnnotation(const std::string& label, const ScenePoint2D& pointedPosition, const ScenePoint2D& labelPosition); + + const Color& GetColor() const + { + return color_; + } + + void SetColor(const Color& color) + { + color_ = color; + } + + const Color& GetHoverColor() const + { + return hoverColor_; + } + + void SetHoverColor(const Color& color) + { + hoverColor_ = color; + } }; }