# HG changeset patch # User Alain Mazy # Date 1724927621 -7200 # Node ID 078b724dcbf8df5e69d9a4f94407c49cbcef277f # Parent ead98edd5bbffa942a7e0e02ab182937c1ed761e if frame decoding fails, transcode to LittleEndianExplicit using plugins and decode with built-in decoder diff -r ead98edd5bbf -r 078b724dcbf8 NEWS --- a/NEWS Tue Aug 27 15:14:22 2024 +0200 +++ b/NEWS Thu Aug 29 12:33:41 2024 +0200 @@ -23,6 +23,11 @@ at the same time. * Upgraded dependencies for static builds: - curl 8.9.0 +* Added a new fallback when trying to decode a frame: transcode the file using the plugin + before decoding the frame. This solves some issues with JP2K Lossy compression: + https://discourse.orthanc-server.org/t/decoding-displaying-jpeg2000-lossy-images/5117 +* Added a new warning that can be disabled in the configuration: W003_DecoderFailure + Version 1.12.4 (2024-06-05) diff -r ead98edd5bbf -r 078b724dcbf8 OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Tue Aug 27 15:14:22 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Thu Aug 29 12:33:41 2024 +0200 @@ -949,12 +949,12 @@ { throw OrthancException(ErrorCode_NotImplemented, "The built-in DCMTK decoder cannot decode some DICOM instance " - "whose transfer syntax is: " + std::string(GetTransferSyntaxUid(s))); + "whose transfer syntax is: " + std::string(GetTransferSyntaxUid(s)), false /* don't log here*/); } else { throw OrthancException(ErrorCode_NotImplemented, - "The built-in DCMTK decoder cannot decode some DICOM instance"); + "The built-in DCMTK decoder cannot decode some DICOM instance", false /* don't log here*/); } } diff -r ead98edd5bbf -r 078b724dcbf8 OrthancServer/Resources/Configuration.json --- a/OrthancServer/Resources/Configuration.json Tue Aug 27 15:14:22 2024 +0200 +++ b/OrthancServer/Resources/Configuration.json Thu Aug 29 12:33:41 2024 +0200 @@ -986,7 +986,11 @@ // your response might be incomplete/inconsistent. // You should call patients|studies|series|instances/../reconstruct to rebuild // the DB. You may also check for the "Housekeeper" plugin - "W002_InconsistentDicomTagsInDb": true + "W002_InconsistentDicomTagsInDb": true, + + // Display a warning message when Orthanc and its plugins are unable + // to decode a frame (new in Orthanc 1.12.5). + "W003_DecoderFailure": true } } diff -r ead98edd5bbf -r 078b724dcbf8 OrthancServer/Sources/OrthancConfiguration.cpp --- a/OrthancServer/Sources/OrthancConfiguration.cpp Tue Aug 27 15:14:22 2024 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.cpp Thu Aug 29 12:33:41 2024 +0200 @@ -1157,6 +1157,10 @@ { warning = Warnings_002_InconsistentDicomTagsInDb; } + else if (name == "W003_DecoderFailure") + { + warning = Warnings_003_DecoderFailure; + } else { throw OrthancException(ErrorCode_BadFileFormat, name + " is not recognized as a valid warning name"); diff -r ead98edd5bbf -r 078b724dcbf8 OrthancServer/Sources/ServerContext.cpp --- a/OrthancServer/Sources/ServerContext.cpp Tue Aug 27 15:14:22 2024 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Thu Aug 29 12:33:41 2024 +0200 @@ -1902,13 +1902,52 @@ if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) { - ServerContext::DicomCacheLocker locker(*this, publicId); - return locker.GetDicom().DecodeFrame(frameIndex); + ServerContext::DicomCacheLocker locker(*this, publicId); + try + { + std::unique_ptr decoded(locker.GetDicom().DecodeFrame(frameIndex)); + + if (decoded.get() != NULL) + { + return decoded.release(); + } + } + catch (OrthancException& e) + { + LOG(INFO) << e.GetDetails(); + } } - else + + if (HasPlugins() && GetPlugins().HasCustomTranscoder()) { - return NULL; // Built-in decoder is disabled + // TODO: Store the raw buffer in the DicomCacheLocker + std::string dicomContent; + ReadDicom(dicomContent, publicId); + + LOG(INFO) << "The plugins and built-in image decoders failed to decode a frame, " + << "trying to transcode the file to LittleEndianExplicit using the plugins."; + DicomImage explicitTemporaryImage; + DicomImage source; + std::set allowedSyntaxes; + + source.AcquireBuffer(dicomContent); + allowedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); + + if (Transcode(explicitTemporaryImage, source, allowedSyntaxes, true)) + { + std::unique_ptr file(explicitTemporaryImage.ReleaseAsParsedDicomFile()); + return file->DecodeFrame(frameIndex); + } + } + + OrthancConfiguration::ReaderLock lock; + if (lock.GetConfiguration().IsWarningEnabled(Warnings_003_DecoderFailure)) + { + LOG(WARNING) << "W003: Unable to decode frame " << frameIndex << " from instance " << publicId; + } + + return NULL; } diff -r ead98edd5bbf -r 078b724dcbf8 OrthancServer/Sources/ServerEnumerations.h --- a/OrthancServer/Sources/ServerEnumerations.h Tue Aug 27 15:14:22 2024 +0200 +++ b/OrthancServer/Sources/ServerEnumerations.h Thu Aug 29 12:33:41 2024 +0200 @@ -206,6 +206,7 @@ Warnings_None, Warnings_001_TagsBeingReadFromStorage, Warnings_002_InconsistentDicomTagsInDb, + Warnings_003_DecoderFailure, // new in Orthanc 1.12.5 }; diff -r ead98edd5bbf -r 078b724dcbf8 TODO --- a/TODO Tue Aug 27 15:14:22 2024 +0200 +++ b/TODO Thu Aug 29 12:33:41 2024 +0200 @@ -67,7 +67,7 @@ * Write a getting started guide (step by step) for each platform to replace https://orthanc.uclouvain.be/book/users/cookbook.html : - Ubuntu/Debian - - Windows + - Windows (done) - OSX - Docker on Linux Each step by step guide should contain: @@ -149,7 +149,7 @@ https://groups.google.com/g/orthanc-users/c/hsZ1jng5rIg/m/8xZL2C1VBgAJ * add an "AutoDeleteIfSuccessful": false option when creating jobs https://discourse.orthanc-server.org/t/job-history-combined-with-auto-forwarding/3729/10 -* Allow skiping automatic conversion of color-space in transcoding/decoding. +* Allow skipping automatic conversion of color-space in transcoding/decoding. The patch that was initialy provided was breaking the IngestTranscoding. This might require a DCMTK decoding plugin ? https://discourse.orthanc-server.org/t/orthanc-convert-ybr-to-rgb-but-does-not-change-metadata/3533/9