Mercurial > hg > orthanc
diff UnitTestsSources/FromDcmtkTests.cpp @ 3893:7a5fa8f307e9 transcoding
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 06 May 2020 12:48:28 +0200 |
parents | 56ce23ba93b7 |
children | 8f7ad4989fec |
line wrap: on
line diff
--- a/UnitTestsSources/FromDcmtkTests.cpp Tue May 05 18:08:51 2020 +0200 +++ b/UnitTestsSources/FromDcmtkTests.cpp Wed May 06 12:48:28 2020 +0200 @@ -1925,535 +1925,7 @@ #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 #include "../Core/DicomNetworking/DicomStoreUserConnection.h" - -#include <dcmtk/dcmjpeg/djrploss.h> // for DJ_RPLossy -#include <dcmtk/dcmjpeg/djrplol.h> // for DJ_RPLossless -#include <dcmtk/dcmjpls/djrparam.h> // for DJLSRepresentationParameter - - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG) -# error Macro ORTHANC_ENABLE_DCMTK_JPEG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) -# error Macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined -#endif - - - -namespace Orthanc -{ - /** - * WARNING: This class might be called from several threads at - * once. Make sure to implement proper locking. - **/ - - class IDicomTranscoder : public boost::noncopyable - { - public: - virtual ~IDicomTranscoder() - { - } - - virtual bool TranscodeToBuffer(std::string& target, - const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - /** - * Transcoding flavor that creates a new parsed DICOM file. A - * "std::set<>" is used to give the possible plugin the - * possibility to do a single parsing for all the possible - * transfer syntaxes. - **/ - virtual DcmFileFormat* TranscodeToParsed(const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - virtual bool HasInplaceTranscode() const = 0; - - /** - * In-place transcoding. This method is preferred for C-STORE. - **/ - virtual bool InplaceTranscode(DcmFileFormat& dicom, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - /** - * Important: Transcoding over the DICOM protocol is only - * implemented towards uncompressed transfer syntaxes. - **/ - static void Store(std::string& sopClassUid /* out */, - std::string& sopInstanceUid /* out */, - DicomStoreUserConnection& connection, - IDicomTranscoder& transcoder, - const void* buffer, - size_t size, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID) - { - std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size)); - if (dicom.get() == NULL || - dicom->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DicomTransferSyntax inputSyntax; - connection.LookupParameters(sopClassUid, sopInstanceUid, inputSyntax, *dicom); - - std::set<DicomTransferSyntax> accepted; - connection.LookupTranscoding(accepted, sopClassUid, inputSyntax); - - if (accepted.find(inputSyntax) != accepted.end()) - { - // No need for transcoding - connection.Store(sopClassUid, sopInstanceUid, *dicom, moveOriginatorAET, moveOriginatorID); - } - else - { - // Transcoding is needed - std::set<DicomTransferSyntax> uncompressedSyntaxes; - - if (accepted.find(DicomTransferSyntax_LittleEndianImplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); - } - - if (accepted.find(DicomTransferSyntax_LittleEndianExplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - } - - if (accepted.find(DicomTransferSyntax_BigEndianExplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_BigEndianExplicit); - } - - std::unique_ptr<DcmFileFormat> transcoded; - - if (transcoder.HasInplaceTranscode()) - { - if (transcoder.InplaceTranscode(*dicom, uncompressedSyntaxes, false)) - { - // In-place transcoding is supported and has succeeded - transcoded.reset(dicom.release()); - } - } - else - { - transcoded.reset(transcoder.TranscodeToParsed(buffer, size, uncompressedSyntaxes, false)); - } - - // WARNING: The "dicom" variable must not be used below this - // point. The "sopInstanceUid" might also have changed (if - // using lossy compression). - - if (transcoded == NULL || - transcoded->getDataset() == NULL) - { - throw OrthancException( - ErrorCode_NotImplemented, - "Cannot transcode from \"" + std::string(GetTransferSyntaxUid(inputSyntax)) + - "\" to an uncompressed syntax for modality: " + - connection.GetParameters().GetRemoteModality().GetApplicationEntityTitle()); - } - else - { - DicomTransferSyntax transcodedSyntax; - - // Sanity check - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, *transcoded) || - accepted.find(transcodedSyntax) == accepted.end()) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - connection.Store(sopClassUid, sopInstanceUid, *transcoded, moveOriginatorAET, moveOriginatorID); - } - } - } - } - - static void Store(std::string& sopClassUid /* out */, - std::string& sopInstanceUid /* out */, - DicomStoreUserConnection& connection, - IDicomTranscoder& transcoder, - const void* buffer, - size_t size) - { - Store(sopClassUid, sopInstanceUid, connection, transcoder, - buffer, size, "", 0 /* Not a C-MOVE */); - } - }; - - - class DcmtkTranscoder : public IDicomTranscoder - { - private: - unsigned int lossyQuality_; - - static uint16_t GetBitsStored(DcmDataset& dataset) - { - uint16_t bitsStored; - if (dataset.findAndGetUint16(DCM_BitsStored, bitsStored).good()) - { - return bitsStored; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing \"Bits Stored\" tag in DICOM instance"); - } - } - - static std::string GetSopInstanceUid(DcmDataset& dataset) - { - const char* v = NULL; - - if (dataset.findAndGetString(DCM_SOPInstanceUID, v).good() && - v != NULL) - { - return std::string(v); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, "File without SOP instance UID"); - } - } - - static void CheckSopInstanceUid(DcmFileFormat& dicom, - const std::string& sopInstanceUid, - bool mustEqual) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - bool ok; - - if (mustEqual) - { - ok = (GetSopInstanceUid(*dicom.getDataset()) == sopInstanceUid); - } - else - { - ok = (GetSopInstanceUid(*dicom.getDataset()) != sopInstanceUid); - } - - if (!ok) - { - throw OrthancException(ErrorCode_InternalError, - mustEqual ? "The SOP instance UID has changed unexpectedly during transcoding" : - "The SOP instance UID has not changed as expected during transcoding"); - } - } - - public: - DcmtkTranscoder() : - lossyQuality_(90) - { - } - - void SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - lossyQuality_ = quality; - } - } - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - virtual DcmFileFormat* TranscodeToParsed(const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size)); - - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (InplaceTranscode(*dicom, allowedSyntaxes, allowNewSopInstanceUid)) - { - return dicom.release(); - } - else - { - return NULL; - } - } - - virtual bool HasInplaceTranscode() const - { - return true; - } - - virtual bool InplaceTranscode(DcmFileFormat& dicom, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomTransferSyntax syntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, dicom)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax"); - } - - const uint16_t bitsStored = GetBitsStored(*dicom.getDataset()); - std::string sourceSopInstanceUid = GetSopInstanceUid(*dicom.getDataset()); - - if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end()) - { - // No transcoding is needed - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - bitsStored == 8) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - bitsStored <= 12) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14SV1) != allowedSyntaxes.end()) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossless parameters(6 /* opt_selection_value */, - 0 /* opt_point_transform */); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, ¶meters)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossless) != allowedSyntaxes.end()) - { - // Check out "dcmjpls/apps/dcmcjpls.cc" - DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */, - OFTrue /* opt_useLosslessProcess */); - - /** - * WARNING: This call results in a segmentation fault if using - * the DCMTK package 3.6.2 from Ubuntu 18.04. - **/ - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, ¶meters)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, true); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - if (allowNewSopInstanceUid && - allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossy) != allowedSyntaxes.end()) - { - // Check out "dcmjpls/apps/dcmcjpls.cc" - DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */, - OFFalse /* opt_useLosslessProcess */); - - /** - * WARNING: This call results in a segmentation fault if using - * the DCMTK package 3.6.2 from Ubuntu 18.04. - **/ - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) - { - CheckSopInstanceUid(dicom, sourceSopInstanceUid, false); - return true; - } - } -#endif - - return false; - } - - - virtual bool TranscodeToBuffer(std::string& target, - const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - std::unique_ptr<DcmFileFormat> transcoded( - TranscodeToParsed(buffer, size, allowedSyntaxes, allowNewSopInstanceUid)); - - if (transcoded.get() == NULL) - { - return false; - } - else - { - if (transcoded->getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - FromDcmtkBridge::SaveToMemoryBuffer(target, *transcoded->getDataset()); - return true; - } - } - }; - - - - class PluginDicomTranscoder: public IDicomTranscoder - { - private: - bool tryDcmtk_; - DcmtkTranscoder dcmtk_; - - protected: - virtual bool TranscodeInternal(std::string& target, - const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - public: - PluginDicomTranscoder(bool tryDcmtk) : - tryDcmtk_(tryDcmtk) - { - } - - virtual bool TranscodeToBuffer(std::string& target, - const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - if (tryDcmtk_) - { - return dcmtk_.TranscodeToBuffer(target, buffer, size, allowedSyntaxes, allowNewSopInstanceUid); - } - else - { - return TranscodeInternal(target, buffer, size, allowedSyntaxes, allowNewSopInstanceUid); - } - } - - virtual DcmFileFormat* TranscodeToParsed(const void* buffer, - size_t size, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - if (tryDcmtk_) - { - return dcmtk_.TranscodeToParsed(buffer, size, allowedSyntaxes, allowNewSopInstanceUid); - } - else - { - std::string transcoded; - if (TranscodeInternal(transcoded, buffer, size, allowedSyntaxes, allowNewSopInstanceUid)) - { - return FromDcmtkBridge::LoadFromMemoryBuffer( - transcoded.empty() ? NULL : transcoded.c_str(), transcoded.size()); - } - else - { - return NULL; - } - } - } - - virtual bool HasInplaceTranscode() const ORTHANC_OVERRIDE - { - return tryDcmtk_; - } - - virtual bool InplaceTranscode(DcmFileFormat& dicom, - const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - if (tryDcmtk_) - { - return dcmtk_.InplaceTranscode(dicom, allowedSyntaxes, allowNewSopInstanceUid); - } - else - { - // "HasInplaceTranscode()" should have been called - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - }; -} - +#include "../Core/DicomParsing/DcmtkTranscoder.h" TEST(Toto, DISABLED_Transcode3) { @@ -2483,7 +1955,7 @@ std::string c, i; try { - IDicomTranscoder::Store(c, i, scu, transcoder, source.c_str(), source.size()); + scu.Transcode(c, i, transcoder, source.c_str(), source.size()); } catch (OrthancException& e) { @@ -2501,8 +1973,6 @@ } - - TEST(Toto, DISABLED_Transcode4) { std::string source; @@ -2534,5 +2004,4 @@ } } - #endif