1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 /*=========================================================================
19  *
20  *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21  *
22  *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23  *
24  *  For complete copyright, license and disclaimer of warranty information
25  *  please refer to the NOTICE file at the top of the ITK source tree.
26  *
27  *=========================================================================*/
28 #ifndef itkGDCMImageIO_h
29 #define itkGDCMImageIO_h
30 
31 #define ITKIO_DEPRECATED_GDCM1_API
32 
33 #include "itkImageIOBase.h"
34 #include "ITKIOGDCMExport.h"
35 #include <fstream>
36 #include <string>
37 
38 namespace itk
39 {
40 /** \class GDCMImageIO
41  *
42  *  \brief ImageIO class for reading and writing DICOM V3.0 and ACR/NEMA 1&2 uncompressed images.
43  *  This class is only an adaptor to the GDCM library.
44  *
45  * GDCM can be found at:
46  *   http://sourceforge.net/projects/gdcm
47  *
48  * To learn more about the revision shipped with ITK, call
49  *
50  *    git log -- Modules/ThirdParty/GDCM/src/
51  *
52  * From an ITK Git checkout.
53  *
54  * GDCM build, instead of the one included within ITK itself.
55  *
56  * The compressors supported include "JPEG2000" (default), and
57  * "JPEG". The compression level parameter is not supported.
58  *
59  *  \warning There are several restrictions to this current writer:
60  *           -  Even though during the writing process you pass in a DICOM file as input
61  *              The output file may not contains ALL DICOM field from the input file.
62  *              In particular:
63  *                             - The SeQuence DICOM field (SQ).
64  *                             - Fields from Private Dictionary.
65  *           -  Some very long (>0xfff) binary fields are not loaded (typically 0029|0010),
66  *              you need to explicitely set the maximum length of elements to load to be bigger
67  *              (see Get/SetMaxSizeLoadEntry).
68  *           - In DICOM some fields are stored directly using their binary representation. When loaded into
69  *             the MetaDataDictionary some fields are converted to ASCII (only VR: OB/OW/OF and UN are encoded as
70  *             mime64).
71  *
72  *  \ingroup IOFilters
73  *
74  * \ingroup ITKIOGDCM
75  *
76  * \wiki
77  * \wikiexample{DICOM/ResampleDICOM,Resample a DICOM series}
78  * \endwiki
79  */
80 class InternalHeader;
81 class ITKIOGDCM_EXPORT GDCMImageIO:public ImageIOBase
82 {
83 public:
84   ITK_DISALLOW_COPY_AND_ASSIGN(GDCMImageIO);
85 
86   /** Standard class type aliases. */
87   using Self = GDCMImageIO;
88   using Superclass = ImageIOBase;
89   using Pointer = SmartPointer< Self >;
90 
91   /** Method for creation through the object factory. */
92   itkNewMacro(Self);
93 
94   /** Run-time type information (and related methods). */
95   itkTypeMacro(GDCMImageIO, Superclass);
96 
97   /*-------- This part of the interface deals with reading data. ------ */
98 
99   /** Determine the file type. Returns true if this ImageIO can read the
100    * file specified. */
101   bool CanReadFile(const char *) override;
102 
103   /** Set the spacing and dimesion information for the current filename. */
104   void ReadImageInformation() override;
105 
106   /** Reads the data from disk into the memory buffer provided. */
107   void Read(void *buffer) override;
108 
109   /** Set/Get the original component type of the image. This differs from
110    * ComponentType which may change as a function of rescale slope and
111    * intercept. */
112   itkGetEnumMacro(InternalComponentType, IOComponentType);
113   itkSetEnumMacro(InternalComponentType, IOComponentType);
114 
115   /*-------- This part of the interfaces deals with writing data. ----- */
116 
117   /** Determine the file type. Returns true if this ImageIO can write the
118    * file specified. GDCM triggers on ".dcm" and ".dicom". */
119   bool CanWriteFile(const char *) override;
120 
121   /** Writes the spacing and dimensions of the image.
122    * Assumes SetFileName has been called with a valid file name. */
123   void WriteImageInformation() override;
124 
125   /** Writes the data to disk from the memory buffer provided. Make sure
126    * that the IORegion has been set properly. */
127   void Write(const void *buffer) override;
128 
129   /** Macro to access Rescale Slope and Rescale Intercept. Which are
130    * needed to rescale properly image when needed. User then need to
131    * Always check those value when access value from the DICOM header */
132   itkGetConstMacro(RescaleSlope, double);
133   itkGetConstMacro(RescaleIntercept, double);
134 
135   /** Macro to access the DICOM UID prefix. By default this is the ITK
136    *  root id. This default can be overriden if the exam is for example
137    *  part of an existing study.
138    */
139   itkGetStringMacro(UIDPrefix);
140   itkSetStringMacro(UIDPrefix);
141 
142   /** Access the generated DICOM UID's. */
143   itkGetStringMacro(StudyInstanceUID);
144   itkGetStringMacro(SeriesInstanceUID);
145   itkGetStringMacro(FrameOfReferenceInstanceUID);
146 
147   /** Preserve the original DICOM UID of the input files
148    */
149   itkSetMacro(KeepOriginalUID, bool);
150   itkGetConstMacro(KeepOriginalUID, bool);
151   itkBooleanMacro(KeepOriginalUID);
152 
153   /** Parse and load any private tags in the DICOM file. Loading DICOM
154    * files is faster when private tags are not needed. Default is false.
155    */
156   itkSetMacro(LoadPrivateTags, bool);
157   itkGetConstMacro(LoadPrivateTags, bool);
158   itkBooleanMacro(LoadPrivateTags);
159 
160 #if defined( ITKIO_DEPRECATED_GDCM1_API )
161   /** Convenience methods to query patient information and scanner
162    * information. These methods are here for compatibility with the
163    * DICOMImageIO2 class and as such should not be used in any new code.
164    * They rely on properly preallocated buffer, which is not a good practice.
165    * Instead user are encourage to use directly the GetValueFromTag function
166    */
167   void GetPatientName(char *name);
168 
169   void GetPatientID(char *id);
170 
171   void GetPatientSex(char *sex);
172 
173   void GetPatientAge(char *age);
174 
175   void GetStudyID(char *id);
176 
177   void GetPatientDOB(char *dob);
178 
179   void GetStudyDescription(char *desc);
180 
181   void GetBodyPart(char *part);
182 
183   void GetNumberOfSeriesInStudy(char *series);
184 
185   void GetNumberOfStudyRelatedSeries(char *series);
186 
187   void GetStudyDate(char *date);
188 
189   void GetModality(char *modality);
190 
191   void GetManufacturer(char *manu);
192 
193   void GetInstitution(char *ins);
194 
195   void GetModel(char *model);
196 
197   void GetScanOptions(char *options);
198 #endif
199 
200   /** More general method to retrieve an arbitrary DICOM value based
201    * on a DICOM Tag (eg "0123|45ef").
202    */
203   bool GetValueFromTag(const std::string & tag, std::string & value);
204 
205   /** Method for consulting the DICOM dictionary and recovering the text
206    * description of a field using its numeric tag represented as a string.  If
207    * the tagkey is not found in the dictionary then this static method return
208    * false and the value "Unknown " in the labelId. If the tagkey is found then
209    * this static method returns true and the actual string descriptor of the
210    * tagkey is returned in the variable labelId. */
211   static bool GetLabelFromTag(const std::string & tag,
212                               std::string & labelId);
213 
214 #if defined( ITKIO_DEPRECATED_GDCM1_API )
215   /** A DICOM file can contains multiple binary stream that can be very long
216    * For example an Overlay on the image. Most of the time user do not want to load
217    * this binary structure in memory since it can consume lot of memory. Therefore
218    * any field that is bigger than the default value 0xfff is discarded and just seek'd
219    * This method allow advanced user to force the reading of such field
220    * \warning this is a GDCM 1.x only option, no effect on GDCM 2.x
221    */
SetMaxSizeLoadEntry(const long)222   virtual void SetMaxSizeLoadEntry( const long ) {}
223 
224   /** Parse any sequences in the DICOM file. Defaults to the value of
225    *  LoadSequencesDefault. Loading DICOM files is faster when
226    *  sequences are not needed.
227    * \warning this is a GDCM 1.x only option, no effect on GDCM 2.x
228    */
SetLoadSequences(const bool)229   virtual void SetLoadSequences( const bool ) {}
GetLoadSequences()230   virtual bool GetLoadSequences () const { return true; }
LoadSequencesOn()231   virtual void LoadSequencesOn () {}
LoadSequencesOff()232   virtual void LoadSequencesOff () {}
233 
234   /** Global method to define the default value for
235    * LoadSequences. When instances of GDCMImageIO are created, the
236    * ivar LoadSequences is initialized to the value of
237    * LoadSequencesDefault.  This method is useful when relying on the
238    * IO factory mechanism to load images rather than specifying a
239    * particular ImageIO object on the readers. Default is false.
240    * \warning this is a GDCM 1.x only option, no effect on GDCM 2.x
241    */
SetLoadSequencesDefault(bool)242   static void SetLoadSequencesDefault(bool) {}
LoadSequencesDefaultOn()243   static void LoadSequencesDefaultOn() {}
LoadSequencesDefaultOff()244   static void LoadSequencesDefaultOff() {}
GetLoadSequencesDefault()245   static bool GetLoadSequencesDefault() { return true; }
246 
247   /** Global method to define the default value for
248    * LoadPrivateTags. When instances of GDCMImageIO are created, the
249    * ivar LoadPrivateTags is initialized to the value of
250    * LoadPrivateTagsDefault.  This method is useful when relying on the
251    * IO factory mechanism to load images rather than specifying a
252    * particular ImageIO object on the readers. Default is false.
253    * \warning this is a GDCM 1.x only option, no effect on GDCM 2.x
254    */
SetLoadPrivateTagsDefault(bool)255   static void SetLoadPrivateTagsDefault(bool) {}
LoadPrivateTagsDefaultOn()256   static void LoadPrivateTagsDefaultOn() {}
LoadPrivateTagsDefaultOff()257   static void LoadPrivateTagsDefaultOff() {}
GetLoadPrivateTagsDefault()258   static bool GetLoadPrivateTagsDefault() { return true; }
259 #endif
260 
261   /** Set/Get a compression type to use. */
262   typedef enum { JPEG = 0, JPEG2000, JPEGLS, RLE } TCompressionType;
263   itkSetEnumMacro(CompressionType, TCompressionType);
264   itkGetEnumMacro(CompressionType, TCompressionType);
265 
266   void InternalSetCompressor(const std::string &_compressor ) override;
267 
268 protected:
269   GDCMImageIO();
270   ~GDCMImageIO() override;
271   void PrintSelf(std::ostream & os, Indent indent) const override;
272 
273   void InternalReadImageInformation();
274 
275   double m_RescaleSlope;
276   double m_RescaleIntercept;
277 
278   std::string m_UIDPrefix;
279   std::string m_StudyInstanceUID;
280   std::string m_SeriesInstanceUID;
281   std::string m_FrameOfReferenceInstanceUID;
282 
283   bool m_KeepOriginalUID;
284 
285   bool m_LoadPrivateTags;
286 
287 private:
288 #if defined( ITKIO_DEPRECATED_GDCM1_API )
289   std::string m_PatientName;
290   std::string m_PatientID;
291   std::string m_PatientDOB;
292   std::string m_StudyID;
293   std::string m_StudyDescription;
294   std::string m_BodyPart;
295   std::string m_NumberOfSeriesInStudy;
296   std::string m_NumberOfStudyRelatedSeries;
297   std::string m_PatientSex;
298   std::string m_PatientAge;
299   std::string m_StudyDate;
300   std::string m_Modality;
301   std::string m_Manufacturer;
302   std::string m_Institution;
303   std::string m_Model;
304   std::string m_ScanOptions;
305 #endif
306 
307   /** defines whether this image is a 2D out of a 2D image
308    *  or a 2D out of a 3D image. */
309   unsigned int     m_GlobalNumberOfDimensions;
310   TCompressionType m_CompressionType;
311 
312   ImageIOBase::IOComponentType m_InternalComponentType;
313   InternalHeader *             m_DICOMHeader;
314 };
315 } // end namespace itk
316 
317 #endif // itkGDCMImageIO_h
318