# HG changeset patch # User Sebastien Jodogne # Date 1745670019 -7200 # Node ID 6450fd850adff00c022c8828abbf9412d47a5ae4 # Parent d9e4d135229b0e3edeb8db79a657f3668ec751b8 added support for more types of DICOM SR diff -r d9e4d135229b -r 6450fd850adf Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp --- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sat Apr 26 11:28:30 2025 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sat Apr 26 14:20:19 2025 +0200 @@ -889,7 +889,7 @@ std::string sopInstanceUid, sopClassUid; if (message.GetInstance(i).LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false) && message.GetInstance(i).LookupStringValue(sopClassUid, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) && - OrthancStone::StringToSopClassUid(sopClassUid) == OrthancStone::SopClassUid_ComprehensiveSR) + OrthancStone::IsStructuredReport(OrthancStone::StringToSopClassUid(sopClassUid))) { std::unique_ptr lock(context_.Lock()); lock->Schedule( @@ -2860,7 +2860,7 @@ **/ bool isMonochrome1 = false; - if (instance.GetSopClassUid() != OrthancStone::SopClassUid_ComprehensiveSR) + if (!OrthancStone::IsStructuredReport(instance.GetSopClassUid())) { isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome1); @@ -3027,7 +3027,7 @@ { lock->RefreshCanvasSize(); - if (instance.GetSopClassUid() == OrthancStone::SopClassUid_ComprehensiveSR) + if (OrthancStone::IsStructuredReport(instance.GetSopClassUid())) { // Fit to the width of the textual report scene.FitTopContent(lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight(), 0.1); @@ -3162,7 +3162,7 @@ try { std::unique_ptr frame; - if (instance.GetSopClassUid() == OrthancStone::SopClassUid_ComprehensiveSR) + if (OrthancStone::IsStructuredReport(instance.GetSopClassUid())) { OrthancStone::DicomStructuredReport report(const_cast(accessor->GetDicom())); frame.reset(report.Render(font_, GetHighlightedColorInternal(), GetAnnotationsColorInternal())); diff -r d9e4d135229b -r 6450fd850adf OrthancStone/Sources/StoneEnumerations.cpp --- a/OrthancStone/Sources/StoneEnumerations.cpp Sat Apr 26 11:28:30 2025 +0200 +++ b/OrthancStone/Sources/StoneEnumerations.cpp Sat Apr 26 14:20:19 2025 +0200 @@ -65,10 +65,78 @@ { return SopClassUid_DicomSeg; } + else if (s == "1.2.840.10008.5.1.4.1.1.88.11") + { + return SopClassUid_BasicTextSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.22") + { + return SopClassUid_EnhancedSR; + } else if (s == "1.2.840.10008.5.1.4.1.1.88.33") { return SopClassUid_ComprehensiveSR; } + else if (s == "1.2.840.10008.5.1.4.1.1.88.34") + { + return SopClassUid_Comprehensive3DSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.35") + { + return SopClassUid_ExtensibleSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.50") + { + return SopClassUid_MammographyCADSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.65") + { + return SopClassUid_ChestCADSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.67") + { + return SopClassUid_XRayRadiationDoseSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.68") + { + return SopClassUid_RadiopharmaceuticalRadiationDoseSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.69") + { + return SopClassUid_ColonCADSR; + } + else if (s == "1.2.840.10008.5.1.4.1.1.88.70") + { + return SopClassUid_ImplantationPlanSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​71") + { + return SopClassUid_AcquisitionContextSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​72") + { + return SopClassUid_SimplifiedAdultEchoSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​73") + { + return SopClassUid_PatientRadiationDoseSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​74") + { + return SopClassUid_PlannedImagingAgentAdministrationSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​75") + { + return SopClassUid_PerformedImagingAgentAdministrationSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​76") + { + return SopClassUid_EnhancedXRayRadiationDoseSR; + } + else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​77") + { + return SopClassUid_WaveformAnnotationSR; + } else { //LOG(INFO) << "Other SOP class UID: " << source; @@ -222,11 +290,40 @@ case SopClassUid_VideoPhotographicImageStorage: return SeriesThumbnailType_Video; - case SopClassUid_ComprehensiveSR: - return SeriesThumbnailType_StructuredReport; + default: + break; + } - default: - return SeriesThumbnailType_Unsupported; + if (IsStructuredReport(sopClassUid)) + { + return SeriesThumbnailType_StructuredReport; + } + else + { + return SeriesThumbnailType_Unsupported; } } + + + bool IsStructuredReport(SopClassUid sopClassUid) + { + return (sopClassUid == SopClassUid_BasicTextSR || + sopClassUid == SopClassUid_EnhancedSR || + sopClassUid == SopClassUid_ComprehensiveSR || + sopClassUid == SopClassUid_Comprehensive3DSR || + sopClassUid == SopClassUid_ExtensibleSR || + sopClassUid == SopClassUid_MammographyCADSR || + sopClassUid == SopClassUid_ChestCADSR || + sopClassUid == SopClassUid_XRayRadiationDoseSR || + sopClassUid == SopClassUid_RadiopharmaceuticalRadiationDoseSR || + sopClassUid == SopClassUid_ColonCADSR || + sopClassUid == SopClassUid_ImplantationPlanSR || + sopClassUid == SopClassUid_AcquisitionContextSR || + sopClassUid == SopClassUid_SimplifiedAdultEchoSR || + sopClassUid == SopClassUid_PatientRadiationDoseSR || + sopClassUid == SopClassUid_PlannedImagingAgentAdministrationSR || + sopClassUid == SopClassUid_PerformedImagingAgentAdministrationSR || + sopClassUid == SopClassUid_EnhancedXRayRadiationDoseSR || + sopClassUid == SopClassUid_WaveformAnnotationSR); + } } diff -r d9e4d135229b -r 6450fd850adf OrthancStone/Sources/StoneEnumerations.h --- a/OrthancStone/Sources/StoneEnumerations.h Sat Apr 26 11:28:30 2025 +0200 +++ b/OrthancStone/Sources/StoneEnumerations.h Sat Apr 26 14:20:19 2025 +0200 @@ -106,6 +106,8 @@ KeyboardKeys_F12 = 123, }; + + // https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_b.5.html enum SopClassUid { SopClassUid_Other, @@ -117,7 +119,26 @@ SopClassUid_VideoMicroscopicImageStorage, SopClassUid_VideoPhotographicImageStorage, SopClassUid_DicomSeg, - SopClassUid_ComprehensiveSR + + // All the possible DICOM-SR + SopClassUid_BasicTextSR, + SopClassUid_EnhancedSR, + SopClassUid_ComprehensiveSR, + SopClassUid_Comprehensive3DSR, + SopClassUid_ExtensibleSR, + SopClassUid_MammographyCADSR, + SopClassUid_ChestCADSR, + SopClassUid_XRayRadiationDoseSR, + SopClassUid_RadiopharmaceuticalRadiationDoseSR, + SopClassUid_ColonCADSR, + SopClassUid_ImplantationPlanSR, + SopClassUid_AcquisitionContextSR, + SopClassUid_SimplifiedAdultEchoSR, + SopClassUid_PatientRadiationDoseSR, + SopClassUid_PlannedImagingAgentAdministrationSR, + SopClassUid_PerformedImagingAgentAdministrationSR, + SopClassUid_EnhancedXRayRadiationDoseSR, + SopClassUid_WaveformAnnotationSR }; enum SeriesThumbnailType @@ -184,4 +205,6 @@ unsigned int border = 0); SeriesThumbnailType GetSeriesThumbnailType(SopClassUid sopClassUid); + + bool IsStructuredReport(SopClassUid sopClassUid); } diff -r d9e4d135229b -r 6450fd850adf OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp --- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp Sat Apr 26 11:28:30 2025 +0200 +++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp Sat Apr 26 14:20:19 2025 +0200 @@ -651,8 +651,9 @@ seriesInstanceUid_ = GetStringValue(dataset, DCM_SeriesInstanceUID); sopInstanceUid_ = GetStringValue(dataset, DCM_SOPInstanceUID); - SopClassUid sopClassUid = StringToSopClassUid(GetStringValue(dataset, DCM_SOPClassUID)); - if (sopClassUid != SopClassUid_ComprehensiveSR) + std::string sopClassUidString = GetStringValue(dataset, DCM_SOPClassUID); + SopClassUid sopClassUid = StringToSopClassUid(sopClassUidString); + if (!IsStructuredReport(sopClassUid)) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } @@ -674,7 +675,8 @@ ReadTextualReport(textualReport_, dataset); - if (IsDicomConcept(dataset, "126000") /* Imaging measurement report */ && + if (sopClassUid == SopClassUid_ComprehensiveSR && + IsDicomConcept(dataset, "126000") /* Imaging measurement report */ && IsDicomTemplate(dataset, "1500") && dataset.tagExists(DCM_CurrentRequestedProcedureEvidenceSequence)) {