comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 2095:ec676dbe85ac

partial integration dicom-sr->mainline
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 08 Nov 2023 15:13:21 +0100
parents 7c3d65166c26
children 79e984a89a38 9f7604d6b581 c23eef785569
comparison
equal deleted inserted replaced
2094:7c3d65166c26 2095:ec676dbe85ac
817 { 817 {
818 return false; 818 return false;
819 } 819 }
820 } 820 }
821 821
822 bool SortSeriesFrames(OrthancStone::SortedFrames& target, 822 IFramesCollection* GetSeriesFrames(const std::string& seriesInstanceUid) const
823 const std::string& seriesInstanceUid) const
824 { 823 {
825 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); 824 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid);
826 825
827 if (accessor.IsComplete()) 826 if (accessor.IsComplete())
828 { 827 {
829 target.Clear(); 828 std::unique_ptr<OrthancStone::SortedFrames> target(new OrthancStone::SortedFrames);
829 target->Clear();
830 830
831 for (size_t i = 0; i < accessor.GetInstancesCount(); i++) 831 for (size_t i = 0; i < accessor.GetInstancesCount(); i++)
832 { 832 {
833 target.AddInstance(accessor.GetInstance(i)); 833 target->AddInstance(accessor.GetInstance(i));
834 } 834 }
835 835
836 target.Sort(); 836 target->Sort();
837 837
838 return true; 838 return new SortedFramesCollection(target.release());
839 } 839 }
840 else 840 else
841 { 841 {
842 return false; 842 return NULL;
843 } 843 }
844 } 844 }
845 845
846 bool SortVirtualSeriesFrames(OrthancStone::SortedFrames& target, 846 IFramesCollection* GetVirtualSeriesFrames(const std::string& virtualSeriesId) const
847 const std::string& virtualSeriesId) const
848 { 847 {
849 const std::string& seriesInstanceUid = virtualSeries_.GetSeriesInstanceUid(virtualSeriesId); 848 const std::string& seriesInstanceUid = virtualSeries_.GetSeriesInstanceUid(virtualSeriesId);
850 849
851 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); 850 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid);
852 851
853 if (accessor.IsComplete()) 852 if (accessor.IsComplete())
854 { 853 {
855 const std::list<std::string>& sopInstanceUids = virtualSeries_.GetSopInstanceUids(virtualSeriesId); 854 const std::list<std::string>& sopInstanceUids = virtualSeries_.GetSopInstanceUids(virtualSeriesId);
856 855
857 target.Clear(); 856 std::unique_ptr<OrthancStone::SortedFrames> target(new OrthancStone::SortedFrames);
857 target->Clear();
858 858
859 for (std::list<std::string>::const_iterator 859 for (std::list<std::string>::const_iterator
860 it = sopInstanceUids.begin(); it != sopInstanceUids.end(); ++it) 860 it = sopInstanceUids.begin(); it != sopInstanceUids.end(); ++it)
861 { 861 {
862 Orthanc::DicomMap instance; 862 Orthanc::DicomMap instance;
863 if (accessor.LookupInstance(instance, *it)) 863 if (accessor.LookupInstance(instance, *it))
864 { 864 {
865 target.AddInstance(instance); 865 target->AddInstance(instance);
866 } 866 }
867 else 867 else
868 { 868 {
869 LOG(ERROR) << "Missing instance: " << *it; 869 LOG(ERROR) << "Missing instance: " << *it;
870 } 870 }
871 } 871 }
872 872
873 target.Sort(); 873 target->Sort();
874 return true; 874
875 return new SortedFramesCollection(target.release());
875 } 876 }
876 else 877 else
877 { 878 {
878 return false; 879 return NULL;
879 } 880 }
880 } 881 }
881 882
882 size_t GetSeriesNumberOfFrames(const std::string& seriesInstanceUid) const 883 size_t GetSeriesNumberOfFrames(const std::string& seriesInstanceUid) const
883 { 884 {
1633 }; 1634 };
1634 }; 1635 };
1635 1636
1636 1637
1637 1638
1638
1639 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport> 1639 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport>
1640 { 1640 {
1641 public: 1641 public:
1642 class IObserver : public boost::noncopyable 1642 class IObserver : public boost::noncopyable
1643 { 1643 {
1915 1915
1916 1916
1917 class SetFullDicomFrame : public ICommand 1917 class SetFullDicomFrame : public ICommand
1918 { 1918 {
1919 private: 1919 private:
1920 std::string studyInstanceUid_;
1921 std::string seriesInstanceUid_;
1920 std::string sopInstanceUid_; 1922 std::string sopInstanceUid_;
1921 unsigned int frameNumber_; 1923 unsigned int frameNumber_;
1922 int priority_; 1924 int priority_;
1923 bool isPrefetch_; 1925 bool isPrefetch_;
1924 bool serverSideTranscoding_; 1926 bool serverSideTranscoding_;
1925 1927
1926 public: 1928 public:
1927 SetFullDicomFrame(boost::shared_ptr<ViewerViewport> viewport, 1929 SetFullDicomFrame(boost::shared_ptr<ViewerViewport> viewport,
1930 const std::string& studyInstanceUid,
1931 const std::string& seriesInstanceUid,
1928 const std::string& sopInstanceUid, 1932 const std::string& sopInstanceUid,
1929 unsigned int frameNumber, 1933 unsigned int frameNumber,
1930 int priority, 1934 int priority,
1931 bool isPrefetch, 1935 bool isPrefetch,
1932 bool serverSideTranscoding) : 1936 bool serverSideTranscoding) :
1933 ICommand(viewport), 1937 ICommand(viewport),
1938 studyInstanceUid_(studyInstanceUid),
1939 seriesInstanceUid_(seriesInstanceUid),
1934 sopInstanceUid_(sopInstanceUid), 1940 sopInstanceUid_(sopInstanceUid),
1935 frameNumber_(frameNumber), 1941 frameNumber_(frameNumber),
1936 priority_(priority), 1942 priority_(priority),
1937 isPrefetch_(isPrefetch), 1943 isPrefetch_(isPrefetch),
1938 serverSideTranscoding_(serverSideTranscoding) 1944 serverSideTranscoding_(serverSideTranscoding)
1954 if (!serverSideTranscoding_) 1960 if (!serverSideTranscoding_)
1955 { 1961 {
1956 // If we haven't tried server-side rendering yet, give it a try 1962 // If we haven't tried server-side rendering yet, give it a try
1957 LOG(INFO) << "Switching to server-side transcoding"; 1963 LOG(INFO) << "Switching to server-side transcoding";
1958 GetViewport().serverSideTranscoding_ = true; 1964 GetViewport().serverSideTranscoding_ = true;
1959 GetViewport().ScheduleLoadFullDicomFrame(sopInstanceUid_, frameNumber_, priority_, isPrefetch_); 1965 GetViewport().ScheduleLoadFullDicomFrame(studyInstanceUid_, seriesInstanceUid_, sopInstanceUid_, frameNumber_, priority_, isPrefetch_);
1960 } 1966 }
1961 return; 1967 return;
1962 } 1968 }
1963 else 1969 else
1964 { 1970 {
2072 OrthancStone::WebAssemblyLoadersContext& context_; 2078 OrthancStone::WebAssemblyLoadersContext& context_;
2073 boost::shared_ptr<OrthancStone::WebAssemblyViewport> viewport_; 2079 boost::shared_ptr<OrthancStone::WebAssemblyViewport> viewport_;
2074 boost::shared_ptr<OrthancStone::DicomResourcesLoader> loader_; 2080 boost::shared_ptr<OrthancStone::DicomResourcesLoader> loader_;
2075 OrthancStone::DicomSource source_; 2081 OrthancStone::DicomSource source_;
2076 boost::shared_ptr<FramesCache> framesCache_; 2082 boost::shared_ptr<FramesCache> framesCache_;
2077 std::unique_ptr<OrthancStone::SortedFrames> frames_; 2083 std::unique_ptr<IFramesCollection> frames_;
2078 std::unique_ptr<SeriesCursor> cursor_; 2084 std::unique_ptr<SeriesCursor> cursor_;
2079 float windowingCenter_; 2085 float windowingCenter_;
2080 float windowingWidth_; 2086 float windowingWidth_;
2081 std::vector<float> windowingPresetCenters_; 2087 std::vector<float> windowingPresetCenters_;
2082 std::vector<float> windowingPresetWidths_; 2088 std::vector<float> windowingPresetWidths_;
2430 2436
2431 // Only change the scene if the loaded frame still corresponds to the current cursor 2437 // Only change the scene if the loaded frame still corresponds to the current cursor
2432 if (instance.GetSopInstanceUid() == loadedSopInstanceUid && 2438 if (instance.GetSopInstanceUid() == loadedSopInstanceUid &&
2433 frameNumber == loadedFrameNumber) 2439 frameNumber == loadedFrameNumber)
2434 { 2440 {
2435 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursorIndex); 2441 const OrthancStone::CoordinateSystem3D plane = IFramesCollection::GetFrameGeometry(*frames_, cursorIndex);
2436 2442
2437 if (quality == DisplayedFrameQuality_Low) 2443 if (quality == DisplayedFrameQuality_Low)
2438 { 2444 {
2439 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber); 2445 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber);
2440 if (accessor.IsValid() && 2446 if (accessor.IsValid() &&
2469 } 2475 }
2470 } 2476 }
2471 } 2477 }
2472 } 2478 }
2473 2479
2474 void ScheduleLoadFullDicomFrame(const std::string& sopInstanceUid, 2480 void ScheduleLoadFullDicomFrame(const std::string& studyInstanceUid,
2481 const std::string& seriesInstanceUid,
2482 const std::string& sopInstanceUid,
2475 unsigned int frameNumber, 2483 unsigned int frameNumber,
2476 int priority, 2484 int priority,
2477 bool isPrefetch) 2485 bool isPrefetch)
2478 { 2486 {
2479 if (frames_.get() != NULL) 2487 if (frames_.get() != NULL)
2480 { 2488 {
2481 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context_.Lock()); 2489 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context_.Lock());
2482 lock->Schedule( 2490 lock->Schedule(
2483 GetSharedObserver(), priority, OrthancStone::ParseDicomFromWadoCommand::Create( 2491 GetSharedObserver(), priority, OrthancStone::ParseDicomFromWadoCommand::Create(
2484 source_, frames_->GetStudyInstanceUid(), frames_->GetSeriesInstanceUid(), 2492 source_, studyInstanceUid, seriesInstanceUid, sopInstanceUid, serverSideTranscoding_,
2485 sopInstanceUid, serverSideTranscoding_,
2486 Orthanc::DicomTransferSyntax_LittleEndianExplicit, 2493 Orthanc::DicomTransferSyntax_LittleEndianExplicit,
2487 new SetFullDicomFrame(GetSharedObserver(), sopInstanceUid, frameNumber, priority, isPrefetch, serverSideTranscoding_))); 2494 new SetFullDicomFrame(GetSharedObserver(), studyInstanceUid, seriesInstanceUid,
2495 sopInstanceUid, frameNumber, priority, isPrefetch, serverSideTranscoding_)));
2488 } 2496 }
2489 } 2497 }
2490 2498
2491 void ScheduleLoadFullDicomFrame(size_t cursorIndex, 2499 void ScheduleLoadFullDicomFrame(size_t cursorIndex,
2492 int priority, 2500 int priority,
2493 bool isPrefetch) 2501 bool isPrefetch)
2494 { 2502 {
2495 if (frames_.get() != NULL) 2503 if (frames_.get() != NULL)
2496 { 2504 {
2505 std::string studyInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetStudyInstanceUid();
2506 std::string seriesInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetSeriesInstanceUid();
2497 std::string sopInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid(); 2507 std::string sopInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid();
2498 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); 2508 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex);
2499 ScheduleLoadFullDicomFrame(sopInstanceUid, frameNumber, priority, isPrefetch); 2509 ScheduleLoadFullDicomFrame(studyInstanceUid, seriesInstanceUid, sopInstanceUid, frameNumber, priority, isPrefetch);
2500 } 2510 }
2501 } 2511 }
2502 2512
2503 void ScheduleLoadRenderedFrame(size_t cursorIndex, 2513 void ScheduleLoadRenderedFrame(size_t cursorIndex,
2504 int priority, 2514 int priority,
2543 } 2553 }
2544 2554
2545 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() == 2555 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() ==
2546 Orthanc::PhotometricInterpretation_Monochrome1); 2556 Orthanc::PhotometricInterpretation_Monochrome1);
2547 2557
2548 const std::string uri = ("studies/" + frames_->GetStudyInstanceUid() + 2558 const std::string uri = ("studies/" + instance.GetStudyInstanceUid() +
2549 "/series/" + frames_->GetSeriesInstanceUid() + 2559 "/series/" + instance.GetSeriesInstanceUid() +
2550 "/instances/" + instance.GetSopInstanceUid() + 2560 "/instances/" + instance.GetSopInstanceUid() +
2551 "/frames/" + boost::lexical_cast<std::string>(frameNumber + 1) + "/rendered"); 2561 "/frames/" + boost::lexical_cast<std::string>(frameNumber + 1) + "/rendered");
2552 2562
2553 std::map<std::string, std::string> headers, arguments; 2563 std::map<std::string, std::string> headers, arguments;
2554 // arguments["quality"] = "10"; // Low-level quality for test purpose 2564 // arguments["quality"] = "10"; // Low-level quality for test purpose
2585 2595
2586 lock->Invalidate(); 2596 lock->Invalidate();
2587 } 2597 }
2588 } 2598 }
2589 2599
2590
2591 ViewerViewport(OrthancStone::WebAssemblyLoadersContext& context, 2600 ViewerViewport(OrthancStone::WebAssemblyLoadersContext& context,
2592 const OrthancStone::DicomSource& source, 2601 const OrthancStone::DicomSource& source,
2593 const std::string& canvas, 2602 const std::string& canvas,
2594 boost::shared_ptr<FramesCache> cache, 2603 boost::shared_ptr<FramesCache> cache,
2595 bool softwareRendering, 2604 bool softwareRendering,
2680 2689
2681 if (that.synchronizationEnabled_) 2690 if (that.synchronizationEnabled_)
2682 { 2691 {
2683 const size_t currentCursorIndex = that.cursor_->GetCurrentIndex(); 2692 const size_t currentCursorIndex = that.cursor_->GetCurrentIndex();
2684 2693
2685 const OrthancStone::CoordinateSystem3D current = 2694 const OrthancStone::CoordinateSystem3D current = IFramesCollection::GetFrameGeometry(*that.frames_, currentCursorIndex);
2686 that.frames_->GetFrameGeometry(currentCursorIndex);
2687 2695
2688 if (isShift && 2696 if (isShift &&
2689 previousCursorIndex != currentCursorIndex) 2697 previousCursorIndex != currentCursorIndex)
2690 { 2698 {
2691 const OrthancStone::CoordinateSystem3D previous = 2699 const OrthancStone::CoordinateSystem3D previous = IFramesCollection::GetFrameGeometry(*that.frames_, previousCursorIndex);
2692 that.frames_->GetFrameGeometry(previousCursorIndex);
2693 that.synchronizationOffset_ += previous.GetOrigin() - current.GetOrigin(); 2700 that.synchronizationOffset_ += previous.GetOrigin() - current.GetOrigin();
2694 } 2701 }
2695 2702
2696 that.observer_->SignalSynchronizedBrowsing( 2703 that.observer_->SignalSynchronizedBrowsing(
2697 that, current.GetOrigin() + that.synchronizationOffset_, current.GetNormal()); 2704 that, current.GetOrigin() + that.synchronizationOffset_, current.GetNormal());
2834 } 2841 }
2835 2842
2836 return viewport; 2843 return viewport;
2837 } 2844 }
2838 2845
2839 void SetFrames(OrthancStone::SortedFrames* frames) 2846 void SetFrames(IFramesCollection* frames)
2840 { 2847 {
2841 if (frames == NULL) 2848 if (frames == NULL)
2842 { 2849 {
2843 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); 2850 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
2844 } 2851 }
2904 uid != OrthancStone::SopClassUid_RTPlan && 2911 uid != OrthancStone::SopClassUid_RTPlan &&
2905 uid != OrthancStone::SopClassUid_RTStruct && 2912 uid != OrthancStone::SopClassUid_RTStruct &&
2906 GetSeriesThumbnailType(uid) != OrthancStone::SeriesThumbnailType_Video) 2913 GetSeriesThumbnailType(uid) != OrthancStone::SeriesThumbnailType_Video)
2907 { 2914 {
2908 // Fetch the details of the series from the central instance 2915 // Fetch the details of the series from the central instance
2909 const std::string uri = ("studies/" + frames_->GetStudyInstanceUid() + 2916 const std::string uri = ("studies/" + centralInstance.GetStudyInstanceUid() +
2910 "/series/" + frames_->GetSeriesInstanceUid() + 2917 "/series/" + centralInstance.GetSeriesInstanceUid() +
2911 "/instances/" + centralInstance.GetSopInstanceUid() + "/metadata"); 2918 "/instances/" + centralInstance.GetSopInstanceUid() + "/metadata");
2912 2919
2913 loader_->ScheduleGetDicomWeb( 2920 loader_->ScheduleGetDicomWeb(
2914 boost::make_shared<OrthancStone::LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID), 2921 boost::make_shared<OrthancStone::LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID),
2915 0, source_, uri, new LoadSeriesDetailsFromInstance(GetSharedObserver())); 2922 0, source_, uri, new LoadSeriesDetailsFromInstance(GetSharedObserver()));
2961 const size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); 2968 const size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex);
2962 2969
2963 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber); 2970 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber);
2964 if (accessor.IsValid()) 2971 if (accessor.IsValid())
2965 { 2972 {
2966 RenderCurrentScene(accessor.GetImage(), instance, frameNumber, frames_->GetFrameGeometry(cursorIndex)); 2973 RenderCurrentScene(accessor.GetImage(), instance, frameNumber, IFramesCollection::GetFrameGeometry(*frames_, cursorIndex));
2967 2974
2968 DisplayedFrameQuality quality; 2975 DisplayedFrameQuality quality;
2969 2976
2970 if (accessor.GetQuality() < QUALITY_FULL) 2977 if (accessor.GetQuality() < QUALITY_FULL)
2971 { 2978 {
3072 bool GetCurrentPlane(OrthancStone::CoordinateSystem3D& plane) const 3079 bool GetCurrentPlane(OrthancStone::CoordinateSystem3D& plane) const
3073 { 3080 {
3074 if (cursor_.get() != NULL && 3081 if (cursor_.get() != NULL &&
3075 frames_.get() != NULL) 3082 frames_.get() != NULL)
3076 { 3083 {
3077 plane = frames_->GetFrameGeometry(cursor_->GetCurrentIndex()); 3084 plane = IFramesCollection::GetFrameGeometry(*frames_, cursor_->GetCurrentIndex());
3078 return true; 3085 return true;
3079 } 3086 }
3080 else 3087 else
3081 { 3088 {
3082 return false; 3089 return false;
3146 3153
3147 3154
3148 void SetWindowingPreset() 3155 void SetWindowingPreset()
3149 { 3156 {
3150 assert(windowingPresetCenters_.size() == windowingPresetWidths_.size()); 3157 assert(windowingPresetCenters_.size() == windowingPresetWidths_.size());
3151 3158
3152 if (windowingPresetCenters_.empty()) 3159 if (windowingPresetCenters_.empty())
3153 { 3160 {
3154 SetWindowing(128, 256); 3161 SetWindowing(128, 256);
3155 } 3162 }
3156 else 3163 else
3572 frames_.get() != NULL && 3579 frames_.get() != NULL &&
3573 cursor_.get() != NULL) 3580 cursor_.get() != NULL)
3574 { 3581 {
3575 const size_t currentCursorIndex = cursor_->GetCurrentIndex(); 3582 const size_t currentCursorIndex = cursor_->GetCurrentIndex();
3576 3583
3577 const OrthancStone::CoordinateSystem3D current = 3584 const OrthancStone::CoordinateSystem3D current = IFramesCollection::GetFrameGeometry(*frames_, currentCursorIndex);
3578 frames_->GetFrameGeometry(currentCursorIndex);
3579 3585
3580 observer_->SignalSynchronizedBrowsing( 3586 observer_->SignalSynchronizedBrowsing(
3581 *this, current.GetOrigin() + synchronizationOffset_, current.GetNormal()); 3587 *this, current.GetOrigin() + synchronizationOffset_, current.GetNormal());
3582 } 3588 }
3583 } 3589 }
4224 int LoadSeriesInViewport(const char* canvas, 4230 int LoadSeriesInViewport(const char* canvas,
4225 const char* seriesInstanceUid) 4231 const char* seriesInstanceUid)
4226 { 4232 {
4227 try 4233 try
4228 { 4234 {
4229 std::unique_ptr<OrthancStone::SortedFrames> frames(new OrthancStone::SortedFrames); 4235 std::unique_ptr<IFramesCollection> frames(GetResourcesLoader().GetSeriesFrames(seriesInstanceUid));
4230 4236
4231 if (GetResourcesLoader().SortSeriesFrames(*frames, seriesInstanceUid)) 4237 if (frames.get() != NULL)
4232 { 4238 {
4233 GetViewport(canvas)->SetFrames(frames.release()); 4239 GetViewport(canvas)->SetFrames(frames.release());
4234 return 1; 4240 return 1;
4235 } 4241 }
4236 else 4242 else
4247 int LoadVirtualSeriesInViewport(const char* canvas, 4253 int LoadVirtualSeriesInViewport(const char* canvas,
4248 const char* virtualSeriesId) 4254 const char* virtualSeriesId)
4249 { 4255 {
4250 try 4256 try
4251 { 4257 {
4252 std::unique_ptr<OrthancStone::SortedFrames> frames(new OrthancStone::SortedFrames); 4258 std::unique_ptr<IFramesCollection> frames(GetResourcesLoader().GetVirtualSeriesFrames(virtualSeriesId));
4253 4259
4254 if (GetResourcesLoader().SortVirtualSeriesFrames(*frames, virtualSeriesId)) 4260 if (frames.get() != NULL)
4255 { 4261 {
4256 GetViewport(canvas)->SetFrames(frames.release()); 4262 GetViewport(canvas)->SetFrames(frames.release());
4257 return 1; 4263 return 1;
4258 } 4264 }
4259 else 4265 else