diff --git a/Modules/DICOMReader/files.cmake b/Modules/DICOMReader/files.cmake index 70eb475bed..b26e96514c 100644 --- a/Modules/DICOMReader/files.cmake +++ b/Modules/DICOMReader/files.cmake @@ -1,46 +1,49 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkDICOMFileReader.cpp mitkDICOMTagScanner.cpp mitkDICOMGDCMTagScanner.cpp + mitkDICOMDCMTKTagScanner.cpp mitkDICOMImageBlockDescriptor.cpp mitkDICOMITKSeriesGDCMReader.cpp mitkDICOMDatasetSorter.cpp mitkDICOMTagBasedSorter.cpp mitkDICOMGDCMImageFrameInfo.cpp mitkDICOMImageFrameInfo.cpp + mitkDICOMGenericImageFrameInfo.cpp mitkDICOMDatasetAccessingImageFrameInfo.cpp mitkDICOMSortCriterion.cpp mitkDICOMSortByTag.cpp mitkITKDICOMSeriesReaderHelper.cpp mitkEquiDistantBlocksSorter.cpp mitkNormalDirectionConsistencySorter.cpp mitkSortByImagePositionPatient.cpp mitkGantryTiltInformation.cpp mitkClassicDICOMSeriesReader.cpp mitkThreeDnTDICOMSeriesReader.cpp mitkDICOMTag.cpp mitkDICOMTagHelper.cpp mitkDICOMTagCache.cpp mitkDICOMGDCMTagCache.cpp + mitkDICOMGenericTagCache.cpp mitkDICOMEnums.cpp mitkDICOMReaderConfigurator.cpp mitkDICOMFileReaderSelector.cpp mitkIDICOMTagsOfInterest.cpp mitkDICOMTagPath.cpp mitkDICOMProperty.cpp ) set(RESOURCE_FILES configurations/3D/classicreader.xml configurations/3D/imageposition.xml configurations/3D/imageposition_byacquisition.xml configurations/3D/instancenumber.xml configurations/3D/instancenumber_soft.xml configurations/3D/slicelocation.xml configurations/3DnT/classicreader.xml configurations/3DnT/imageposition_byacquisition.xml configurations/3DnT/imageposition_bytriggertime.xml ) diff --git a/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h b/Modules/DICOMReader/include/mitkDICOMDCMTKTagScanner.h similarity index 57% copy from Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h copy to Modules/DICOMReader/include/mitkDICOMDCMTKTagScanner.h index e8802b0580..b7d2f93419 100644 --- a/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h +++ b/Modules/DICOMReader/include/mitkDICOMDCMTKTagScanner.h @@ -1,119 +1,99 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef mitkDICOMGDCMTagScanner_h -#define mitkDICOMGDCMTagScanner_h +#ifndef mitkDICOMDCMTKTagScanner_h +#define mitkDICOMDCMTKTagScanner_h + +#include #include "mitkDICOMTagScanner.h" #include "mitkDICOMEnums.h" -#include "mitkDICOMGDCMTagCache.h" +#include "mitkDICOMGenericTagCache.h" namespace mitk { /** \ingroup DICOMReaderModule \brief Encapsulates the tag scanning process for a set of DICOM files. - Formerly integrated as a part of DICOMITKSeriesGDCMReader, the tag - scanning part has been factored out into this DICOMGDCMTagScanner class - in order to allow a single scan for multiple reader alternatives. This - helps much in the selection process of e.g. DICOMFileReaderSelector. - - The class works similar to gdcm::Scanner, just with the MITK set of classes: - - add a number of DICOM tags that should be read - - set a list of files that should be scanned for named tags - - call Scan() - - retrieve the scan results - - via GetFrameInfoList() or - - via GetTagValue() - - When used in a process where multiple classes will access the scan - results, care should be taken that all the tags and files of interest - are communicated to DICOMGDCMTagScanner before requesting the results! + For the scanning process it uses DCMTK functionality. */ - class MITKDICOMREADER_EXPORT DICOMGDCMTagScanner : public DICOMTagScanner + class MITKDICOMREADER_EXPORT DICOMDCMTKTagScanner : public DICOMTagScanner { public: - mitkClassMacro(DICOMGDCMTagScanner, DICOMTagScanner); - itkFactorylessNewMacro( DICOMGDCMTagScanner ); + mitkClassMacro(DICOMDCMTKTagScanner, DICOMTagScanner); + itkFactorylessNewMacro( DICOMDCMTKTagScanner ); itkCloneMacro(Self); /** \brief Add this tag to the scanning process. */ virtual void AddTag(const DICOMTag& tag) override; /** \brief Add a list of tags to the scanning process. */ virtual void AddTags(const DICOMTagList& tags) override; /** \brief Add this tag path to the scanning process. */ virtual void AddTagPath(const DICOMTagPath& tag) override; /** \brief Add a list of tag pathes to the scanning process. */ virtual void AddTagPaths(const DICOMTagPathList& tags) override; /** \brief Define the list of files to scan. This does not ADD to an internal list, but it replaces the whole list of files. */ virtual void SetInputFiles(const StringList& filenames) override; /** \brief Start the scanning process. Calling Scan() will invalidate previous scans, forgetting all about files and tags from files that have been scanned previously. */ virtual void Scan(); /** \brief Retrieve a result list for file-by-file tag access. */ virtual DICOMDatasetAccessingImageFrameList GetFrameInfoList() const override; /** \brief Retrieve Pointer to the complete cache of the scan. */ virtual DICOMTagCache::Pointer GetScanCache() const override; - /** - \brief Directly retrieve the tag value for a given frame and tag. - @pre Scan() must have been called before calling this function. - */ - virtual DICOMDatasetFinding GetTagValue(DICOMImageFrameInfo* frame, const DICOMTag& tag) const; - protected: - DICOMGDCMTagScanner(); - virtual ~DICOMGDCMTagScanner(); + DICOMDCMTKTagScanner(); + virtual ~DICOMDCMTKTagScanner(); - std::set m_ScannedTags; + std::set m_ScannedTags; StringList m_InputFilenames; - DICOMGDCMTagCache::Pointer m_Cache; - std::shared_ptr m_GDCMScanner; + DICOMGenericTagCache::Pointer m_Cache; private: - DICOMGDCMTagScanner(const DICOMGDCMTagScanner&); + DICOMDCMTKTagScanner(const DICOMDCMTKTagScanner&); }; } #endif diff --git a/Modules/DICOMReader/include/mitkDICOMDatasetAccess.h b/Modules/DICOMReader/include/mitkDICOMDatasetAccess.h index 374577fbd5..c816fe0eef 100644 --- a/Modules/DICOMReader/include/mitkDICOMDatasetAccess.h +++ b/Modules/DICOMReader/include/mitkDICOMDatasetAccess.h @@ -1,78 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDICOMDatasetAccess_h #define mitkDICOMDatasetAccess_h #include "mitkDICOMTag.h" #include "mitkDICOMTagPath.h" #include "MitkDICOMReaderExports.h" namespace mitk { /** Helper class that is used for the result of DICOMDatasetAccess::GetTagValueAsString */ struct MITKDICOMREADER_EXPORT DICOMDatasetFinding { /**Indicates if value is valid or not.*/ bool isValid; /**The found value.*/ std::string value; /**Tag path of the value*/ DICOMTagPath path; - DICOMDatasetFinding() : isValid(false), value("") + DICOMDatasetFinding(bool valid = false, const std::string& aValue = "", const DICOMTagPath& aPath = DICOMTagPath()) : isValid(valid), value(aValue), path(aPath) {}; }; /** \ingroup DICOMReaderModule \brief Interface to datasets that is presented to sorting classes such as DICOMDatasetSorter. Minimal interface to hide actual implementation, which might rely on GDCM. */ class MITKDICOMREADER_EXPORT DICOMDatasetAccess { public: typedef std::list FindingsListType; /// \brief Return a filename if possible. /// If DICOM is not read from file but from somewhere else (network, database), we might not have files. virtual std::string GetFilenameIfAvailable() const = 0; /** \brief Return a DICOMDatasetFinding instance of the tag. The return containes (if valid) the raw value of the tag as a string. \param tag Tag which value should be retreived. */ virtual DICOMDatasetFinding GetTagValueAsString(const DICOMTag& tag) const = 0; /** \brief Return a list of DICOMDatasetFindings of the passed tag path. The return containes (if valid) the raw value of the tag as a string. \param path Tag path which value should be retreived. */ virtual FindingsListType GetTagValueAsString(const DICOMTagPath& path) const = 0; virtual ~DICOMDatasetAccess() {}; }; typedef std::vector DICOMDatasetList; } #endif diff --git a/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h b/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h index e8802b0580..4a3289bed3 100644 --- a/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h +++ b/Modules/DICOMReader/include/mitkDICOMGDCMTagScanner.h @@ -1,119 +1,123 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDICOMGDCMTagScanner_h #define mitkDICOMGDCMTagScanner_h #include "mitkDICOMTagScanner.h" #include "mitkDICOMEnums.h" #include "mitkDICOMGDCMTagCache.h" namespace mitk { /** \ingroup DICOMReaderModule \brief Encapsulates the tag scanning process for a set of DICOM files. Formerly integrated as a part of DICOMITKSeriesGDCMReader, the tag scanning part has been factored out into this DICOMGDCMTagScanner class in order to allow a single scan for multiple reader alternatives. This helps much in the selection process of e.g. DICOMFileReaderSelector. The class works similar to gdcm::Scanner, just with the MITK set of classes: - add a number of DICOM tags that should be read - set a list of files that should be scanned for named tags - call Scan() - retrieve the scan results - via GetFrameInfoList() or - via GetTagValue() When used in a process where multiple classes will access the scan results, care should be taken that all the tags and files of interest are communicated to DICOMGDCMTagScanner before requesting the results! + + @remark This scanner does only support the scanning for simple value tag. + If you need to scann for sequence items or non-top-level elements, this scanner + will not be sufficient. See i.a. DICOMDCMTKTagScanner for these cases. */ class MITKDICOMREADER_EXPORT DICOMGDCMTagScanner : public DICOMTagScanner { public: mitkClassMacro(DICOMGDCMTagScanner, DICOMTagScanner); itkFactorylessNewMacro( DICOMGDCMTagScanner ); itkCloneMacro(Self); /** \brief Add this tag to the scanning process. */ virtual void AddTag(const DICOMTag& tag) override; /** \brief Add a list of tags to the scanning process. */ virtual void AddTags(const DICOMTagList& tags) override; /** \brief Add this tag path to the scanning process. */ virtual void AddTagPath(const DICOMTagPath& tag) override; /** \brief Add a list of tag pathes to the scanning process. */ virtual void AddTagPaths(const DICOMTagPathList& tags) override; /** \brief Define the list of files to scan. This does not ADD to an internal list, but it replaces the whole list of files. */ virtual void SetInputFiles(const StringList& filenames) override; /** \brief Start the scanning process. Calling Scan() will invalidate previous scans, forgetting all about files and tags from files that have been scanned previously. */ virtual void Scan(); /** \brief Retrieve a result list for file-by-file tag access. */ virtual DICOMDatasetAccessingImageFrameList GetFrameInfoList() const override; /** \brief Retrieve Pointer to the complete cache of the scan. */ virtual DICOMTagCache::Pointer GetScanCache() const override; /** \brief Directly retrieve the tag value for a given frame and tag. @pre Scan() must have been called before calling this function. */ virtual DICOMDatasetFinding GetTagValue(DICOMImageFrameInfo* frame, const DICOMTag& tag) const; protected: DICOMGDCMTagScanner(); virtual ~DICOMGDCMTagScanner(); std::set m_ScannedTags; StringList m_InputFilenames; DICOMGDCMTagCache::Pointer m_Cache; std::shared_ptr m_GDCMScanner; private: DICOMGDCMTagScanner(const DICOMGDCMTagScanner&); }; } #endif diff --git a/Modules/DICOMReader/include/mitkDICOMGenericImageFrameInfo.h b/Modules/DICOMReader/include/mitkDICOMGenericImageFrameInfo.h new file mode 100644 index 0000000000..2525ed4398 --- /dev/null +++ b/Modules/DICOMReader/include/mitkDICOMGenericImageFrameInfo.h @@ -0,0 +1,69 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkDICOMGenericImageFrameInfo_h +#define mitkDICOMGenericImageFrameInfo_h + +#include "mitkDICOMDatasetAccessingImageFrameInfo.h" + +#include + +namespace mitk +{ + /** + \ingroup DICOMReaderModule + \brief A generic storage class for image frame info with data access. + */ + class MITKDICOMREADER_EXPORT DICOMGenericImageFrameInfo : public DICOMDatasetAccessingImageFrameInfo + { + public: + + mitkClassMacro(DICOMGenericImageFrameInfo, DICOMDatasetAccessingImageFrameInfo); + itkFactorylessNewMacro( DICOMGenericImageFrameInfo ); + mitkNewMacro1Param( DICOMGenericImageFrameInfo, const std::string&); + mitkNewMacro2Param( DICOMGenericImageFrameInfo, const std::string&, unsigned int ); + mitkNewMacro1Param( DICOMGenericImageFrameInfo, const DICOMImageFrameInfo::Pointer& ); + + virtual ~DICOMGenericImageFrameInfo(); + + virtual DICOMDatasetFinding GetTagValueAsString(const DICOMTag&) const override; + + virtual FindingsListType GetTagValueAsString(const DICOMTagPath& path) const override; + + std::string GetFilenameIfAvailable() const override; + + /** Sets the value for a passed tag path. If the tag path is already set, it will be overwritten + with the new value. + @pre Path must be explicit. No wildcards are allowd. + @post The passed value is set for the passed path. + */ + void SetTagValue(const DICOMTagPath& path, const std::string& value); + + protected: + typedef std::map ValueMapType; + ValueMapType m_Values; + + DICOMGenericImageFrameInfo(const DICOMImageFrameInfo::Pointer& frameinfo); + DICOMGenericImageFrameInfo(const std::string& filename = "", unsigned int frameNo = 0); + + private: + Self& operator = (const Self&); + DICOMGenericImageFrameInfo(const Self&); + }; + +} + +#endif diff --git a/Modules/DICOMReader/include/mitkDICOMGenericTagCache.h b/Modules/DICOMReader/include/mitkDICOMGenericTagCache.h new file mode 100644 index 0000000000..6b2cf9a13b --- /dev/null +++ b/Modules/DICOMReader/include/mitkDICOMGenericTagCache.h @@ -0,0 +1,59 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkDICOMGenericTagCache_h +#define mitkDICOMGenericTagCache_h + +#include "mitkDICOMTagCache.h" +#include "mitkDICOMGenericImageFrameInfo.h" + +namespace mitk +{ + + /** + \ingroup DICOMReaderModule + \brief Generic tag cache implementation. + */ + class MITKDICOMREADER_EXPORT DICOMGenericTagCache : public DICOMTagCache + { + public: + + mitkClassMacro(DICOMGenericTagCache, DICOMTagCache); + itkFactorylessNewMacro( DICOMGenericTagCache ); + itkCloneMacro(Self); + + virtual DICOMDatasetFinding GetTagValue(DICOMImageFrameInfo* frame, const DICOMTag& tag) const override; + + virtual FindingsListType GetTagValue(DICOMImageFrameInfo* frame, const DICOMTagPath& path) const override; + + virtual DICOMDatasetAccessingImageFrameList GetFrameInfoList() const override; + + void AddFrameInfo(DICOMDatasetAccessingImageFrameInfo* info); + void Reset(); + + protected: + + DICOMGenericTagCache(); + virtual ~DICOMGenericTagCache(); + + DICOMDatasetAccessingImageFrameList m_ScanResult; + + private: + DICOMGenericTagCache(const DICOMGenericTagCache&); + }; +} + +#endif diff --git a/Modules/DICOMReader/include/mitkDICOMTagPath.h b/Modules/DICOMReader/include/mitkDICOMTagPath.h index 163b7a4820..1890c00393 100644 --- a/Modules/DICOMReader/include/mitkDICOMTagPath.h +++ b/Modules/DICOMReader/include/mitkDICOMTagPath.h @@ -1,157 +1,166 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDICOMTagPath_h #define mitkDICOMTagPath_h #include #include #include namespace mitk { class MITKDICOMREADER_EXPORT DICOMTagPath { public: typedef int ItemSelectionIndex; struct MITKDICOMREADER_EXPORT NodeInfo { enum class NodeType { Invalid = 0, //*< Node is non existant or invalid. Element, //*< Selects an specific element given the node name. SequenceSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]"). AnySelection, //*< Selects all items of a specific element ("[*]"). AnyElement, //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily. }; NodeType type; DICOMTag tag; ItemSelectionIndex selection; NodeInfo(); NodeInfo(const DICOMTag& tag, NodeType type = NodeType::Element); bool Matches(const NodeInfo& right) const; + + bool operator == (const NodeInfo& right) const; }; typedef std::vector NodeInfoVectorType; typedef NodeInfoVectorType::size_type PathIndexType; /** Returns if the DICOMTagPath is empty.*/ bool IsEmpty() const; /** Returns if the path is explicit (has no wildcards).*/ bool IsExplicit() const; /** Returns if the path has any nodes with item selection wild cards ([*]).*/ bool HasItemSelectionWildcardsOnly() const; /** Number of path nodes the DICOMTagPath contains.*/ PathIndexType Size() const; /** Adds a new node to the end of the path. \param [in] newNode Reference to the node that should be added. \return Returns the index of the newly added node.*/ PathIndexType AddNode(const NodeInfo& newNode); /** Function returns the node info of a path node specified by the index * within the DICOMTagPath. * \pre Passed index must not be out of bound. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetNode(const PathIndexType& index) const; /** Function returns the node info of a path node specified by the index * within the DICOMTagPath. * \pre Passed index must not be out of bound. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be thrown.*/ NodeInfo& GetNode(const PathIndexType& index); /** Function returns the node info of the first path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo& GetFirstNode(); /** Function returns the node info of the first path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetFirstNode() const; /** Function returns the node info of the last path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo& GetLastNode(); /** Function returns the node info of the last path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetLastNode() const; const NodeInfoVectorType& GetNodes() const; std::string ToStr() const; DICOMTagPath& FromStr(const std::string& pathStr); + /**Compares two DICOMTagPaths for real equality. So its a string compare of their string conversion*/ + bool operator == (const DICOMTagPath& path) const; + + /**Operation equals like comparing the ToStr() results with operator <.*/ + bool operator < (const DICOMTagPath& right) const; + /**Checks if to DICOMTagPathes are specify the same node. Hence all wildcards will be processed.\n * E.G.: "item1/child1/grandChild2" == ".//item1//grandChild2" is true. * \remark If you want to check if to pathes are "truely" equal and not only equal in terms of * pointing to the same node, use the member function Equals()*/ - bool operator == (const DICOMTagPath& path) const; - - /**Compares two DICOMTagPaths for real equality. So its a string compare of their string conversion*/ bool Equals(const DICOMTagPath& path) const; DICOMTagPath& operator = (const DICOMTagPath& path); DICOMTagPath& addAnyElement(); DICOMTagPath& addElement(unsigned int group, unsigned int element); DICOMTagPath& addAnySelection(unsigned int group, unsigned int element); DICOMTagPath& addSelection(unsigned int group, unsigned int element, ItemSelectionIndex index); DICOMTagPath(); DICOMTagPath(const DICOMTagPath& path); DICOMTagPath(const DICOMTag& tag); ~DICOMTagPath(); virtual void Reset(); protected: NodeInfoVectorType m_NodeInfos; static bool DICOMTagPathesMatch(const DICOMTagPath& left, const DICOMTagPath& right); }; typedef std::vector DICOMTagPathList; MITKDICOMREADER_EXPORT std::string TagPathToPropertyName(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string TagPathToPropertRegEx(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string TagPathToPersistenceKeyRegEx(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string TagPathToPersistenceKeyTemplate(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string TagPathToPersistenceNameTemplate(const DICOMTagPath& tagPath); + + /** Converts a passed path into a search string for the DCMTK DcmPathProcessor. + @pre tagPath must be an explicit (DICOMTagPath::IsExplicit()) path or + must only contain selection wild cards (DICOMTagPath::HasItemSelectionWildcardsOnly()).*/ MITKDICOMREADER_EXPORT std::string TagPathToDCMTKSearchPath(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT DICOMTagPath PropertyNameToTagPath(const std::string& tagPath); } #endif diff --git a/Modules/DICOMReader/include/mitkDICOMTagScanner.h b/Modules/DICOMReader/include/mitkDICOMTagScanner.h index 49f0fed144..eccc604dc8 100644 --- a/Modules/DICOMReader/include/mitkDICOMTagScanner.h +++ b/Modules/DICOMReader/include/mitkDICOMTagScanner.h @@ -1,100 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDICOMTagScanner_h #define mitkDICOMTagScanner_h +#include +#include "itkMutexLock.h" + #include "mitkDICOMEnums.h" #include "mitkDICOMTagPath.h" #include "mitkDICOMTagCache.h" #include "mitkDICOMDatasetAccessingImageFrameInfo.h" namespace mitk { /** \ingroup DICOMReaderModule \brief Abstracts the tag scanning process for a set of DICOM files. Formerly integrated as a part of DICOMITKSeriesGDCMReader, the tag scanning part has been factored out into DICOMTagScanner classes in order to allow a single scan for multiple reader alternatives. This helps much in the selection process of e.g. DICOMFileReaderSelector. This is an abstract base class for concrete scanner implementations. @remark When used in a process where multiple classes will access the scan results, care should be taken that all the tags and files of interest are communicated to DICOMTagScanner before requesting the results! */ class MITKDICOMREADER_EXPORT DICOMTagScanner : public itk::Object { public: mitkClassMacroItkParent(DICOMTagScanner, itk::Object); /** \brief Add this tag to the scanning process. */ virtual void AddTag(const DICOMTag& tag) = 0; /** \brief Add a list of tags to the scanning process. */ virtual void AddTags(const DICOMTagList& tags) = 0; /** \brief Add this tag path to the scanning process. */ virtual void AddTagPath(const DICOMTagPath& path) = 0; /** \brief Add a list of tag pathes to the scanning process. */ virtual void AddTagPaths(const DICOMTagPathList& paths) = 0; /** \brief Define the list of files to scan. This does not ADD to an internal list, but it replaces the whole list of files. */ virtual void SetInputFiles(const StringList& filenames) = 0; /** \brief Start the scanning process. Calling Scan() will invalidate previous scans, forgetting all about files and tags from files that have been scanned previously. */ virtual void Scan() = 0; /** \brief Retrieve a result list for file-by-file tag access. */ virtual DICOMDatasetAccessingImageFrameList GetFrameInfoList() const = 0; /** \brief Retrieve Pointer to the complete cache of the scan. */ virtual DICOMTagCache::Pointer GetScanCache() const = 0; protected: + /** \brief Return active C locale */ + static std::string GetActiveLocale(); + /** + \brief Remember current locale on stack, activate "C" locale. + "C" locale is required for correct parsing of numbers by itk::ImageSeriesReader + */ + void PushLocale() const; + /** + \brief Activate last remembered locale from locale stack + "C" locale is required for correct parsing of numbers by itk::ImageSeriesReader + */ + void PopLocale() const; + DICOMTagScanner(); virtual ~DICOMTagScanner(); private: + + static itk::MutexLock::Pointer s_LocaleMutex; + + mutable std::stack m_ReplacedCLocales; + mutable std::stack m_ReplacedCinLocales; + DICOMTagScanner(const DICOMTagScanner&); }; } #endif diff --git a/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp b/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp new file mode 100644 index 0000000000..6d4b7bb781 --- /dev/null +++ b/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp @@ -0,0 +1,180 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkDICOMDCMTKTagScanner.h" +#include "mitkDICOMGenericImageFrameInfo.h" + +#include +#include + +mitk::DICOMDCMTKTagScanner::DICOMDCMTKTagScanner() +{ +} + +mitk::DICOMDCMTKTagScanner::~DICOMDCMTKTagScanner() +{ +} + +void mitk::DICOMDCMTKTagScanner::AddTag( const DICOMTag& tag ) +{ + m_ScannedTags.insert( DICOMTagPath(tag) ); +} + +void mitk::DICOMDCMTKTagScanner::AddTags( const DICOMTagList& tags ) +{ + for ( auto tagIter = tags.cbegin(); tagIter != tags.cend(); ++tagIter ) + { + this->AddTag( *tagIter ); + } +} + +void mitk::DICOMDCMTKTagScanner::AddTagPath(const DICOMTagPath& path) +{ + m_ScannedTags.insert(path); +} + +void mitk::DICOMDCMTKTagScanner::AddTagPaths(const DICOMTagPathList& paths) +{ + for (const auto& path : paths) + { + this->AddTagPath(path); + } +} + +void mitk::DICOMDCMTKTagScanner::SetInputFiles( const StringList& filenames ) +{ + m_InputFilenames = filenames; +} + +mitk::DICOMTagPath DcmPathToTagPath(DcmPath * dcmpath) +{ + mitk::DICOMTagPath result; + + OFListConstIterator(DcmPathNode*) it = dcmpath->begin(); + OFListConstIterator(DcmPathNode*) endOfList = dcmpath->end(); + OFString pathStr; DcmEVR vr; DcmObject* obj; + + mitk::DICOMTagPath::NodeInfo info; + + while (it != endOfList) + { + if (((*it) == NULL) || ((*it)->m_obj == NULL)) + { + mitkThrow() << "Error in DcmPathToTagPath(). Invalid search result"; + } + obj = (*it)->m_obj; + vr = obj->ident(); + + if ((vr == EVR_SQ) || (obj->isLeaf())) + { + if (info.type != mitk::DICOMTagPath::NodeInfo::NodeType::Invalid) + { + result.AddNode(info); + } + info.type = mitk::DICOMTagPath::NodeInfo::NodeType::Element; + info.tag = mitk::DICOMTag(obj->getTag().getGroup(), obj->getTag().getElement()); + } + else if ((vr == EVR_item) || (vr == EVR_dataset)) + { + info.type = mitk::DICOMTagPath::NodeInfo::NodeType::SequenceSelection; + info.selection = (*it)->m_itemNo; + } + else + { + info = mitk::DICOMTagPath::NodeInfo(); //invalid node + result.AddNode(info); + } + ++it; + } + + return result; +} + +void mitk::DICOMDCMTKTagScanner::Scan() +{ + this->PushLocale(); + + try + { + DcmPathProcessor processor; + processor.setItemWildcardSupport(true); + + DICOMGenericTagCache::Pointer newCache = DICOMGenericTagCache::New(); + + for (const auto& fileName : this->m_InputFilenames) + { + DcmFileFormat dfile; + OFCondition cond = dfile.loadFile(fileName.c_str()); + if (cond.bad()) + { + MITK_ERROR << "Error when scanning for tags. Cannot open given file. File: " << fileName; + } + else + { + DICOMGenericImageFrameInfo::Pointer info = DICOMGenericImageFrameInfo::New(fileName); + + for (const auto& path : this->m_ScannedTags) + { + std::string tagPath = TagPathToDCMTKSearchPath(path); + cond = processor.findOrCreatePath(&dfile, tagPath.c_str()); + if (cond.good()) + { + OFList< DcmPath * > findings; + processor.getResults(findings); + for (const auto& finding : findings) + { + auto element = dynamic_cast(finding->back()->m_obj); + if (element) + { + OFString value; + cond = element->getOFStringArray(value); + if (cond.good()) + { + info->SetTagValue(DcmPathToTagPath(finding), std::string(value.c_str())); + } + } + } + } + } + newCache->AddFrameInfo(info); + } + } + + m_Cache = newCache; + + this->PopLocale(); + } + catch (...) + { + this->PopLocale(); + throw; + } +} + +mitk::DICOMTagCache::Pointer +mitk::DICOMDCMTKTagScanner::GetScanCache() const +{ + return m_Cache.GetPointer(); +} + +mitk::DICOMDatasetAccessingImageFrameList mitk::DICOMDCMTKTagScanner::GetFrameInfoList() const +{ + if (m_Cache.IsNotNull()) + { + return m_Cache->GetFrameInfoList(); + } + return mitk::DICOMDatasetAccessingImageFrameList(); +} diff --git a/Modules/DICOMReader/src/mitkDICOMGDCMTagCache.cpp b/Modules/DICOMReader/src/mitkDICOMGDCMTagCache.cpp index abf367ca0d..1b0eed068c 100644 --- a/Modules/DICOMReader/src/mitkDICOMGDCMTagCache.cpp +++ b/Modules/DICOMReader/src/mitkDICOMGDCMTagCache.cpp @@ -1,106 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDICOMGDCMTagCache.h" #include "mitkDICOMEnums.h" #include "mitkDICOMGDCMImageFrameInfo.h" mitk::DICOMGDCMTagCache::DICOMGDCMTagCache() { } mitk::DICOMGDCMTagCache::~DICOMGDCMTagCache() { } mitk::DICOMDatasetFinding mitk::DICOMGDCMTagCache::GetTagValue( DICOMImageFrameInfo* frame, const DICOMTag& tag ) const { assert( frame ); for ( auto frameIter = m_ScanResult.cbegin(); frameIter != m_ScanResult.cend(); ++frameIter ) { if ( **frameIter == *frame ) { return (*frameIter)->GetTagValueAsString(tag); } } if ( m_ScannedTags.find( tag ) != m_ScannedTags.cend() ) { if ( std::find( m_InputFilenames.cbegin(), m_InputFilenames.cend(), frame->Filename ) == m_InputFilenames.cend() ) { // callers are required to tell us about the filenames they are interested in // this is a helpful reminder for them to inform us std::stringstream errorstring; errorstring << "Invalid call to DICOMGDCMTagCache::GetTagValue( " << "'" << frame->Filename << "', frame " << frame->FrameNo << " ). Filename was never mentioned before!"; MITK_ERROR << errorstring.str(); throw std::invalid_argument( errorstring.str() ); } } else { // callers are required to tell us about the tags they are interested in // this is a helpful reminder for them to inform us std::stringstream errorstring; errorstring << "Invalid call to DICOMGDCMTagCache::GetTagValue( "; tag.Print( errorstring ); errorstring << " ). Tag was never mentioned before!"; MITK_ERROR << errorstring.str(); throw std::invalid_argument( errorstring.str() ); } + + return DICOMDatasetFinding(); } mitk::DICOMDatasetAccess::FindingsListType mitk::DICOMGDCMTagCache::GetTagValue(DICOMImageFrameInfo* frame, const DICOMTagPath& path) const { FindingsListType result; if (path.Size() == 1 && path.IsExplicit()) { result.push_back(this->GetTagValue(frame, path.GetFirstNode().tag)); } return result; } mitk::DICOMDatasetAccessingImageFrameList mitk::DICOMGDCMTagCache::GetFrameInfoList() const { return m_ScanResult; } void mitk::DICOMGDCMTagCache::InitCache(const std::set& scannedTags, const std::shared_ptr& scanner, const StringList& inputFiles) { m_ScannedTags = scannedTags; m_InputFilenames = inputFiles; m_Scanner = scanner; m_ScanResult.clear(); m_ScanResult.reserve(m_InputFilenames.size()); for (auto inputIter = m_InputFilenames.cbegin(); inputIter != m_InputFilenames.cend(); ++inputIter) { m_ScanResult.push_back(DICOMGDCMImageFrameInfo::New(DICOMImageFrameInfo::New(*inputIter, 0), m_Scanner->GetMapping(inputIter->c_str())).GetPointer()); } } const gdcm::Scanner& mitk::DICOMGDCMTagCache::GetScanner() const { return *(this->m_Scanner); } diff --git a/Modules/DICOMReader/src/mitkDICOMGenericImageFrameInfo.cpp b/Modules/DICOMReader/src/mitkDICOMGenericImageFrameInfo.cpp new file mode 100644 index 0000000000..0d874f306c --- /dev/null +++ b/Modules/DICOMReader/src/mitkDICOMGenericImageFrameInfo.cpp @@ -0,0 +1,87 @@ +/*=================================================================== + + The Medical Imaging Interaction Toolkit (MITK) + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics. + All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. + + See LICENSE.txt or http://www.mitk.org for details. + + ===================================================================*/ + +#include "mitkDICOMGenericImageFrameInfo.h" +#include "mitkException.h" + +mitk::DICOMGenericImageFrameInfo +::DICOMGenericImageFrameInfo(const std::string& filename, unsigned int frameNo) +:DICOMDatasetAccessingImageFrameInfo(filename, frameNo) +{ +} + +mitk::DICOMGenericImageFrameInfo +::DICOMGenericImageFrameInfo(const DICOMImageFrameInfo::Pointer& frameinfo) +:DICOMDatasetAccessingImageFrameInfo(frameinfo->Filename, frameinfo->FrameNo) +{ +} + +mitk::DICOMGenericImageFrameInfo:: +~DICOMGenericImageFrameInfo() +{ +} + +mitk::DICOMDatasetFinding +mitk::DICOMGenericImageFrameInfo +::GetTagValueAsString(const DICOMTag& tag) const +{ + DICOMTagPath path(tag); + DICOMDatasetFinding result; + + const auto finding = m_Values.find(path); + if (finding != m_Values.cend()) + { + result.isValid = true; + result.value = finding->second; + result.path = path; + } + + return result; +} + +mitk::DICOMDatasetAccess::FindingsListType +mitk::DICOMGenericImageFrameInfo::GetTagValueAsString(const DICOMTagPath& path) const +{ + FindingsListType result; + + for (const auto& iter : m_Values) + { + if (path.Equals(iter.first)) + { + result.emplace(result.end(), true, iter.second, path); + } + } + + return result; +} + +void +mitk::DICOMGenericImageFrameInfo::SetTagValue(const DICOMTagPath& path, const std::string& value) +{ + if (!path.IsExplicit()) + { + mitkThrow() << "Only explicit tag paths (no wildcards) are allowed for tag values in DICOMGenericImageFrameInfo. Passed tag path:" << path.ToStr(); + } + + m_Values[path] = value; +} + +std::string +mitk::DICOMGenericImageFrameInfo +::GetFilenameIfAvailable() const +{ + return this->Filename; +} diff --git a/Modules/DICOMReader/src/mitkDICOMGenericTagCache.cpp b/Modules/DICOMReader/src/mitkDICOMGenericTagCache.cpp new file mode 100644 index 0000000000..0fc821a369 --- /dev/null +++ b/Modules/DICOMReader/src/mitkDICOMGenericTagCache.cpp @@ -0,0 +1,71 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkDICOMGenericTagCache.h" +#include "mitkDICOMEnums.h" +#include "mitkDICOMGenericImageFrameInfo.h" + +mitk::DICOMGenericTagCache::DICOMGenericTagCache() +{ +} + +mitk::DICOMGenericTagCache::~DICOMGenericTagCache() +{ +} + +mitk::DICOMDatasetFinding mitk::DICOMGenericTagCache::GetTagValue( DICOMImageFrameInfo* frame, const DICOMTag& tag ) const +{ + auto findings = GetTagValue(frame, DICOMTagPath(tag)); + + DICOMDatasetFinding result; + if (!findings.empty()) + { + result = findings.front(); + } + return result; +} + +mitk::DICOMDatasetAccess::FindingsListType +mitk::DICOMGenericTagCache::GetTagValue(DICOMImageFrameInfo* frame, const DICOMTagPath& path) const +{ + FindingsListType result; + + for (auto info : m_ScanResult) + { + if (info == frame) + { + result = info->GetTagValueAsString(path); + } + } + return result; +} + +mitk::DICOMDatasetAccessingImageFrameList mitk::DICOMGenericTagCache::GetFrameInfoList() const +{ + return m_ScanResult; +} + +void +mitk::DICOMGenericTagCache::AddFrameInfo(DICOMDatasetAccessingImageFrameInfo* info) +{ + m_ScanResult.push_back(info); +}; + +void +mitk::DICOMGenericTagCache::Reset() +{ + m_ScanResult.clear(); +}; diff --git a/Modules/DICOMReader/src/mitkDICOMTagPath.cpp b/Modules/DICOMReader/src/mitkDICOMTagPath.cpp index 0c90243cef..1bf8cd7f40 100644 --- a/Modules/DICOMReader/src/mitkDICOMTagPath.cpp +++ b/Modules/DICOMReader/src/mitkDICOMTagPath.cpp @@ -1,328 +1,353 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include namespace mitk { DICOMTagPath::NodeInfo:: NodeInfo() : tag(0,0) { type = NodeType::Invalid; }; DICOMTagPath::NodeInfo:: NodeInfo(const DICOMTag& aTag, NodeType aType) : type(aType), tag(aTag) {}; + bool DICOMTagPath::NodeInfo::operator == (const NodeInfo& right) const + { + if (!(this->tag == right.tag)) return false; + if (this->type != right.type) return false; + if (this->selection != right.selection) return false; + + return true; + }; + bool DICOMTagPath::NodeInfo:: Matches(const NodeInfo& right) const { if (type == NodeType::AnyElement || right.type == NodeType::AnyElement) { return true; } else if (tag == right.tag && type != NodeType::Invalid && right.type != NodeType::Invalid) { if (type == NodeType::Element && right.type == NodeType::Element) { return true; } else if(selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection) { return true; } } return false; }; bool DICOMTagPath::IsEmpty() const { return m_NodeInfos.empty(); }; bool DICOMTagPath:: IsExplicit() const { for (const auto & pos : m_NodeInfos) { if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement)) return false; } return true; }; bool DICOMTagPath:: HasItemSelectionWildcardsOnly() const { bool result = false; for (const auto & pos : m_NodeInfos) { if (pos.type == NodeInfo::NodeType::AnyElement) return false; result = result || pos.type == NodeInfo::NodeType::AnySelection; } return result; }; DICOMTagPath::PathIndexType DICOMTagPath::Size() const { return m_NodeInfos.size(); } DICOMTagPath::PathIndexType DICOMTagPath:: AddNode(const NodeInfo& newNode) { m_NodeInfos.push_back(newNode); return m_NodeInfos.size() - 1; }; const DICOMTagPath::NodeInfo& DICOMTagPath:: GetNode(const PathIndexType& index) const { if ((index<0) || (index >= Size())) { mitkThrow() << "Error. Cannot return info of path node. Node index is out of bound. Index: " << index << "; Path: " << this->ToStr(); } return m_NodeInfos[index]; }; DICOMTagPath::NodeInfo& DICOMTagPath:: GetNode(const PathIndexType& index) { if ((index<0) || (index >= Size())) { mitkThrow() << "Error. Cannot return info of path node. Node index is out of bound. Index: " << index << "; Path: " << this->ToStr(); } return m_NodeInfos[index]; }; const DICOMTagPath::NodeInfo& DICOMTagPath:: GetFirstNode() const { return GetNode(0); }; const DICOMTagPath::NodeInfo& DICOMTagPath:: GetLastNode() const { return GetNode(Size() - 1); }; DICOMTagPath::NodeInfo& DICOMTagPath:: GetLastNode() { return GetNode(Size() - 1); }; const DICOMTagPath::NodeInfoVectorType& DICOMTagPath:: GetNodes() const { return m_NodeInfos; }; std::string DICOMTagPath:: ToStr() const { std::string sPath = ""; if (this->Size() == 0) return sPath; PathIndexType i = 0; for (const auto& node : m_NodeInfos) { if (i) { sPath += "."; } if (node.type == NodeInfo::NodeType::AnyElement) { sPath += "*"; } else if (node.type != NodeInfo::NodeType::Invalid) { std::ostringstream nameStream; nameStream << "(" << std::setw(4) << std::setfill('0') << std::hex << node.tag.GetGroup() << "," << std::setw(4) << std::setfill('0') << std::hex << node.tag.GetElement()<<")"; if (node.type == NodeInfo::NodeType::SequenceSelection) { nameStream << "[" << node.selection << "]"; } else if (node.type == NodeInfo::NodeType::AnySelection) { nameStream << "[*]"; } sPath += nameStream.str(); } else { sPath += "INVALID_NODE"; } } return sPath; }; bool DICOMTagPath:: operator == (const DICOMTagPath& path) const { - return DICOMTagPathesMatch(*this, path); + return this->m_NodeInfos == path.m_NodeInfos; }; + bool + DICOMTagPath:: + operator < (const DICOMTagPath& right) const + { + return this->ToStr() < right.ToStr(); + } + bool DICOMTagPath:: Equals(const DICOMTagPath& path) const { - return this->ToStr() == path.ToStr(); + return DICOMTagPathesMatch(*this, path); }; DICOMTagPath& DICOMTagPath:: operator = (const DICOMTagPath& path) { if (&path == this) return *this; - Reset(); - this->m_NodeInfos = path.m_NodeInfos; return *this; }; DICOMTagPath& DICOMTagPath:: FromStr(const std::string& pathStr) { NodeInfoVectorType result; std::istringstream f(pathStr); std::string subStr; while (getline(f, subStr, '.')) { NodeInfo info; if (subStr == "*") { info.type = NodeInfo::NodeType::AnyElement; } else { std::regex reg_element("\\((\\d{4}),(\\d{4})\\)"); std::regex reg_anySelection("\\((\\d{4}),(\\d{4})\\)\\[\\*\\]"); std::regex reg_Selection("\\((\\d{4}),(\\d{4})\\)\\[(\\d+)\\]"); std::smatch sm; if (std::regex_match(subStr, sm, reg_anySelection)) { info.type = NodeInfo::NodeType::AnySelection; info.tag = DICOMTag(std::stoul(sm[1], nullptr, 16), std::stoul(sm[2], nullptr, 16)); } else if (std::regex_match(subStr, reg_Selection)) { info.type = NodeInfo::NodeType::SequenceSelection; info.tag = DICOMTag(std::stoul(sm[1], nullptr, 16), std::stoul(sm[2], nullptr, 16)); info.selection = std::stoi(sm[3]); } else if (std::regex_match(subStr, reg_element)) { info.type = NodeInfo::NodeType::Element; info.tag = DICOMTag(std::stoul(sm[1], nullptr, 16), std::stoul(sm[2], nullptr, 16)); } } result.push_back(info); } this->m_NodeInfos.swap(result); return *this; }; DICOMTagPath::DICOMTagPath() { Reset(); }; DICOMTagPath:: DICOMTagPath(const DICOMTagPath& path) { *this = path; }; DICOMTagPath:: DICOMTagPath(const DICOMTag& tag) { NodeInfo info; info.type = NodeInfo::NodeType::Element; info.tag = tag; }; DICOMTagPath:: ~DICOMTagPath() {}; void DICOMTagPath:: Reset() { this->m_NodeInfos.clear(); }; bool DICOMTagPath:: DICOMTagPathesMatch(const DICOMTagPath& left, const DICOMTagPath& right) { NodeInfoVectorType::const_iterator leftPos = left.GetNodes().cbegin(); NodeInfoVectorType::const_iterator rightPos = right.GetNodes().cbegin(); NodeInfoVectorType::const_iterator leftEnd = left.GetNodes().cend(); NodeInfoVectorType::const_iterator rightEnd = right.GetNodes().cend(); while (leftPos != leftEnd && rightPos != rightEnd) { if (!leftPos->Matches(*rightPos)) break; ++leftPos; ++rightPos; } if (leftPos == leftEnd && rightPos == rightEnd) return true; else return false; }; std::ostream & operator<<(std::ostream &os, const DICOMTagPath &value) { os << value.ToStr(); return os; }; + + std::string TagPathToDCMTKSearchPath(const DICOMTagPath& tagPath) + { + if (!tagPath.IsExplicit() && !tagPath.HasItemSelectionWildcardsOnly()) + { + mitkThrow() << "Cannot convert DICOMTagPath into DCMTK search path. Path has element wild cards. Path: " << tagPath.ToStr(); + } + + return tagPath.ToStr(); + }; + } diff --git a/Modules/DICOMReader/src/mitkDICOMTagScanner.cpp b/Modules/DICOMReader/src/mitkDICOMTagScanner.cpp index 85783cefde..c5e12ada41 100644 --- a/Modules/DICOMReader/src/mitkDICOMTagScanner.cpp +++ b/Modules/DICOMReader/src/mitkDICOMTagScanner.cpp @@ -1,26 +1,76 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDICOMTagScanner.h" +itk::MutexLock::Pointer mitk::DICOMTagScanner::s_LocaleMutex = itk::MutexLock::New(); + mitk::DICOMTagScanner::DICOMTagScanner() { } mitk::DICOMTagScanner::~DICOMTagScanner() { } + +void mitk::DICOMTagScanner::PushLocale() const +{ + s_LocaleMutex->Lock(); + + std::string currentCLocale = setlocale(LC_NUMERIC, nullptr); + m_ReplacedCLocales.push(currentCLocale); + setlocale(LC_NUMERIC, "C"); + + std::locale currentCinLocale(std::cin.getloc()); + m_ReplacedCinLocales.push(currentCinLocale); + std::locale l("C"); + std::cin.imbue(l); + + s_LocaleMutex->Unlock(); +} + +void mitk::DICOMTagScanner::PopLocale() const +{ + s_LocaleMutex->Lock(); + + if (!m_ReplacedCLocales.empty()) + { + setlocale(LC_NUMERIC, m_ReplacedCLocales.top().c_str()); + m_ReplacedCLocales.pop(); + } + else + { + MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader."; + } + + if (!m_ReplacedCinLocales.empty()) + { + std::cin.imbue(m_ReplacedCinLocales.top()); + m_ReplacedCinLocales.pop(); + } + else + { + MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader."; + } + + s_LocaleMutex->Unlock(); +} + +std::string mitk::DICOMTagScanner::GetActiveLocale() +{ + return setlocale(LC_NUMERIC, nullptr); +}