Mercurial > hg > orthanc-stone
changeset 2261:d212eabd6440
cleanup
| author | Sebastien Jodogne <s.jodogne@gmail.com> |
|---|---|
| date | Wed, 03 Dec 2025 18:31:28 +0100 |
| parents | e8c876f65c56 |
| children | b3219cfccd3d |
| files | Applications/StoneWebViewer/NEWS OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h |
| diffstat | 3 files changed, 49 insertions(+), 213 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/NEWS Wed Dec 03 18:11:55 2025 +0100 +++ b/Applications/StoneWebViewer/NEWS Wed Dec 03 18:31:28 2025 +0100 @@ -20,6 +20,7 @@ * Improved support of the (0028,9132) tag for Philips multiframe images * Use "ImagerPixelSpacing" (0018,1164) tag if "PixelSpacing" is missing * Added safeguard against US images containing regions with negative "PhysicalDeltaX" value +* Fix compatibility of videos with DICOMweb plugin >= 1.19 Version 2.6 (2024-08-31)
--- a/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp Wed Dec 03 18:11:55 2025 +0100 +++ b/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp Wed Dec 03 18:31:28 2025 +0100 @@ -82,16 +82,16 @@ switch (mime) { - case Orthanc::MimeType_Jpeg: - { - std::unique_ptr<Orthanc::JpegReader> reader(new Orthanc::JpegReader); - reader->ReadFromMemory(GetEncodedImage()); - return reader.release(); - } + case Orthanc::MimeType_Jpeg: + { + std::unique_ptr<Orthanc::JpegReader> reader(new Orthanc::JpegReader); + reader->ReadFromMemory(GetEncodedImage()); + return reader.release(); + } - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, - "Cannot decode MIME type for thumbnail: " + GetMime()); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, + "Cannot decode MIME type for thumbnail: " + GetMime()); } } @@ -188,70 +188,6 @@ }; - class SeriesThumbnailsLoader::DicomWebSopClassHandler : public SeriesThumbnailsLoader::Handler - { - private: - static bool GetSopClassUid(std::string& sopClassUid, - const Json::Value& json) - { - Orthanc::DicomMap dicom; - dicom.FromDicomWeb(json); - - return dicom.LookupStringValue(sopClassUid, Orthanc::DICOM_TAG_SOP_CLASS_UID, false); - } - - public: - DicomWebSopClassHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, - const DicomSource& source, - const std::string& studyInstanceUid, - const std::string& seriesInstanceUid) : - Handler(loader, source, studyInstanceUid, seriesInstanceUid) - { - } - - virtual void HandleSuccess(const std::string& body, - const std::map<std::string, std::string>& headers) ORTHANC_OVERRIDE - { - Json::Value value; - - if (!Orthanc::Toolbox::ReadJson(value, body) || - value.type() != Json::arrayValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - else - { - SeriesThumbnailType type = SeriesThumbnailType_Unsupported; - - std::string sopClassUid; - if (value.size() > 0 && - GetSopClassUid(sopClassUid, value[0])) - { - bool ok = true; - - for (Json::Value::ArrayIndex i = 1; i < value.size() && ok; i++) - { - std::string s; - if (!GetSopClassUid(s, value[i]) || - s != sopClassUid) - { - ok = false; - } - } - - if (ok) - { - type = GetSeriesThumbnailType(StringToSopClassUid(sopClassUid)); - } - } - - GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(), - GetSeriesInstanceUid(), new Thumbnail(type)); - } - } - }; - - class SeriesThumbnailsLoader::DicomWebThumbnailHandler : public SeriesThumbnailsLoader::Handler { public: @@ -282,19 +218,9 @@ virtual void HandleError() ORTHANC_OVERRIDE { - // The DICOMweb wasn't able to generate a thumbnail, try to - // retrieve the SopClassUID tag using QIDO-RS - - std::map<std::string, std::string> arguments, headers; - arguments["0020000D"] = GetStudyInstanceUid(); - arguments["0020000E"] = GetSeriesInstanceUid(); - arguments["includefield"] = "00080016"; // SOP Class UID - - std::unique_ptr<IOracleCommand> command( - GetSource().CreateDicomWebCommand( - "/instances", arguments, headers, new DicomWebSopClassHandler( - GetLoader(), GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid()))); - GetLoader()->Schedule(command.release()); + // The DICOMweb wasn't able to generate a thumbnail + GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(), + GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Unsupported)); } }; @@ -373,10 +299,10 @@ }; - class SeriesThumbnailsLoader::SelectOrthancInstanceHandler : public SeriesThumbnailsLoader::Handler + class SeriesThumbnailsLoader::OrthancSelectInstanceHandler : public SeriesThumbnailsLoader::Handler { public: - SelectOrthancInstanceHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, + OrthancSelectInstanceHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, const DicomSource& source, const std::string& studyInstanceUid, const std::string& seriesInstanceUid) : @@ -418,19 +344,21 @@ }; - class SeriesThumbnailsLoader::DicomWebGetOneInstanceInSeriesHandler : public SeriesThumbnailsLoader::Handler + class SeriesThumbnailsLoader::DicomWebSelectInstanceHandler : public SeriesThumbnailsLoader::Handler { private: - void LogError() const + void LogError() { LOG(ERROR) << "Cannot download one instance from series: " << GetSeriesInstanceUid(); + GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(), + GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Unsupported)); } public: - DicomWebGetOneInstanceInSeriesHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, - const DicomSource& source, - const std::string& studyInstanceUid, - const std::string& seriesInstanceUid) : + DicomWebSelectInstanceHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, + const DicomSource& source, + const std::string& studyInstanceUid, + const std::string& seriesInstanceUid) : Handler(loader, source, studyInstanceUid, seriesInstanceUid) { } @@ -454,31 +382,27 @@ Orthanc::DicomMap instance; instance.FromDicomWeb(instances[0]); - std::unique_ptr<IOracleCommand> command; - std::string sopInstanceUid; std::string sopClassUid; if (instance.LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false) && instance.LookupStringValue(sopClassUid, Orthanc::DICOM_TAG_SOP_CLASS_UID, false)) { - switch (StringToSopClassUid(sopClassUid)) + SeriesThumbnailType type = GetSeriesThumbnailType(StringToSopClassUid(sopClassUid)); + + if (type == SeriesThumbnailType_Pdf || + type == SeriesThumbnailType_Video || + type == SeriesThumbnailType_Image || + type == SeriesThumbnailType_StructuredReport) { - case SopClassUid_VideoEndoscopicImageStorage: - case SopClassUid_VideoMicroscopicImageStorage: - case SopClassUid_VideoPhotographicImageStorage: GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(), - GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Video)); - break; + GetSeriesInstanceUid(), new Thumbnail(type)); + } + else + { + std::unique_ptr<IOracleCommand> command; - case SopClassUid_EncapsulatedPdf: - GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(), - GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Pdf)); - break; - - default: if (GetSource().HasDicomWebRendered()) { - LOG(ERROR) << "OOOOO"; // By default, rely on server-side rendering const std::string uri = ("/studies/" + GetStudyInstanceUid() + @@ -511,12 +435,10 @@ #endif } - break; - } - - if (command.get() != NULL) - { - GetLoader()->Schedule(command.release()); + if (command.get() != NULL) + { + GetLoader()->Schedule(command.release()); + } } } else @@ -533,51 +455,6 @@ }; -#if ORTHANC_ENABLE_DCMTK == 1 - class SeriesThumbnailsLoader::SelectDicomWebInstanceHandler : public SeriesThumbnailsLoader::Handler - { - public: - SelectDicomWebInstanceHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader, - const DicomSource& source, - const std::string& studyInstanceUid, - const std::string& seriesInstanceUid) : - Handler(loader, source, studyInstanceUid, seriesInstanceUid) - { - } - - virtual void HandleSuccess(const std::string& body, - const std::map<std::string, std::string>& headers) ORTHANC_OVERRIDE - { - Json::Value json; - if (!Orthanc::Toolbox::ReadJson(json, body) || - json.type() != Json::arrayValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - LoadedDicomResources instances(Orthanc::DICOM_TAG_SOP_INSTANCE_UID); - instances.AddFromDicomWeb(json); - - std::string sopInstanceUid; - if (instances.GetSize() == 0 || - !instances.GetResource(0).LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false)) - { - LOG(ERROR) << "Series without an instance: " << GetSeriesInstanceUid(); - } - else - { - GetLoader()->Schedule( - ParseDicomFromWadoCommand::Create( - GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid(), sopInstanceUid, false, - Orthanc::DicomTransferSyntax_LittleEndianExplicit /* useless, as no transcoding */, - new ThumbnailInformation( - GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid()))); - } - } - }; -#endif - - void SeriesThumbnailsLoader::Schedule(IOracleCommand* command) { std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); @@ -798,61 +675,20 @@ if (source.IsDicomWeb()) { { + // Run a QIDO-RS request to get 1 instance in the series std::map<std::string, std::string> arguments, headers; arguments["0020000D"] = studyInstanceUid; arguments["0020000E"] = seriesInstanceUid; - arguments["includefield"] = "00080016"; // SOP Class UID + arguments["includefield"] = "00080016"; // Request SOP Class UID arguments["limit"] = "1"; std::unique_ptr<IOracleCommand> command( source.CreateDicomWebCommand( - "/instances", arguments, headers, new DicomWebGetOneInstanceInSeriesHandler( + "/instances", arguments, headers, new DicomWebSelectInstanceHandler( GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid))); Schedule(command.release()); } -#if 0 - if (!source.HasDicomWebRendered()) - { -#if ORTHANC_ENABLE_DCMTK == 1 - // Issue a QIDO-RS request to select one of the instances in the series - std::map<std::string, std::string> arguments, headers; - arguments["0020000D"] = studyInstanceUid; - arguments["0020000E"] = seriesInstanceUid; - arguments["includefield"] = "00080018"; // SOP Instance UID is mandatory - - std::unique_ptr<IOracleCommand> command( - source.CreateDicomWebCommand( - "/instances", arguments, headers, new SelectDicomWebInstanceHandler( - GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid))); - Schedule(command.release()); -#else - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, - "Stone of Orthanc was built without support to decode DICOM images"); -#endif - } - else - { - const std::string uri = ("/studies/" + studyInstanceUid + - "/series/" + seriesInstanceUid + "/rendered"); - - std::map<std::string, std::string> arguments, headers; - arguments["viewport"] = (boost::lexical_cast<std::string>(width_) + "," + - boost::lexical_cast<std::string>(height_)); - - // Needed to set this header explicitly, as long as emscripten - // does not include macro "EMSCRIPTEN_FETCH_RESPONSE_HEADERS" - // https://github.com/emscripten-core/emscripten/pull/8486 - headers["Accept"] = Orthanc::MIME_JPEG; - - std::unique_ptr<IOracleCommand> command( - source.CreateDicomWebCommand( - uri, arguments, headers, new DicomWebThumbnailHandler( - GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid))); - Schedule(command.release()); - } -#endif - scheduledSeries_.insert(seriesInstanceUid); } else if (source.IsOrthanc()) @@ -862,7 +698,7 @@ std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); command->SetUri("/series/" + hasher.HashSeries()); - command->AcquirePayload(new SelectOrthancInstanceHandler( + command->AcquirePayload(new OrthancSelectInstanceHandler( GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid)); Schedule(command.release());
--- a/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h Wed Dec 03 18:11:55 2025 +0100 +++ b/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h Wed Dec 03 18:31:28 2025 +0100 @@ -135,17 +135,16 @@ private: class Handler; - class DicomWebSopClassHandler; - class DicomWebThumbnailHandler; class ThumbnailInformation; + + // To load from an Orthanc server class OrthancSopClassHandler; - class SelectOrthancInstanceHandler; - class DicomWebGetOneInstanceInSeriesHandler; + class OrthancSelectInstanceHandler; -#if ORTHANC_ENABLE_DCMTK == 1 - class SelectDicomWebInstanceHandler; -#endif - + // To load from a DICOMweb server + class DicomWebThumbnailHandler; + class DicomWebSelectInstanceHandler; + // Maps a "Series Instance UID" to a thumbnail typedef std::map<std::string, Thumbnail*> Thumbnails;
