Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1703:76c590a62755
start work on series with multiple multiframe instances
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 27 Nov 2020 16:36:43 +0100 |
parents | bc40b6450261 |
children | 902d13889ae4 |
comparison
equal
deleted
inserted
replaced
1702:bc40b6450261 | 1703:76c590a62755 |
---|---|
193 const std::string& seriesInstanceUid) = 0; | 193 const std::string& seriesInstanceUid) = 0; |
194 | 194 |
195 virtual void SignalSeriesPdfLoaded(const std::string& studyInstanceUid, | 195 virtual void SignalSeriesPdfLoaded(const std::string& studyInstanceUid, |
196 const std::string& seriesInstanceUid, | 196 const std::string& seriesInstanceUid, |
197 const std::string& pdf) = 0; | 197 const std::string& pdf) = 0; |
198 | |
199 virtual void SignalMultiframeInstanceThumbnailLoaded(const std::string& sopInstanceUid, | |
200 const std::string& jpeg) = 0; | |
198 }; | 201 }; |
199 | 202 |
200 private: | 203 private: |
201 OrthancStone::ILoadersContext& context_; | 204 OrthancStone::ILoadersContext& context_; |
202 std::unique_ptr<IObserver> observer_; | 205 std::unique_ptr<IObserver> observer_; |
205 boost::shared_ptr<OrthancStone::LoadedDicomResources> studies_; | 208 boost::shared_ptr<OrthancStone::LoadedDicomResources> studies_; |
206 boost::shared_ptr<OrthancStone::LoadedDicomResources> series_; | 209 boost::shared_ptr<OrthancStone::LoadedDicomResources> series_; |
207 boost::shared_ptr<OrthancStone::DicomResourcesLoader> resourcesLoader_; | 210 boost::shared_ptr<OrthancStone::DicomResourcesLoader> resourcesLoader_; |
208 boost::shared_ptr<OrthancStone::SeriesThumbnailsLoader> thumbnailsLoader_; | 211 boost::shared_ptr<OrthancStone::SeriesThumbnailsLoader> thumbnailsLoader_; |
209 boost::shared_ptr<OrthancStone::SeriesMetadataLoader> metadataLoader_; | 212 boost::shared_ptr<OrthancStone::SeriesMetadataLoader> metadataLoader_; |
213 std::set<std::string> scheduledMultiframeInstances_; | |
210 | 214 |
211 explicit ResourcesLoader(OrthancStone::ILoadersContext& context, | 215 explicit ResourcesLoader(OrthancStone::ILoadersContext& context, |
212 const OrthancStone::DicomSource& source) : | 216 const OrthancStone::DicomSource& source) : |
213 context_(context), | 217 context_(context), |
214 source_(source), | 218 source_(source), |
359 LOG(ERROR) << "Unable to extract PDF from series: " << info.GetSeriesInstanceUid(); | 363 LOG(ERROR) << "Unable to extract PDF from series: " << info.GetSeriesInstanceUid(); |
360 } | 364 } |
361 } | 365 } |
362 } | 366 } |
363 | 367 |
368 void FetchInstanceThumbnail(const std::string& studyInstanceUid, | |
369 const std::string& seriesInstanceUid, | |
370 const std::string& sopInstanceUid) | |
371 { | |
372 if (scheduledMultiframeInstances_.find(sopInstanceUid) == scheduledMultiframeInstances_.end()) | |
373 { | |
374 scheduledMultiframeInstances_.insert(sopInstanceUid); | |
375 | |
376 std::map<std::string, std::string> arguments; | |
377 std::map<std::string, std::string> headers; | |
378 arguments["viewport"] = ( | |
379 boost::lexical_cast<std::string>(thumbnailsLoader_->GetThumbnailWidth()) + "," + | |
380 boost::lexical_cast<std::string>(thumbnailsLoader_->GetThumbnailHeight())); | |
381 headers["Accept"] = Orthanc::MIME_JPEG; | |
382 | |
383 const std::string uri = ("studies/" + studyInstanceUid + "/series/" + seriesInstanceUid + | |
384 "/instances/" + sopInstanceUid + "/frames/1/rendered"); | |
385 | |
386 { | |
387 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context_.Lock()); | |
388 lock->Schedule( | |
389 GetSharedObserver(), PRIORITY_LOW + 2, source_.CreateDicomWebCommand( | |
390 uri, arguments, headers, new Orthanc::SingleValueObject<std::string>(sopInstanceUid))); | |
391 } | |
392 } | |
393 } | |
394 | |
395 void HandleInstanceThumbnail(const OrthancStone::HttpCommand::SuccessMessage& message) | |
396 { | |
397 if (observer_.get() != NULL) | |
398 { | |
399 const std::string& sopInstanceUid = | |
400 dynamic_cast<const Orthanc::SingleValueObject<std::string>&>( | |
401 message.GetOrigin().GetPayload()).GetValue(); | |
402 observer_->SignalMultiframeInstanceThumbnailLoaded(sopInstanceUid, message.GetAnswer()); | |
403 } | |
404 } | |
405 | |
364 public: | 406 public: |
365 static boost::shared_ptr<ResourcesLoader> Create(OrthancStone::ILoadersContext::ILock& lock, | 407 static boost::shared_ptr<ResourcesLoader> Create(OrthancStone::ILoadersContext::ILock& lock, |
366 const OrthancStone::DicomSource& source) | 408 const OrthancStone::DicomSource& source) |
367 { | 409 { |
368 boost::shared_ptr<ResourcesLoader> loader(new ResourcesLoader(lock.GetContext(), source)); | 410 boost::shared_ptr<ResourcesLoader> loader(new ResourcesLoader(lock.GetContext(), source)); |
380 loader->Register<OrthancStone::SeriesMetadataLoader::SuccessMessage>( | 422 loader->Register<OrthancStone::SeriesMetadataLoader::SuccessMessage>( |
381 *loader->metadataLoader_, &ResourcesLoader::Handle); | 423 *loader->metadataLoader_, &ResourcesLoader::Handle); |
382 | 424 |
383 loader->Register<OrthancStone::ParseDicomSuccessMessage>( | 425 loader->Register<OrthancStone::ParseDicomSuccessMessage>( |
384 lock.GetOracleObservable(), &ResourcesLoader::Handle); | 426 lock.GetOracleObservable(), &ResourcesLoader::Handle); |
385 | 427 |
428 loader->Register<OrthancStone::HttpCommand::SuccessMessage>( | |
429 lock.GetOracleObservable(), &ResourcesLoader::HandleInstanceThumbnail); | |
430 | |
386 return loader; | 431 return loader; |
387 } | 432 } |
388 | 433 |
389 void FetchAllStudies() | 434 void FetchAllStudies() |
390 { | 435 { |
426 { | 471 { |
427 return series_->GetSize(); | 472 return series_->GetSize(); |
428 } | 473 } |
429 | 474 |
430 void GetStudy(Orthanc::DicomMap& target, | 475 void GetStudy(Orthanc::DicomMap& target, |
431 size_t i) | 476 size_t i) const |
432 { | 477 { |
433 target.Assign(studies_->GetResource(i)); | 478 target.Assign(studies_->GetResource(i)); |
434 } | 479 } |
435 | 480 |
436 void GetSeries(Orthanc::DicomMap& target, | 481 void GetSeries(Orthanc::DicomMap& target, |
437 size_t i) | 482 size_t i) const |
438 { | 483 { |
439 target.Assign(series_->GetResource(i)); | 484 target.Assign(series_->GetResource(i)); |
440 | 485 |
441 // Complement with the study-level tags | 486 // Complement with the study-level tags |
442 std::string studyInstanceUid; | 487 std::string studyInstanceUid; |
447 } | 492 } |
448 } | 493 } |
449 | 494 |
450 OrthancStone::SeriesThumbnailType GetSeriesThumbnail(std::string& image, | 495 OrthancStone::SeriesThumbnailType GetSeriesThumbnail(std::string& image, |
451 std::string& mime, | 496 std::string& mime, |
452 const std::string& seriesInstanceUid) | 497 const std::string& seriesInstanceUid) const |
453 { | 498 { |
454 return thumbnailsLoader_->GetSeriesThumbnail(image, mime, seriesInstanceUid); | 499 return thumbnailsLoader_->GetSeriesThumbnail(image, mime, seriesInstanceUid); |
455 } | 500 } |
456 | 501 |
457 void FetchSeriesMetadata(int priority, | 502 void FetchSeriesMetadata(int priority, |
458 const std::string& studyInstanceUid, | 503 const std::string& studyInstanceUid, |
459 const std::string& seriesInstanceUid) | 504 const std::string& seriesInstanceUid) const |
460 { | 505 { |
461 metadataLoader_->ScheduleLoadSeries(priority, source_, studyInstanceUid, seriesInstanceUid); | 506 metadataLoader_->ScheduleLoadSeries(priority, source_, studyInstanceUid, seriesInstanceUid); |
462 } | 507 } |
463 | 508 |
464 bool IsSeriesComplete(const std::string& seriesInstanceUid) | 509 bool IsSeriesComplete(const std::string& seriesInstanceUid) const |
465 { | 510 { |
466 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); | 511 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); |
467 return accessor.IsComplete(); | 512 return accessor.IsComplete(); |
468 } | 513 } |
469 | 514 |
515 bool LookupMultiframeSeries(std::map<std::string, unsigned int>& numberOfFramesPerInstance, | |
516 const std::string& seriesInstanceUid) | |
517 { | |
518 numberOfFramesPerInstance.clear(); | |
519 | |
520 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); | |
521 if (accessor.IsComplete() && | |
522 accessor.GetInstancesCount() >= 2) | |
523 { | |
524 bool isMultiframe = false; | |
525 | |
526 for (size_t i = 0; i < accessor.GetInstancesCount(); i++) | |
527 { | |
528 OrthancStone::DicomInstanceParameters p(accessor.GetInstance(i)); | |
529 numberOfFramesPerInstance[p.GetSopInstanceUid()] = p.GetNumberOfFrames(); | |
530 | |
531 if (p.GetNumberOfFrames() > 1) | |
532 { | |
533 isMultiframe = true; | |
534 } | |
535 } | |
536 | |
537 if (isMultiframe) | |
538 { | |
539 for (size_t i = 0; i < accessor.GetInstancesCount(); i++) | |
540 { | |
541 OrthancStone::DicomInstanceParameters p(accessor.GetInstance(i)); | |
542 FetchInstanceThumbnail(p.GetStudyInstanceUid(), p.GetSeriesInstanceUid(), p.GetSopInstanceUid()); | |
543 } | |
544 } | |
545 | |
546 return isMultiframe; | |
547 } | |
548 else | |
549 { | |
550 return false; | |
551 } | |
552 } | |
553 | |
470 bool SortSeriesFrames(OrthancStone::SortedFrames& target, | 554 bool SortSeriesFrames(OrthancStone::SortedFrames& target, |
471 const std::string& seriesInstanceUid) | 555 const std::string& seriesInstanceUid) const |
472 { | 556 { |
473 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); | 557 OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid); |
474 | 558 |
475 if (accessor.IsComplete()) | 559 if (accessor.IsComplete()) |
476 { | 560 { |
2672 studyInstanceUid.c_str(), | 2756 studyInstanceUid.c_str(), |
2673 seriesInstanceUid.c_str(), | 2757 seriesInstanceUid.c_str(), |
2674 pdf.empty() ? 0 : reinterpret_cast<intptr_t>(pdf.c_str()), // Explicit conversion to an integer | 2758 pdf.empty() ? 0 : reinterpret_cast<intptr_t>(pdf.c_str()), // Explicit conversion to an integer |
2675 pdf.size()); | 2759 pdf.size()); |
2676 } | 2760 } |
2761 | |
2762 | |
2763 virtual void SignalMultiframeInstanceThumbnailLoaded(const std::string& sopInstanceUid, | |
2764 const std::string& jpeg) ORTHANC_OVERRIDE | |
2765 { | |
2766 std::string dataUriScheme; | |
2767 Orthanc::Toolbox::EncodeDataUriScheme(dataUriScheme, "image/jpeg", jpeg); | |
2768 | |
2769 EM_ASM({ | |
2770 const customEvent = document.createEvent("CustomEvent"); | |
2771 customEvent.initCustomEvent("MultiframeInstanceThumbnailLoaded", false, false, | |
2772 { "sopInstanceUid" : UTF8ToString($0), | |
2773 "thumbnail" : UTF8ToString($1) }); | |
2774 window.dispatchEvent(customEvent); | |
2775 }, | |
2776 sopInstanceUid.c_str(), | |
2777 dataUriScheme.c_str()); | |
2778 } | |
2677 }; | 2779 }; |
2678 | 2780 |
2679 | 2781 |
2680 | 2782 |
2681 static OrthancStone::DicomSource source_; | 2783 static OrthancStone::DicomSource source_; |
3244 it->second->SetSynchronizedBrowsingEnabled(enabled); | 3346 it->second->SetSynchronizedBrowsingEnabled(enabled); |
3245 } | 3347 } |
3246 } | 3348 } |
3247 EXTERN_CATCH_EXCEPTIONS; | 3349 EXTERN_CATCH_EXCEPTIONS; |
3248 } | 3350 } |
3351 | |
3352 | |
3353 EMSCRIPTEN_KEEPALIVE | |
3354 int LoadMultiframeInstancesFromSeries(const char* seriesInstanceUid) | |
3355 { | |
3356 try | |
3357 { | |
3358 std::map<std::string, unsigned int> numberOfFramesPerInstance; | |
3359 if (GetResourcesLoader().LookupMultiframeSeries(numberOfFramesPerInstance, seriesInstanceUid)) | |
3360 { | |
3361 Json::Value json = Json::objectValue; | |
3362 for (std::map<std::string, unsigned int>::const_iterator it = | |
3363 numberOfFramesPerInstance.begin(); it != numberOfFramesPerInstance.end(); ++it) | |
3364 { | |
3365 json[it->first] = it->second; | |
3366 } | |
3367 | |
3368 stringBuffer_ = json.toStyledString(); | |
3369 return true; | |
3370 } | |
3371 else | |
3372 { | |
3373 return false; | |
3374 } | |
3375 } | |
3376 EXTERN_CATCH_EXCEPTIONS; | |
3377 return false; | |
3378 } | |
3249 } | 3379 } |