comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1722:802cb1272f3a

fix for the WRIX dataset
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 01 Dec 2020 14:47:11 +0100
parents d4a8e2b19a65
children 9ac2a65d4172
comparison
equal deleted inserted replaced
1721:d4a8e2b19a65 1722:802cb1272f3a
1403 private: 1403 private:
1404 std::string sopInstanceUid_; 1404 std::string sopInstanceUid_;
1405 unsigned int frameNumber_; 1405 unsigned int frameNumber_;
1406 int priority_; 1406 int priority_;
1407 bool isPrefetch_; 1407 bool isPrefetch_;
1408 bool serverSideTranscoding_;
1408 1409
1409 public: 1410 public:
1410 SetFullDicomFrame(boost::shared_ptr<ViewerViewport> viewport, 1411 SetFullDicomFrame(boost::shared_ptr<ViewerViewport> viewport,
1411 const std::string& sopInstanceUid, 1412 const std::string& sopInstanceUid,
1412 unsigned int frameNumber, 1413 unsigned int frameNumber,
1413 int priority, 1414 int priority,
1414 bool isPrefetch) : 1415 bool isPrefetch,
1416 bool serverSideTranscoding) :
1415 ICommand(viewport), 1417 ICommand(viewport),
1416 sopInstanceUid_(sopInstanceUid), 1418 sopInstanceUid_(sopInstanceUid),
1417 frameNumber_(frameNumber), 1419 frameNumber_(frameNumber),
1418 priority_(priority), 1420 priority_(priority),
1419 isPrefetch_(isPrefetch) 1421 isPrefetch_(isPrefetch),
1422 serverSideTranscoding_(serverSideTranscoding)
1420 { 1423 {
1421 } 1424 }
1422 1425
1423 virtual void Handle(const OrthancStone::ParseDicomSuccessMessage& message) const ORTHANC_OVERRIDE 1426 virtual void Handle(const OrthancStone::ParseDicomSuccessMessage& message) const ORTHANC_OVERRIDE
1424 { 1427 {
1425 Apply(GetViewport(), message.GetDicom(), sopInstanceUid_, frameNumber_, priority_, isPrefetch_);
1426
1427 if (isPrefetch_)
1428 {
1429 GetViewport().ScheduleNextPrefetch();
1430 }
1431 }
1432
1433 static void Apply(ViewerViewport& viewport,
1434 const Orthanc::ParsedDicomFile& dicom,
1435 const std::string& sopInstanceUid,
1436 unsigned int frameNumber,
1437 int priority,
1438 bool isPrefetch)
1439 {
1440 Orthanc::DicomMap tags;
1441 dicom.ExtractDicomSummary(tags, ORTHANC_STONE_MAX_TAG_LENGTH);
1442
1443 std::string s;
1444 if (!tags.LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false))
1445 {
1446 // Safety check
1447 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1448 }
1449
1450 std::unique_ptr<Orthanc::ImageAccessor> frame; 1428 std::unique_ptr<Orthanc::ImageAccessor> frame;
1451 1429
1452 try 1430 try
1453 { 1431 {
1454 frame.reset(dicom.DecodeFrame(frameNumber)); 1432 frame.reset(message.GetDicom().DecodeFrame(frameNumber_));
1455 } 1433 }
1456 catch (Orthanc::OrthancException& e) 1434 catch (Orthanc::OrthancException& e)
1457 { 1435 {
1458 if (e.GetErrorCode() == Orthanc::ErrorCode_NotImplemented) 1436 if (e.GetErrorCode() == Orthanc::ErrorCode_NotImplemented)
1459 { 1437 {
1460 viewport.serverSideTranscoding_ = true; 1438 if (!serverSideTranscoding_)
1461 LOG(INFO) << "Switching to server-side transcoding"; 1439 {
1462 viewport.ScheduleLoadFullDicomFrame(sopInstanceUid, frameNumber, priority, isPrefetch); 1440 // If we haven't tried server-side rendering yet, give it a try
1441 LOG(INFO) << "Switching to server-side transcoding";
1442 GetViewport().serverSideTranscoding_ = true;
1443 GetViewport().ScheduleLoadFullDicomFrame(sopInstanceUid_, frameNumber_, priority_, isPrefetch_);
1444 }
1463 return; 1445 return;
1464 } 1446 }
1465 else 1447 else
1466 { 1448 {
1467 throw; 1449 throw;
1470 1452
1471 if (frame.get() == NULL) 1453 if (frame.get() == NULL)
1472 { 1454 {
1473 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 1455 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1474 } 1456 }
1457 else
1458 {
1459 Apply(GetViewport(), message.GetDicom(), frame.release(), sopInstanceUid_, frameNumber_);
1460
1461 if (isPrefetch_)
1462 {
1463 GetViewport().ScheduleNextPrefetch();
1464 }
1465 }
1466 }
1467
1468 static void Apply(ViewerViewport& viewport,
1469 const Orthanc::ParsedDicomFile& dicom,
1470 Orthanc::ImageAccessor* f,
1471 const std::string& sopInstanceUid,
1472 unsigned int frameNumber)
1473 {
1474 std::unique_ptr<Orthanc::ImageAccessor> frameProtection(f);
1475
1476 Orthanc::DicomMap tags;
1477 dicom.ExtractDicomSummary(tags, ORTHANC_STONE_MAX_TAG_LENGTH);
1475 1478
1476 std::unique_ptr<Orthanc::ImageAccessor> converted; 1479 std::unique_ptr<Orthanc::ImageAccessor> converted;
1477 1480
1478 if (frame->GetFormat() == Orthanc::PixelFormat_RGB24) 1481 if (frameProtection->GetFormat() == Orthanc::PixelFormat_RGB24)
1479 { 1482 {
1480 converted.reset(frame.release()); 1483 converted.reset(frameProtection.release());
1481 } 1484 }
1482 else 1485 else
1483 { 1486 {
1484 double a = 1; 1487 double a = 1;
1485 double b = 0; 1488 double b = 0;
1496 { 1499 {
1497 a *= rescaleSlope; 1500 a *= rescaleSlope;
1498 b = rescaleIntercept; 1501 b = rescaleIntercept;
1499 } 1502 }
1500 1503
1501 converted.reset(new Orthanc::Image(Orthanc::PixelFormat_Float32, frame->GetWidth(), frame->GetHeight(), false)); 1504 converted.reset(new Orthanc::Image(Orthanc::PixelFormat_Float32, frameProtection->GetWidth(), frameProtection->GetHeight(), false));
1502 Orthanc::ImageProcessing::Convert(*converted, *frame); 1505 Orthanc::ImageProcessing::Convert(*converted, *frameProtection);
1503 Orthanc::ImageProcessing::ShiftScale2(*converted, b, a, false); 1506 Orthanc::ImageProcessing::ShiftScale2(*converted, b, a, false);
1504 } 1507 }
1505 1508
1506 assert(converted.get() != NULL); 1509 assert(converted.get() != NULL);
1507 viewport.RenderCurrentSceneFromCommand(*converted, sopInstanceUid, frameNumber, DisplayedFrameQuality_High); 1510 viewport.RenderCurrentSceneFromCommand(*converted, sopInstanceUid, frameNumber, DisplayedFrameQuality_High);
1854 lock->Schedule( 1857 lock->Schedule(
1855 GetSharedObserver(), priority, OrthancStone::ParseDicomFromWadoCommand::Create( 1858 GetSharedObserver(), priority, OrthancStone::ParseDicomFromWadoCommand::Create(
1856 source_, frames_->GetStudyInstanceUid(), frames_->GetSeriesInstanceUid(), 1859 source_, frames_->GetStudyInstanceUid(), frames_->GetSeriesInstanceUid(),
1857 sopInstanceUid, serverSideTranscoding_, 1860 sopInstanceUid, serverSideTranscoding_,
1858 Orthanc::DicomTransferSyntax_LittleEndianExplicit, 1861 Orthanc::DicomTransferSyntax_LittleEndianExplicit,
1859 new SetFullDicomFrame(GetSharedObserver(), sopInstanceUid, frameNumber, priority, isPrefetch))); 1862 new SetFullDicomFrame(GetSharedObserver(), sopInstanceUid, frameNumber, priority, isPrefetch, serverSideTranscoding_)));
1860 } 1863 }
1861 } 1864 }
1862 1865
1863 void ScheduleLoadFullDicomFrame(size_t cursorIndex, 1866 void ScheduleLoadFullDicomFrame(size_t cursorIndex,
1864 int priority, 1867 int priority,
1885 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex); 1888 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex);
1886 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); 1889 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex);
1887 1890
1888 /** 1891 /**
1889 * If the full-resolution DICOM file is already available in the 1892 * If the full-resolution DICOM file is already available in the
1890 * cache of the oracle, skip the loading of the "rendered". 1893 * cache of the oracle, bypass the loading of the "rendered" and
1894 * use the cached DICOM file.
1891 **/ 1895 **/
1892 std::unique_ptr<OrthancStone::WebAssemblyOracle::CachedInstanceAccessor> accessor( 1896 std::unique_ptr<OrthancStone::WebAssemblyOracle::CachedInstanceAccessor> accessor(
1893 context_.AccessCachedInstance(instance.GetSopInstanceUid())); 1897 context_.AccessCachedInstance(instance.GetSopInstanceUid()));
1894 1898
1895 if (accessor.get() != NULL && 1899 if (accessor.get() != NULL &&
1896 accessor->IsValid()) 1900 accessor->IsValid())
1897 { 1901 {
1898 try 1902 try
1899 { 1903 {
1900 SetFullDicomFrame::Apply(*this, accessor->GetDicom(), instance.GetSopInstanceUid(), 1904 std::unique_ptr<Orthanc::ImageAccessor> frame(accessor->GetDicom().DecodeFrame(frameNumber));
1901 frameNumber, priority, isPrefetch); 1905 SetFullDicomFrame::Apply(*this, accessor->GetDicom(), frame.release(), instance.GetSopInstanceUid(), frameNumber);
1902 return; 1906 return; // Success
1903 } 1907 }
1904 catch (Orthanc::OrthancException&) 1908 catch (Orthanc::OrthancException&)
1905 { 1909 {
1906 // This happens in the case of a JPEG2k image unsupported by DCMTK 1910 /**
1911 * This happens if the cached DICOM file uses a transfer
1912 * syntax that is not supported by DCMTK (such as
1913 * JPEG2k). Fallback to "/rendered" in order to re-download
1914 * the DICOM file using server-side transcoding. This
1915 * happens on WRIX dataset.
1916 **/
1907 } 1917 }
1908 } 1918 }
1909 1919
1910 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() == 1920 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() ==
1911 Orthanc::PhotometricInterpretation_Monochrome1); 1921 Orthanc::PhotometricInterpretation_Monochrome1);