]> Creatis software - gdcm.git/blob - src/gdcm.h
* src/gdcm.h, gdcmHeader.cxx:
[gdcm.git] / src / gdcm.h
1 // gdcmlib Intro:  
2 // * gdcmlib is a library dedicated to reading and writing dicom files.
3 // * LGPL for the license
4 // * lightweigth as opposed to CTN or DCMTK wich come bundled which try
5 //   to implement the full DICOM standard (networking...). gdcmlib concentrates
6 //   on reading and 
7 // * Formats: this lib should be able to read ACR-NEMA v1 and v2, Dicom v3 (as
8 //   stated in part10). [cf dcmtk/dcmdata/docs/datadict.txt]
9 // * Targeted plateforms: Un*xes and Win32/VC++6.0
10 //
11 //
12 // TODO
13 // The declarations commented out and starting with "TODO Swig" needed
14 // to be temporarily removed for swig to proceed correctly (in fact
15 // problems appears at loading of _gdcm.[so/dll]). So, simply uncomment
16 // the declaration once you provided the definition of the method...
17
18 #include <string>
19 #ifdef _MSC_VER
20 using namespace std;  // string type lives in the std namespace on VC++
21 #endif
22
23 #include <iostream>
24 #include <stddef.h>   // For size_t
25 #include <stdio.h>    // FIXME For FILE on GCC only
26 #include <map>
27
28 #ifdef __GNUC__
29 #include <stdint.h>
30 #define guint16 uint16_t
31 #define guint32 uint32_t
32 #endif
33
34 #ifdef _MSC_VER 
35 typedef  unsigned short guint16;
36 typedef  unsigned int guint32;
37 #endif
38
39 #ifdef _MSC_VER
40 #define GDCM_EXPORT __declspec( dllexport )
41 #else
42 #define GDCM_EXPORT
43 #endif
44
45 ////////////////////////////////////////////////////////////////////////////
46 // Tag based hash tables.
47 // We shall use as keys the strings (as the C++ type) obtained by
48 // concatenating the group value and the element value (both of type
49 // unsigned 16 bit integers in Dicom) expressed in hexadecimal.
50 // Example: consider the tag given as (group, element) = (0x0010, 0x0010).
51 // Then the corresponding TagKey shall be the string 0010|0010 (where
52 // the | (pipe symbol) acts as a separator). Refer to 
53 // gdcmDictEntry::TranslateToKey for this conversion function.
54 typedef string TagKey;
55
56 class GDCM_EXPORT gdcmDictEntry {
57 private:
58         guint16 group;    // e.g. 0x0010
59         guint16 element;  // e.g. 0x0010
60         string  vr;       // Value Representation i.e. some clue about the nature
61                           // of the data represented e.g. "FD" short for
62                           // "Floating Point Double"
63         // CLEANME: find the official dicom name for this field !
64         string  fourth;   // Fourth field containing some semantics.
65         string  name;     // e.g. "Patient_Name"
66         TagKey  key;      // Redundant with (group, element) but we add it
67                           // on efficiency purposes.
68         // DCMTK has many fields for handling a DictEntry (see below). What are the
69         // relevant ones for gdcmlib ?
70         //      struct DBI_SimpleEntry {
71         //         Uint16 upperGroup;
72         //         Uint16 upperElement;
73         //         DcmEVR evr;
74         //         const char* tagName;
75         //         int vmMin;
76         //         int vmMax;
77         //         const char* standardVersion;
78         //         DcmDictRangeRestriction groupRestriction;
79         //         DcmDictRangeRestriction elementRestriction;
80         //       };
81 public:
82         gdcmDictEntry(guint16 group, guint16 element,
83                       string vr     = "Unknown",
84                       string fourth = "Unknown",
85                       string name   = "Unknown");
86         static TagKey TranslateToKey(guint16 group, guint16 element);
87         guint16 GetGroup(void)  { return group;};
88         guint16 GetElement(void){return element;};
89         string  GetVR(void)     {return vr; };
90         void    SetVR(string);
91         bool    IsVrUnknown(void);
92         string  GetFourth(void) {return fourth;};
93         string  GetName(void)   {return name;};
94         string  GetKey(void)    {return key;};
95 };
96   
97 ////////////////////////////////////////////////////////////////////////////
98 // A single DICOM dictionary i.e. a container for a collection of dictionary
99 // entries. There should be a single public dictionary (THE dictionary of
100 // the actual DICOM v3) but as many shadow dictionaries as imagers 
101 // combined with all software versions...
102 typedef map<TagKey, gdcmDictEntry*> TagHT;
103
104 class GDCM_EXPORT gdcmDict {
105         string name;
106         string filename;
107         TagHT entries;
108 public:
109         gdcmDict(const char* FileName);   // Read Dict from disk
110         // TODO Swig int AppendEntry(gdcmDictEntry* NewEntry);
111         gdcmDictEntry * GetTag(guint32 group, guint32 element);
112         void Print(ostream&);
113 };
114
115 ////////////////////////////////////////////////////////////////////////////
116 // Container for managing a set of loaded dictionaries. Sharing dictionaries
117 // should avoid :
118 // * reloading an allready loaded dictionary,
119 // * having many in memory representations of the same dictionary.
120 typedef string DictKey;
121 typedef map<DictKey, gdcmDict*> DictSetHT;
122
123 class GDCM_EXPORT gdcmDictSet {
124 private:
125         string DictPath;      // Directory path to dictionaries
126         DictSetHT dicts;
127         int AppendDict(gdcmDict* NewDict);
128         int LoadDictFromFile(string filename, DictKey);
129         void SetDictPath(void);
130 public:
131         gdcmDictSet(void);    // loads THE DICOM v3 dictionary
132         // TODO Swig int LoadDictFromFile(string filename);
133    // QUESTION: the following function might not be thread safe !? Maybe
134    //           we need some mutex here, to avoid concurent creation of
135    //           the same dictionary !?!?!
136         // TODO Swig int LoadDictFromName(string filename);
137         // TODO Swig int LoadAllDictFromDirectory(string DirectoryName);
138         // TODO Swig string* GetAllDictNames();
139         int LoadDicomV3Dict(void);
140         void Print(ostream&);
141         gdcmDict* GetDict(DictKey DictName);
142         gdcmDict* GetDefaultPublicDict(void);
143 };
144
145 ////////////////////////////////////////////////////////////////////////////
146 // The dicom header of a Dicom file contains a set of such ELement VALUES
147 // (when successfuly parsed against a given Dicom dictionary)
148 class GDCM_EXPORT ElValue {
149 private:
150         gdcmDictEntry *entry;
151         guint32 LgrElem;
152         bool ImplicitVr;       // Even when reading explicit vr files, some
153                                // elements happen to be implicit. Flag them here
154                                // since we can't use the entry->vr without breaking
155                                // the underlying dictionary.
156         // Might prove of some interest (see _ID_DCM_ELEM)
157         // int Swap;
158 public:
159         string  value;     // used to be char * valeurElem
160         size_t Offset;     // Offset from the begining of file for direct user access
161         ElValue(gdcmDictEntry*);
162         void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
163
164         bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
165         void SetLength(guint32 l){LgrElem = l; };
166         void SetValue(string val){ value = val; };
167         void SetOffset(size_t of){ Offset = of; };
168         void SetImplicitVr(void) { ImplicitVr = true; };
169         bool  IsImplicitVr(void) { return ImplicitVr; };
170         void    SetVR(string);
171         string  GetVR(void);
172         string  GetValue(void)   { return value; };
173         guint32 GetLength(void)  { return LgrElem; };
174         size_t  GetOffset(void)  { return Offset; };
175         guint16 GetGroup(void)   { return entry->GetGroup(); };
176         guint16 GetElement(void) { return entry->GetElement(); };
177         string  GetKey(void)     { return entry->GetKey(); };
178         string  GetName(void)    { return entry->GetName();};
179 };
180
181 ////////////////////////////////////////////////////////////////////////////
182 // Container for a set of succefully parsed ElValues.
183 typedef map<TagKey, ElValue*> TagElValueHT;
184         typedef map<string, ElValue*> TagElValueNameHT;
185
186 class GDCM_EXPORT ElValSet {
187                 // We need both accesses with a TagKey and the Dictentry.Name
188         TagElValueHT tagHt;
189         TagElValueNameHT NameHt;
190 public:
191         void Add(ElValue*);
192         void Print(ostream &);
193         void PrintByName(ostream &);
194         ElValue* GetElementByNumber(guint32 group, guint32 element);
195         ElValue* GetElementByName(string);
196         string GetElValueByNumber(guint32 group, guint32 element);
197         string GetElValueByName(string);
198         TagElValueHT & GetTagHt(void);
199 };
200
201 ////////////////////////////////////////////////////////////////////////////
202 // The typical usage of instances of class gdcmHeader is to classify a set of
203 // dicom files according to header information e.g. to create a file hierachy
204 // reflecting the Patient/Study/Serie informations, or extracting a given
205 // SerieId. Accesing the content (image[s] or volume[s]) is beyond the
206 // functionality of this class and belong to gdmcFile (see below).
207 // Notes:
208 // * the various entries of the explicit value representation (VR) shall
209 //   be managed within a dictionary which is shared by all gdcmHeader instances
210 // * the gdcmHeader::Set*Tag* family members cannot be defined as protected
211 //   (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
212  
213 typedef string VRKey;
214 typedef string VRAtr;
215 typedef map<TagKey, VRAtr> VRHT;    // Value Representation Hash Table
216
217 class GDCM_EXPORT gdcmHeader {
218         void SkipBytes(guint32);
219 private:
220         static VRHT *dicom_vr;
221         // Dictionaries of data elements:
222         static gdcmDictSet* Dicts;  // global dictionary container
223         gdcmDict* RefPubDict;       // public dictionary
224         gdcmDict* RefShaDict;       // shadow dictionary (optional)
225         // Parsed element values:
226         ElValSet PubElVals;         // parsed with Public Dictionary
227         ElValSet ShaElVals;         // parsed with Shadow Dictionary
228         string filename;            // refering underlying file
229         FILE * fp;
230         // The tag Image Location ((0028,0200) containing the address of
231         // the pixels) is not allways present. When we store this information
232         // FIXME
233         // outside of the elements:
234         guint16 grPixel;
235         guint16 numPixel;
236         // Swap code (little, big, big-bad endian): this code is not fixed
237         // during parsing.FIXME sw should be an enum e.g.
238         //enum EndianType {
239                 //LittleEndian, 
240                 //BadLittleEndian,
241                 //BigEndian, 
242                 //BadBigEndian};
243         int sw;
244         // Only the elements whose size are below this bound shall be loaded.
245         // By default, this upper bound is limited to 1024 (which looks reasonable
246         // when one considers the definition of the various VR contents).
247         guint32 MaxSizeLoadElementValue;
248
249         guint16 ReadInt16(void);
250         guint32 ReadInt32(void);
251         guint16 SwapShort(guint16);
252         guint32 SwapLong(guint32);
253         void Initialise(void);
254         void CheckSwap(void);
255         void FindLength(ElValue *);
256         guint32 FindLengthOB(void);
257         void FindVR(ElValue *);
258         void LoadElementValue(ElValue *);
259         void LoadElementValueSafe(ElValue *);
260         void SkipElementValue(ElValue *);
261         void InitVRDict(void);
262         void SwitchSwapToBigEndian(void);
263         void FixFoundLength(ElValue*, guint32);
264         bool IsAnInteger(ElValue *);
265         bool IsBigEndianTransferSyntax(void);
266         void SetMaxSizeLoadElementValue(long);
267         ElValue       * ReadNextElement(void);
268         gdcmDictEntry * IsInDicts(guint32, guint32);
269         size_t GetPixelOffset(void);
270 protected:
271         enum FileType {
272                 Unknown = 0,
273                 TrueDicom,
274                 ExplicitVR,
275                 ImplicitVR,
276                 ACR,
277                 ACR_LIBIDO};  // CLEANME
278         FileType filetype;
279         int write(ostream&);   
280         int anonymize(ostream&);  // FIXME : anonymize should be a friend ?
281 public:
282         void LoadElements(void);
283         virtual void ParseHeader(void);
284         gdcmHeader(const char* filename);
285         virtual ~gdcmHeader();
286
287         // TODO Swig int SetPubDict(string filename);
288         // When some proprietary shadow groups are disclosed, whe can set
289         // up an additional specific dictionary to access extra information.
290         // TODO Swig int SetShaDict(string filename);
291
292         // Retrieve all potentially available tag [tag = (group, element)] names
293         // from the standard (or public) dictionary. Typical usage: enable the
294         // user of a GUI based interface to select his favorite fields for sorting
295         // or selection.
296         // TODO Swig string* GetPubTagNames();
297         // Get the element values themselves:
298         string GetPubElValByName(string TagName);
299         string GetPubElValByNumber(guint16 group, guint16 element);
300         // Getting the element value representation (VR) might be needed by caller
301         // to convert the string typed content to caller's native type (think
302         // of C/C++ vs Python).
303         string GetPubElValRepByName(string TagName);
304         string GetPubElValRepByNumber(guint16 group, guint16 element);
305         TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
306         void   PrintPubElVal(ostream & os = cout);
307         void   PrintPubDict(ostream &);
308           
309         // Same thing with the shadow :
310         // TODO Swig string* GetShaTagNames(); 
311         string GetShaElValByName(string TagName);
312         string GetShaElValByNumber(guint16 group, guint16 element);
313         string GetShaElValRepByName(string TagName);
314         string GetShaElValRepByNumber(guint16 group, guint16 element);
315
316         // Wrappers of the above (public is privileged over shadow) to avoid
317         // bugging the caller with knowing if ElVal is from the public or shadow
318         // dictionary.
319         string GetElValByName(string TagName);
320         string GetElValByNumber(guint16 group, guint16 element);
321         string GetElValRepByName(string TagName);
322         string GetElValRepByNumber(guint16 group, guint16 element);
323
324         // TODO Swig int SetPubElValByName(string content, string TagName);
325         // TODO Swig int SetPubElValByNumber(string content, guint16 group, guint16 element);
326         // TODO Swig int SetShaElValByName(string content, string ShadowTagName);
327         // TODO Swig int SetShaElValByNumber(string content, guint16 group, guint16 element);
328
329         // TODO Swig int GetSwapCode();
330 };
331
332 ////////////////////////////////////////////////////////////////////////////
333 // In addition to Dicom header exploration, this class is designed
334 // for accessing the image/volume content. One can also use it to
335 // write Dicom files.
336 ////// QUESTION: this looks still like an open question wether the
337 //////           relationship between a gdcmFile and gdcmHeader is of
338 //////           type IS_A or HAS_A !
339 class GDCM_EXPORT gdcmFile: gdcmHeader
340 {
341 private:
342         void* Data;
343         int Parsed;          // weather allready parsed
344         string OrigFileName; // To avoid file overwrite
345 public:
346         // Constructor dedicated to writing a new DICOMV3 part10 compliant
347         // file (see SetFileName, SetDcmTag and Write)
348         // TODO Swig gdcmFile();
349         // Opens (in read only and when possible) an existing file and checks
350         // for DICOM compliance. Returns NULL on failure.
351         // Note: the in-memory representation of all available tags found in
352         //    the DICOM header is post-poned to first header information access.
353         //    This avoid a double parsing of public part of the header when
354         //    one sets an a posteriori shadow dictionary (efficiency can be
355         //    seen a a side effect).
356         gdcmFile(string & filename);
357         // For promotion (performs a deepcopy of pointed header object)
358         // TODO Swig gdcmFile(gdcmHeader* header);
359         // TODO Swig ~gdcmFile();
360
361         // On writing purposes. When instance was created through
362         // gdcmFile(string filename) then the filename argument MUST be different
363         // from the constructor's one (no overwriting aloud).
364         // TODO Swig int SetFileName(string filename);
365
366         // Allocates necessary memory, copies the data (image[s]/volume[s]) to
367         // newly allocated zone and return a pointer to it:
368         // TODO Swig void * GetImageData();
369         // Returns size (in bytes) of required memory to contain data
370         // represented in this file.
371         // TODO Swig size_t GetImageDataSize();
372         // Copies (at most MaxSize bytes) of data to caller's memory space.
373         // Returns an error code on failure (if MaxSize is not big enough)
374         // TODO Swig int PutImageDataHere(void* destination, size_t MaxSize );
375         // Allocates ExpectedSize bytes of memory at this->Data and copies the
376         // pointed data to it.
377         // TODO Swig int SetImageData(void * Data, size_t ExpectedSize);
378         // Push to disk.
379         // TODO Swig int Write();
380 };
381
382 //class gdcmSerie : gdcmFile;
383 //class gdcmMultiFrame : gdcmFile;