Mercurial > hg > orthanc-wsi
changeset 389:7954645ed874
reimplemented jpeg-ls for older version of DCMTK
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 08 Apr 2025 14:47:47 +0200 |
parents | a7194a77c591 |
children | 7c787ee1f3ae |
files | Framework/ImageToolbox.cpp Framework/ImageToolbox.h Framework/Outputs/DicomPyramidWriter.cpp Framework/Outputs/DicomPyramidWriter.h Framework/Outputs/HierarchicalTiffWriter.cpp Framework/Outputs/HierarchicalTiffWriter.h Framework/Outputs/MultiframeDicomWriter.cpp Framework/Outputs/PyramidWriterBase.cpp Framework/Outputs/PyramidWriterBase.h |
diffstat | 9 files changed, 107 insertions(+), 100 deletions(-) [+] |
line wrap: on
line diff
--- a/Framework/ImageToolbox.cpp Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/ImageToolbox.cpp Tue Apr 08 14:47:47 2025 +0200 @@ -27,13 +27,6 @@ #include "Jpeg2000Reader.h" #include "Jpeg2000Writer.h" -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -# include <DicomParsing/DcmtkTranscoder.h> -# include <DicomParsing/ParsedDicomFile.h> -# include <DicomParsing/FromDcmtkBridge.h> -# include <dcmtk/dcmdata/dcpxitem.h> -#endif - #include <Compatibility.h> // For std::unique_ptr #include <OrthancException.h> #include <Images/ImageProcessing.h> @@ -176,6 +169,20 @@ } + void EncodeUncompressedTile(std::string& target, + const Orthanc::ImageAccessor& source) + { + unsigned int pitch = GetBytesPerPixel(source.GetFormat()) * source.GetWidth(); + target.resize(pitch * source.GetHeight()); + + const unsigned int height = source.GetHeight(); + for (unsigned int i = 0; i < height; i++) + { + memcpy(&target[i * pitch], source.GetConstRow(i), pitch); + } + } + + void EncodeTile(std::string& target, const Orthanc::ImageAccessor& source, ImageCompression compression, @@ -183,22 +190,7 @@ { if (compression == ImageCompression_None) { - unsigned int pitch = GetBytesPerPixel(source.GetFormat()) * source.GetWidth(); - target.resize(pitch * source.GetHeight()); - - const unsigned int height = source.GetHeight(); - for (unsigned int i = 0; i < height; i++) - { - memcpy(&target[i * pitch], source.GetConstRow(i), pitch); - } - } - else if (compression == ImageCompression_JpegLS) - { -#if (ORTHANC_ENABLE_DCMTK_TRANSCODING == 1) && (ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1) - CompressFrameUsingDcmtk(target, source, Orthanc::DicomTransferSyntax_JPEGLSLossless); -#else - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DCMTK was compiled without support for JPEG-LS"); -#endif + EncodeUncompressedTile(target, source); } else { @@ -420,59 +412,5 @@ p[3] == 0xe1); } } - - -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - void CompressFrameUsingDcmtk(std::string& target, - const Orthanc::ImageAccessor& frame, - Orthanc::DicomTransferSyntax syntax) - { - if (frame.GetFormat() != Orthanc::PixelFormat_RGB24) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - Orthanc::ParsedDicomFile dicom(true); - dicom.EmbedImage(frame); - - Orthanc::IDicomTranscoder::DicomImage source; - source.AcquireParsed(dicom); // "dicom" is invalid below this point - - Orthanc::IDicomTranscoder::DicomImage transcoded; - - std::set<Orthanc::DicomTransferSyntax> s; - s.insert(syntax); - - Orthanc::DcmtkTranscoder transcoder(1); - - if (transcoder.Transcode(transcoded, source, s, true)) - { - DcmPixelSequence* pixelSequence = Orthanc::FromDcmtkBridge::GetPixelSequence(*transcoded.GetParsed().getDataset()); - - DcmPixelItem* compressed = NULL; - Uint8* data = NULL; - if (pixelSequence != NULL && - pixelSequence->card() == 2 && - pixelSequence->getItem(compressed, 1).good() && - compressed != NULL && - compressed->getUint8Array(data).good() && - data != NULL) - { - const unsigned int size = compressed->getNumberOfValues(); - - target.resize(size); - if (size != 0) - { - memcpy(&target[0], data, size); - } - - return; // Success - } - } - - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DCMTK cannot transcode to " + - std::string(Orthanc::GetTransferSyntaxUid(syntax))); - } -#endif } }
--- a/Framework/ImageToolbox.h Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/ImageToolbox.h Tue Apr 08 14:47:47 2025 +0200 @@ -58,6 +58,9 @@ unsigned int width, unsigned int height); + void EncodeUncompressedTile(std::string& target, + const Orthanc::ImageAccessor& source); + void EncodeTile(std::string& target, const Orthanc::ImageAccessor& source, ImageCompression compression, @@ -81,11 +84,5 @@ bool HasPngSignature(const std::string& buffer); bool HasJpegSignature(const std::string& buffer); - -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - void CompressFrameUsingDcmtk(std::string& target, - const Orthanc::ImageAccessor& frame, - Orthanc::DicomTransferSyntax syntax); -#endif } }
--- a/Framework/Outputs/DicomPyramidWriter.cpp Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/DicomPyramidWriter.cpp Tue Apr 08 14:47:47 2025 +0200 @@ -25,6 +25,7 @@ #include "DicomPyramidWriter.h" #include "../DicomToolbox.h" +#include "../ImageToolbox.h" #include <Compatibility.h> // For std::unique_ptr #include <Logging.h> @@ -198,6 +199,21 @@ } + void DicomPyramidWriter::EncodeTileInternal(std::string& encoded, + const Orthanc::ImageAccessor& tile) + { + if (GetImageCompression() == ImageCompression_JpegLS) + { + // For JPEG-LS, images are first store uncompressed, then transcoded in "MultiframeDicomWriter" + ImageToolbox::EncodeUncompressedTile(encoded, tile); + } + else + { + ImageToolbox::EncodeTile(encoded, tile, GetImageCompression(), GetJpegQuality()); + } + } + + DicomPyramidWriter::DicomPyramidWriter(IFileTarget& target, const DcmDataset& dataset, Orthanc::PixelFormat pixelFormat,
--- a/Framework/Outputs/DicomPyramidWriter.h Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/DicomPyramidWriter.h Tue Apr 08 14:47:47 2025 +0200 @@ -65,6 +65,9 @@ { } + virtual void EncodeTileInternal(std::string& encoded, + const Orthanc::ImageAccessor& tile) ORTHANC_OVERRIDE; + public: DicomPyramidWriter(IFileTarget& target, const DcmDataset& dataset,
--- a/Framework/Outputs/HierarchicalTiffWriter.cpp Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/HierarchicalTiffWriter.cpp Tue Apr 08 14:47:47 2025 +0200 @@ -24,6 +24,8 @@ #include "../PrecompiledHeadersWSI.h" #include "HierarchicalTiffWriter.h" +#include "../ImageToolbox.h" + #include <Logging.h> #include <OrthancException.h> #include <TemporaryFile.h> @@ -415,6 +417,13 @@ } + void HierarchicalTiffWriter::EncodeTileInternal(std::string& encoded, + const Orthanc::ImageAccessor& tile) + { + ImageToolbox::EncodeTile(encoded, tile, GetImageCompression(), GetJpegQuality()); + } + + HierarchicalTiffWriter::HierarchicalTiffWriter(const std::string& path, Orthanc::PixelFormat pixelFormat, ImageCompression compression,
--- a/Framework/Outputs/HierarchicalTiffWriter.h Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/HierarchicalTiffWriter.h Tue Apr 08 14:47:47 2025 +0200 @@ -75,6 +75,8 @@ virtual void AddLevelInternal(const Level& level) ORTHANC_OVERRIDE; + virtual void EncodeTileInternal(std::string& encoded, + const Orthanc::ImageAccessor& tile) ORTHANC_OVERRIDE; public: HierarchicalTiffWriter(const std::string& path,
--- a/Framework/Outputs/MultiframeDicomWriter.cpp Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/MultiframeDicomWriter.cpp Tue Apr 08 14:47:47 2025 +0200 @@ -31,6 +31,10 @@ #include <Logging.h> #include <OrthancException.h> +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 +# include <DicomParsing/DcmtkTranscoder.h> +#endif + #include <dcmtk/dcmdata/dcuid.h> #include <dcmtk/dcmdata/dcdeftag.h> #include <dcmtk/dcmdata/dcostrmb.h> @@ -255,7 +259,8 @@ // Free the functional group on error std::unique_ptr<DcmItem> functionalGroupRaii(functionalGroup); - if (compression_ == ImageCompression_None) + if (compression_ == ImageCompression_None || + compression_ == ImageCompression_JpegLS) { if (frame.size() != uncompressedFrameSize_) { @@ -317,25 +322,58 @@ DicomToolbox::SetUint16Tag(*dicom->getDataset(), DCM_InConcatenationNumber, countInstances_); } - switch (compression_) + if (compression_ == ImageCompression_JpegLS) { - case ImageCompression_None: - InjectUncompressedPixelData(*dicom); - break; +#if (ORTHANC_ENABLE_DCMTK_TRANSCODING == 1) && (ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1) + const Orthanc::DicomTransferSyntax syntax = Orthanc::DicomTransferSyntax_JPEGLSLossless; + + InjectUncompressedPixelData(*dicom); + + Orthanc::IDicomTranscoder::DicomImage source; + source.AcquireParsed(dicom.release()); // "dicom" is invalid below this point + + std::set<Orthanc::DicomTransferSyntax> s; + s.insert(syntax); + + Orthanc::IDicomTranscoder::DicomImage transcoded; - case ImageCompression_Jpeg: - case ImageCompression_Jpeg2000: - case ImageCompression_JpegLS: - offsetTable_->createOffsetTable(*offsetList_); - dicom->getDataset()->insert(compressedPixelSequence_.release()); - break; + Orthanc::DcmtkTranscoder transcoder(1); + if (transcoder.Transcode(transcoded, source, s, true)) + { + ResetImage(); + SaveDicomToMemory(target, transcoded.GetParsed(), transferSyntax_); + return; // Success + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DCMTK cannot transcode to " + + std::string(Orthanc::GetTransferSyntaxUid(syntax))); + } +#else + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DCMTK was compiled without support for JPEG-LS"); +#endif + } + else + { + switch (compression_) + { + case ImageCompression_None: + InjectUncompressedPixelData(*dicom); + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } + case ImageCompression_Jpeg: + case ImageCompression_Jpeg2000: + offsetTable_->createOffsetTable(*offsetList_); + dicom->getDataset()->insert(compressedPixelSequence_.release()); + break; - ResetImage(); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } - SaveDicomToMemory(target, *dicom, transferSyntax_); + ResetImage(); + + SaveDicomToMemory(target, *dicom, transferSyntax_); + } } }
--- a/Framework/Outputs/PyramidWriterBase.cpp Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/PyramidWriterBase.cpp Tue Apr 08 14:47:47 2025 +0200 @@ -148,7 +148,8 @@ const Level level = GetLevel(z); std::string raw; - ImageToolbox::EncodeTile(raw, tile, compression_, jpegQuality_); + EncodeTileInternal(raw, tile); + WriteRawTileInternal(raw, level, x, y); } }
--- a/Framework/Outputs/PyramidWriterBase.h Tue Apr 08 13:11:27 2025 +0200 +++ b/Framework/Outputs/PyramidWriterBase.h Tue Apr 08 14:47:47 2025 +0200 @@ -51,6 +51,9 @@ // This function is invoked before any call to WriteRawTileInternal() virtual void AddLevelInternal(const Level& level) = 0; + virtual void EncodeTileInternal(std::string& encoded, + const Orthanc::ImageAccessor& tile) = 0; + private: boost::mutex mutex_; // This mutex protects access to the levels Orthanc::PixelFormat pixelFormat_;