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 }