Mercurial > hg > orthanc-stone
changeset 1681:f2e8b3ac1dcd
handling multiple windowing presets in the Stone web viewer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 24 Nov 2020 18:08:07 +0100 |
parents | 03afa09cfcf1 |
children | 84fe7089ccaa |
files | Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp |
diffstat | 3 files changed, 132 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js Tue Nov 24 16:39:54 2020 +0100 +++ b/Applications/StoneWebViewer/WebApplication/app.js Tue Nov 24 18:08:07 2020 +0100 @@ -300,6 +300,9 @@ viewport4Visible: false, viewport4Series: {}, + showWindowing: false, + windowingPresets: [], + series: [], studies: [], seriesIndex: {} // Maps "SeriesInstanceUID" to "index in this.series" @@ -617,19 +620,13 @@ }, SetWindowing: function(center, width) { + this.showWindowing = false; var canvas = this.GetActiveCanvas(); if (canvas != '') { stone.SetWindowing(canvas, center, width); } }, - SetPresetWindowing: function() { - var canvas = this.GetActiveCanvas(); - if (canvas != '') { - stone.SetPresetWindowing(canvas); - } - }, - InvertContrast: function() { var canvas = this.GetActiveCanvas(); if (canvas != '') { @@ -679,6 +676,27 @@ stone.FocusFirstOsiriXAnnotation('canvas1'); } + }, + + ToggleWindowing: function() + { + if (this.showWindowing) + { + this.showWindowing = false; + } + else + { + stone.LoadWindowingPresets(this.GetActiveCanvas()); + this.windowingPresets = JSON.parse(stone.GetStringBuffer()); + + var p = $('#windowing-popover').last(); + var top = p.offset().top + p.height() + 10; + $('#windowing-content').css('top', top); + //$('#windowing-content').css('right', '10'); + //$('#windowing-content').css('left', 'auto'); + + this.showWindowing = true; + } } }, @@ -783,17 +801,6 @@ //app.modalWarning = true; - $('#windowing-popover').popover({ - container: 'body', - content: $('#windowing-content').html(), - template: '<div class="popover wvToolbar__windowingPresetConfigPopover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>', - placement: 'auto', - html: true, - sanitize: false, - trigger: 'focus' // Close on click - }); - - var wasmSource = 'StoneWebViewer.js'; // Option 1: Loading script using plain HTML
--- a/Applications/StoneWebViewer/WebApplication/index.html Tue Nov 24 16:39:54 2020 +0100 +++ b/Applications/StoneWebViewer/WebApplication/index.html Tue Nov 24 18:08:07 2020 +0100 @@ -367,11 +367,64 @@ <div class="ng-scope inline-object"> <button class="wvButton--underline text-center" data-toggle="tooltip" data-title="Change windowing" - id="windowing-popover"> + id="windowing-popover" + v-on:click="ToggleWindowing()"> <i class="fa fa-sun"></i> </button> </div> + <div id="windowing-content" v-show="showWindowing" + class="popover wvToolbar__windowingPresetConfigPopover" + style="position: absolute; display: block" + > + <div class="arrow"></div> + <h3 class="popover-title">Change windowing</h3> + <div class="popover-content"> + + <!--p class="wvToolbar__windowingPresetConfigNotice"> + Click on the button to toggle the windowing tool or apply a preset to the selected viewport. + </p--> + + <ul class="wvToolbar__windowingPresetList"> + <li v-for="preset in windowingPresets" class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(preset.center, preset.width)"> + {{ preset.name }} <small>({{ preset.info }})</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(-400, 1600)"> + CT Lung <small>(C -400, W 1600)</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(300, 1500)"> + CT Abdomen <small>(C 300, W 1500)</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(40, 80)"> + CT Bone <small>(C 40, W 80)</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(40, 400)"> + CT Brain <small>(C 40, W 400)</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(-400, 1600)"> + CT Chest <small>(C -400, W 1600)</small> + </a> + </li> + <li class="wvToolbar__windowingPresetListItem"> + <a href="#" v-on:click="SetWindowing(300, 600)"> + CT Angio <small>(C 300, W 600)</small> + </a> + </li> + </ul> + </div> + </div> + <div class="ng-scope inline-object"> <button class="wvButton--underline text-center" data-toggle="tooltip" data-title="Flip horizontally" @@ -464,58 +517,11 @@ v-bind:active="activeViewport==4"></viewport> </div> </div> - </div> - </div> + </div> </div> - - - <script type="text/x-template" id="windowing-content"> - <p class="wvToolbar__windowingPresetConfigNotice"> - Click on the button to toggle the windowing tool or apply a preset to the selected viewport. - </p> - - <ul class="wvToolbar__windowingPresetList"> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetPresetWindowing()"> - Preset - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(-400, 1600)"> - CT Lung <small>(L -400, W 1,600)</small> - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(300, 1500)"> - CT Abdomen <small>(L 300, W 1,500)</small> - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(40, 80)"> - CT Bone <small>(L 40, W 80)</small> - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(40, 400)"> - CT Brain <small>(L 40, W 400)</small> - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(-400, 1600)"> - CT Chest <small>(L -400, W 1,600)</small> - </a> - </li> - <li class="wvToolbar__windowingPresetListItem"> - <a href="#" onclick="app.SetWindowing(300, 600)"> - CT Angio <small>(L 300, W 600)</small> - </a> - </li> - </ul> - </script> - <script type="text/x-template" id="viewport-template"> <div v-bind:id="canvasId + '-container'" v-bind:style="{ padding:'2px',
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Tue Nov 24 16:39:54 2020 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Tue Nov 24 18:08:07 2020 +0100 @@ -94,6 +94,7 @@ #include <WebGLViewport.h> +#include <boost/math/special_functions/round.hpp> #include <boost/make_shared.hpp> #include <stdio.h> @@ -1102,27 +1103,25 @@ { OrthancStone::DicomInstanceParameters params(dicom); + GetViewport().windowingPresetCenters_.resize(params.GetWindowingPresetsCount()); + GetViewport().windowingPresetWidths_.resize(params.GetWindowingPresetsCount()); + for (size_t i = 0; i < params.GetWindowingPresetsCount(); i++) { - LOG(INFO) << "Preset windowing " << i << "/" << params.GetWindowingPresetsCount() + LOG(INFO) << "Preset windowing " << (i + 1) << "/" << params.GetWindowingPresetsCount() << ": " << params.GetWindowingPresetCenter(i) << "," << params.GetWindowingPresetWidth(i); + + GetViewport().windowingPresetCenters_[i] = params.GetWindowingPresetCenter(i); + GetViewport().windowingPresetWidths_[i] = params.GetWindowingPresetWidth(i); } - // TODO - WINDOWING - if (params.GetWindowingPresetsCount() > 0) - { - GetViewport().presetWindowingCenter_ = params.GetWindowingPresetCenter(0); - GetViewport().presetWindowingWidth_ = params.GetWindowingPresetWidth(0); - - GetViewport().windowingCenter_ = params.GetWindowingPresetCenter(0); - GetViewport().windowingWidth_ = params.GetWindowingPresetWidth(0); - } - else + if (params.GetWindowingPresetsCount() == 0) { LOG(INFO) << "No preset windowing"; - GetViewport().ResetWindowingPreset(); } + + GetViewport().SetWindowingPreset(); } uint32_t cineRate; @@ -1367,8 +1366,8 @@ std::unique_ptr<SeriesCursor> cursor_; float windowingCenter_; float windowingWidth_; - float presetWindowingCenter_; - float presetWindowingWidth_; + std::vector<float> windowingPresetCenters_; + std::vector<float> windowingPresetWidths_; unsigned int cineRate_; bool inverted_; bool flipX_; @@ -1416,18 +1415,6 @@ } - void ResetWindowingPreset() - { - presetWindowingCenter_ = 128; - presetWindowingWidth_ = 256; - - windowingCenter_ = presetWindowingCenter_; - windowingWidth_ = presetWindowingWidth_; - - inverted_ = false; - } - - void ClearViewport() { { @@ -1794,7 +1781,7 @@ emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey); emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey); - ResetWindowingPreset(); + SetWindowingPreset(); } static EM_BOOL OnKey(int eventType, @@ -1896,13 +1883,14 @@ flipY_ = false; fitNextContent_ = true; cineRate_ = DEFAULT_CINE_RATE; - + inverted_ = false; + frames_.reset(frames); cursor_.reset(new SeriesCursor(frames_->GetFramesCount())); LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); - ResetWindowingPreset(); + SetWindowingPreset(); ClearViewport(); prefetchQueue_.clear(); @@ -2131,7 +2119,18 @@ void SetWindowingPreset() { - SetWindowing(presetWindowingCenter_, presetWindowingWidth_); + assert(windowingPresetCenters_.size() == windowingPresetWidths_.size()); + + if (windowingPresetCenters_.empty()) + { + windowingCenter_ = 128; + windowingWidth_ = 256; + } + else + { + windowingCenter_ = windowingPresetCenters_[0]; + windowingWidth_ = windowingPresetWidths_[0]; + } } void SetWindowing(float windowingCenter, @@ -2333,7 +2332,30 @@ void FormatWindowingPresets(Json::Value& target) const { + assert(windowingPresetCenters_.size() == windowingPresetWidths_.size()); + target = Json::arrayValue; + + for (size_t i = 0; i < windowingPresetCenters_.size(); i++) + { + const float c = windowingPresetCenters_[i]; + const float w = windowingPresetWidths_[i]; + + std::string name = "Preset"; + if (windowingPresetCenters_.size() > 1) + { + name += " " + boost::lexical_cast<std::string>(i + 1); + } + + Json::Value preset = Json::objectValue; + preset["name"] = name; + preset["info"] = ("C " + boost::lexical_cast<std::string>(boost::math::iround(c)) + + ", W " + boost::lexical_cast<std::string>(boost::math::iround(w))); + preset["center"] = c; + preset["width"] = w; + + target.append(preset); + } } }; @@ -2825,17 +2847,6 @@ EMSCRIPTEN_KEEPALIVE - void SetWindowingPreset(const char* canvas) - { - try - { - GetViewport(canvas)->SetWindowingPreset(); - } - EXTERN_CATCH_EXCEPTIONS; - } - - - EMSCRIPTEN_KEEPALIVE void SetWindowing(const char* canvas, int center, int width)