view OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h @ 5911:bfae0fc2ea1b get-scu-test

Started to work on handling errors as warnings when trying to store instances whose SOPClassUID has not been accepted during the negotiation. Work to be finalized later
author Alain Mazy <am@orthanc.team>
date Mon, 09 Dec 2024 10:07:19 +0100
parents f7adfb22e20e
children
line wrap: on
line source

/**
 * Orthanc - A Lightweight, RESTful DICOM Store
 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
 * Department, University Hospital of Liege, Belgium
 * Copyright (C) 2017-2023 Osimis S.A., Belgium
 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 **/


#pragma once

#include "../OrthancFramework.h"

#if !defined(ORTHANC_ENABLE_JPEG)
#  error Macro ORTHANC_ENABLE_JPEG must be defined to use this file
#endif

#if !defined(ORTHANC_ENABLE_PNG)
#  error Macro ORTHANC_ENABLE_PNG must be defined to use this file
#endif

#if !defined(ORTHANC_ENABLE_CIVETWEB)
#  error Macro ORTHANC_ENABLE_CIVETWEB must be defined to use this file
#endif

#if !defined(ORTHANC_ENABLE_MONGOOSE)
#  error Macro ORTHANC_ENABLE_MONGOOSE must be defined to use this file
#endif

#if !defined(ORTHANC_SANDBOXED)
#  error The macro ORTHANC_SANDBOXED must be defined
#endif

#if !defined(ORTHANC_ENABLE_DCMTK)
#  error The macro ORTHANC_ENABLE_DCMTK must be defined
#endif

#if ORTHANC_ENABLE_DCMTK != 1
#  error The macro ORTHANC_ENABLE_DCMTK must be set to 1 to use this file
#endif

#include "ITagVisitor.h"
#include "../DicomFormat/DicomInstanceHasher.h"
#include "../DicomFormat/DicomPath.h"
#include "../Images/ImageAccessor.h"
#include "../IDynamicObject.h"
#include "../Toolbox.h"

#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
#  include "../RestApi/RestApiOutput.h"
#endif

#include <boost/shared_ptr.hpp>


class DcmDataset;
class DcmFileFormat;

namespace Orthanc
{
  class ORTHANC_PUBLIC ParsedDicomFile : public IDynamicObject
  {
  private:
    struct PImpl;
    boost::shared_ptr<PImpl> pimpl_;

    ParsedDicomFile(const ParsedDicomFile& other,
                    bool keepSopInstanceUid);

    void CreateFromDicomMap(const DicomMap& source,
                            Encoding defaultEncoding,
                            bool permissive,
                            const std::string& defaultPrivateCreator,
                            const std::map<uint16_t, std::string>& privateCreators);

    void RemovePrivateTagsInternal(const std::set<DicomTag>* toKeep);

    void UpdateStorageUid(const DicomTag& tag,
                          const std::string& value,
                          bool decodeDataUriScheme);

    void InvalidateCache();

    bool EmbedContentInternal(const std::string& dataUriScheme);

    void EncapsulateDocument(MimeType mime,
                             const std::string& document);

    // For internal use only, in order to provide const-correctness on
    // the top of DCMTK API
    DcmFileFormat& GetDcmtkObjectConst() const;

    explicit ParsedDicomFile(DcmFileFormat* dicom);  // This takes ownership (no clone)

#if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1
    // Alias for binary compatibility with Orthanc Framework 1.7.2 => don't use it anymore
    void DatasetToJson(Json::Value& target, 
                       DicomToJsonFormat format,
                       DicomToJsonFlags flags,
                       unsigned int maxStringLength);    
    DcmFileFormat& GetDcmtkObject() const;
    void Apply(ITagVisitor& visitor);
    ParsedDicomFile* Clone(bool keepSopInstanceUid);
    bool LookupTransferSyntax(std::string& result);
    bool LookupTransferSyntax(std::string& result) const;
    bool GetTagValue(std::string& value,
                     const DicomTag& tag);
#endif

  public:
    explicit ParsedDicomFile(bool createIdentifiers);  // Create a minimal DICOM instance

    ParsedDicomFile(const DicomMap& map,
                    Encoding defaultEncoding,
                    bool permissive);

    ParsedDicomFile(const DicomMap& map,
                    Encoding defaultEncoding,
                    bool permissive,
                    const std::string& defaultPrivateCreator,
                    const std::map<uint16_t, std::string>& privateCreators);

    ParsedDicomFile(const void* content,
                    size_t size);

    explicit ParsedDicomFile(const std::string& content);

    explicit ParsedDicomFile(DcmDataset& dicom);  // This clones the DCMTK object

    explicit ParsedDicomFile(DcmFileFormat& dicom);  // This clones the DCMTK object

    static ParsedDicomFile* AcquireDcmtkObject(DcmFileFormat* dicom);

    DcmFileFormat& GetDcmtkObject();

    // The "ParsedDicomFile" object cannot be used after calling this method
    DcmFileFormat* ReleaseDcmtkObject();

    ParsedDicomFile* Clone(bool keepSopInstanceUid) const;

#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
    void SendPathValue(RestApiOutput& output,
                       const UriComponents& uri) const;

    void Answer(RestApiOutput& output) const;
#endif

    void Remove(const DicomTag& tag);

