# HG changeset patch # User Alain Mazy # Date 1632400722 -7200 # Node ID 63587fdeec690847c75295dfeb9941e06014a59a # Parent 9290d291615098d17ca6a5e351ed277f33b5d4c4 added 'SkipSeriesFromModalities' to ignore series from modality types diff -r 9290d2916150 -r 63587fdeec69 Applications/StoneWebViewer/BuildInstructions.txt --- a/Applications/StoneWebViewer/BuildInstructions.txt Tue Sep 21 12:44:40 2021 +0200 +++ b/Applications/StoneWebViewer/BuildInstructions.txt Thu Sep 23 14:38:42 2021 +0200 @@ -31,6 +31,8 @@ make -j 6 # build the StoneViewer WASM code +# note: for fast link time: use -DCMAKE_BUILD_TYPE=RelWithDebInfo. However, this produces an output that is too large to be embedded in the plugin +# therefore, when you build the plugin, build the WASM code with -DCMAKE_BUILD_TYPE=Release cd ~/dev/build/wasm-stone-viewer cmake ../../orthanc-stone/Applications/StoneWebViewer/WebAssembly -DLIBCLANG=/usr/lib/x86_64-linux-gnu/libclang-10.so -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DALLOW_DOWNLOADS=ON -G Ninja ninja install diff -r 9290d2916150 -r 63587fdeec69 Applications/StoneWebViewer/NEWS --- a/Applications/StoneWebViewer/NEWS Tue Sep 21 12:44:40 2021 +0200 +++ b/Applications/StoneWebViewer/NEWS Thu Sep 23 14:38:42 2021 +0200 @@ -4,12 +4,13 @@ * SeriesList: - display the SeriesNumber tag in front of image count. - order series by SeriesNumber - - hide non displayable series (PR, SR) + - don't show non displayable series (see "SkipSeriesFromModalities") * In the top right overlay, display ContentDate/ContentTime if they are available in the instance. If not, StudyDate is displayed (previous behavior) * New configuration options: - "TimeFormat" to control the way Dicom Times are displayed. + - "SkipSeriesFromModalities" to ignore series from given modality types. Version 2.2 (2021-08-31) diff -r 9290d2916150 -r 63587fdeec69 Applications/StoneWebViewer/WebApplication/app.js --- a/Applications/StoneWebViewer/WebApplication/app.js Tue Sep 21 12:44:40 2021 +0200 +++ b/Applications/StoneWebViewer/WebApplication/app.js Thu Sep 23 14:38:42 2021 +0200 @@ -33,7 +33,6 @@ var SERIES_DESCRIPTION = '0008,103e'; var MODALITY = '0008,0060'; var PATIENT_BIRTH_DATE = '0010,0030'; -var NON_DISPLAYABLE_MODALITIES = ['PR', 'SR'] // Registry of the PDF series for which the instance metadata is still waiting var pendingSeriesPdf_ = {}; @@ -571,9 +570,6 @@ // order series by SeriesNumber sourceSeries.sort((a, b) => {return a[SERIES_NUMBER] - b[SERIES_NUMBER];}) - // discard non displayable series - sourceSeries = sourceSeries.filter((s) => {return NON_DISPLAYABLE_MODALITIES.indexOf(s[MODALITY]) == -1; } ) - for (var i = 0; i < sourceStudies.length; i++) { var studyInstanceUid = sourceStudies[i][STUDY_INSTANCE_UID]; if (studyInstanceUid !== undefined) { @@ -1147,6 +1143,10 @@ stone.SetDicomCacheSize(app.globalConfiguration.DicomCacheSize); } + if ('SkipSeriesFromModalities' in app.globalConfiguration) { + stone.SetSkipSeriesFromModalities(JSON.stringify(app.globalConfiguration.SkipSeriesFromModalities)); + } + // Bearer token is new in Stone Web viewer 2.0 var token = getParameterFromUrl('token'); if (token !== undefined) @@ -1211,7 +1211,7 @@ window.addEventListener('ResourcesLoaded', function() { - console.log('resources loaded'); + console.log('resources loaded: ', stone.GetStudiesCount(), 'studies &', stone.GetSeriesCount(), 'series'); var studies = []; for (var i = 0; i < stone.GetStudiesCount(); i++) { diff -r 9290d2916150 -r 63587fdeec69 Applications/StoneWebViewer/WebApplication/configuration.json --- a/Applications/StoneWebViewer/WebApplication/configuration.json Tue Sep 21 12:44:40 2021 +0200 +++ b/Applications/StoneWebViewer/WebApplication/configuration.json Thu Sep 23 14:38:42 2021 +0200 @@ -114,6 +114,11 @@ * image, this logo will be displayed at the bottom-left of the * Stone Web viewer. **/ - "InstitutionLogo" : "" + "InstitutionLogo" : "", + + /** + * Define a list of modality type that the viewer will ignore. + **/ + "SkipSeriesFromModalities": ["SR", "SEG", "PR"] } } diff -r 9290d2916150 -r 63587fdeec69 Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp --- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Tue Sep 21 12:44:40 2021 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Thu Sep 23 14:38:42 2021 +0200 @@ -98,7 +98,7 @@ #include #include #include - +#include #if !defined(STONE_WEB_VIEWER_EXPORT) // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm @@ -321,6 +321,7 @@ boost::shared_ptr metadataLoader_; std::set scheduledVirtualSeriesThumbnails_; VirtualSeries virtualSeries_; + std::vector skipSeriesFromModalities_; explicit ResourcesLoader(OrthancStone::ILoadersContext& context, const OrthancStone::DicomSource& source) : @@ -342,20 +343,41 @@ LOG(INFO) << "resources loaded: " << dicom.GetSize() << ", " << Orthanc::EnumerationToString(payload.GetValue()); + std::vector seriesIdsToRemove; + if (payload.GetValue() == Orthanc::ResourceType_Series) { + // the 'dicom' var is actually equivalent to the 'series_' member in this case + for (size_t i = 0; i < dicom.GetSize(); i++) { - std::string studyInstanceUid, seriesInstanceUid; + std::string studyInstanceUid, seriesInstanceUid, modality; if (dicom.GetResource(i).LookupStringValue( studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) && dicom.GetResource(i).LookupStringValue( - seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false)) + seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false) && + dicom.GetResource(i).LookupStringValue( + modality, Orthanc::DICOM_TAG_MODALITY, false)) { - thumbnailsLoader_->ScheduleLoadThumbnail(source_, "", studyInstanceUid, seriesInstanceUid); - metadataLoader_->ScheduleLoadSeries(PRIORITY_LOW + 1, source_, studyInstanceUid, seriesInstanceUid); + // skip series that should not be displayed + if (std::find(skipSeriesFromModalities_.begin(), skipSeriesFromModalities_.end(), modality) == skipSeriesFromModalities_.end()) + { + thumbnailsLoader_->ScheduleLoadThumbnail(source_, "", studyInstanceUid, seriesInstanceUid); + metadataLoader_->ScheduleLoadSeries(PRIORITY_LOW + 1, source_, studyInstanceUid, seriesInstanceUid); + } + + else + { + seriesIdsToRemove.push_back(seriesInstanceUid); + } } } + + for (size_t i = 0; i < seriesIdsToRemove.size(); i++) + { + LOG(INFO) << "series to hide: " << seriesIdsToRemove[i]; + dicom.RemoveResource(seriesIdsToRemove[i]); + } } if (pending_ == 0) @@ -515,6 +537,11 @@ } public: + void SetSkipSeriesFromModalities(const std::vector& skipSeriesFromModalities) + { + skipSeriesFromModalities_ = skipSeriesFromModalities; + } + static boost::shared_ptr Create(OrthancStone::ILoadersContext::ILock& lock, const OrthancStone::DicomSource& source) { @@ -3572,6 +3599,27 @@ EMSCRIPTEN_KEEPALIVE + void SetSkipSeriesFromModalities(const char* value) + { + try + { + LOG(WARNING) << "SetSkipSeriesFromModalities " << value; + + Json::Value modalities; + Orthanc::Toolbox::ReadJson(modalities, value); + std::vector skipSeriesFromModalities; + + for (Json::Value::ArrayIndex i = 0; i < modalities.size(); i++) + { + skipSeriesFromModalities.push_back(modalities[i].asString()); + } + GetResourcesLoader().SetSkipSeriesFromModalities(skipSeriesFromModalities); + } + EXTERN_CATCH_EXCEPTIONS; + } + + + EMSCRIPTEN_KEEPALIVE void FetchAllStudies() { try diff -r 9290d2916150 -r 63587fdeec69 OrthancStone/Sources/Loaders/LoadedDicomResources.h --- a/OrthancStone/Sources/Loaders/LoadedDicomResources.h Tue Sep 21 12:44:40 2021 +0200 +++ b/OrthancStone/Sources/Loaders/LoadedDicomResources.h Thu Sep 23 14:38:42 2021 +0200 @@ -109,6 +109,17 @@ return resources_.find(id) != resources_.end(); } + void RemoveResource(const std::string& id) + { + if (HasResource(id)) + { + Resource* resource = resources_[id]; + delete resource; + resources_.erase(id); + flattened_.clear(); // Invalidate the flattened version + } + } + void MergeResource(Orthanc::DicomMap& target, const std::string& id) const;