    // Replace the DICOM tag as a NULL/empty value (e.g. for anonymization)
    void Clear(const DicomTag& tag,
               bool onlyIfExists);

    void Replace(const DicomTag& tag,
                 const std::string& utf8Value,
                 bool decodeDataUriScheme,
                 DicomReplaceMode mode,
                 const std::string& privateCreator /* used only for private tags */);

    void Replace(const DicomTag& tag,
                 const Json::Value& value,  // Assumed to be encoded with UTF-8
                 bool decodeDataUriScheme,
                 DicomReplaceMode mode,
                 const std::string& privateCreator /* used only for private tags */);

    void Insert(const DicomTag& tag,
                const Json::Value& value,   // Assumed to be encoded with UTF-8
                bool decodeDataUriScheme,
                const std::string& privateCreator /* used only for private tags */);

    // Cannot be applied to private tags
    void ReplacePlainString(const DicomTag& tag,
                            const std::string& utf8Value);

    // Cannot be applied to private tags
    void SetIfAbsent(const DicomTag& tag,
                     const std::string& utf8Value);

    void RemovePrivateTags();

    void RemovePrivateTags(const std::set<DicomTag>& toKeep);

    // WARNING: This function handles the decoding of strings to UTF8
    bool GetTagValue(std::string& value,
                     const DicomTag& tag) const;

    DicomInstanceHasher GetHasher() const;

    // The "Save" methods are not tagged as "const", as the internal
    // representation might be changed after serialization
    void SaveToMemoryBuffer(std::string& buffer);

#if ORTHANC_SANDBOXED == 0
    void SaveToFile(const std::string& path);
#endif

    // This method must only be used on the PixelData and EncapsulatedDocument tags
    void EmbedContent(const std::string& dataUriScheme);

    void EmbedImage(const ImageAccessor& accessor);

    void EmbedImage(MimeType mime,
                    const std::string& content);

    void EmbedRawPixelData(const std::string& content);

    Encoding DetectEncoding(bool& hasCodeExtensions) const;

    // WARNING: This function only sets the encoding, it will not
    // convert the encoding of the tags. Use "ChangeEncoding()" if need be.
    void SetEncoding(Encoding encoding);

    void DatasetToJson(Json::Value& target, 
                       DicomToJsonFormat format,
                       DicomToJsonFlags flags,
                       unsigned int maxStringLength) const;

    void DatasetToJson(Json::Value& target, 
                       DicomToJsonFormat format,
                       DicomToJsonFlags flags,
                       unsigned int maxStringLength,
                       const std::set<DicomTag>& ignoreTagLength) const;
      
    void HeaderToJson(Json::Value& target, 
                      DicomToJsonFormat format) const;

    bool HasTag(const DicomTag& tag) const;

    bool ExtractPdf(std::string& pdf) const;

    void GetRawFrame(std::string& target, // OUT
                     MimeType& mime,   // OUT
                     unsigned int frameId) const;  // IN

    unsigned int GetFramesCount() const;

    static ParsedDicomFile* CreateFromJson(const Json::Value& value,
                                           DicomFromJsonFlags flags,
                                           const std::string& privateCreator);

    void ChangeEncoding(Encoding target);

    /**
     * The DICOM tags with a string whose size is greater than
     * "maxTagLength", are replaced by a DicomValue whose type is
     * "DicomValue_Null". If "maxTagLength" is zero, all the leaf tags
     * are included, independently of their length.
     **/
    void ExtractDicomSummary(DicomMap& target,
                             unsigned int maxTagLength) const;

    /**
     * This flavor can be used to bypass the "maxTagLength" limitation
     * on a selected set of DICOM tags.
     **/
    void ExtractDicomSummary(DicomMap& target,
                             unsigned int maxTagLength,
                             const std::set<DicomTag>& ignoreTagLength) const;

    bool LookupTransferSyntax(DicomTransferSyntax& result) const;

    bool LookupPhotometricInterpretation(PhotometricInterpretation& result) const;

    void Apply(ITagVisitor& visitor) const;

    // Decode the given frame, using the built-in DICOM decoder of Orthanc
    ImageAccessor* DecodeFrame(unsigned int frame) const;

    void ReplacePath(const DicomPath& path,
                     const Json::Value& value,  // Assumed to be encoded with UTF-8
                     bool decodeDataUriScheme,
                     DicomReplaceMode mode,
                     const std::string& privateCreator /* used only for private tags */);

    void RemovePath(const DicomPath& path);

    void ClearPath(const DicomPath& path,
                   bool onlyIfExists);

    bool LookupSequenceItem(DicomMap& target,
                            const DicomPath& path,
                            size_t sequenceIndex) const;

    void GetDefaultWindowing(double& windowCenter,
                             double& windowWidth,
                             unsigned int frame) const;

    void GetRescale(double& rescaleIntercept,
                    double& rescaleSlope,
                    unsigned int frame) const;

    void ListOverlays(std::set<uint16_t>& groups) const;

    ImageAccessor* DecodeOverlay(int& originX,
                                 int& originY,
                                 uint16_t group) const;

    ImageAccessor* DecodeAllOverlays(int& originX,
                                     int& originY) const;

    void InjectEmptyPixelData(ValueRepresentation vr);

    // Remove all the tags after pixel data
    void RemoveFromPixelData();

    ValueRepresentation GuessPixelDataValueRepresentation() const;
  };
}