]> Creatis software - gdcm.git/blob - src/gdcm.h
Commenataires?
[gdcm.git] / src / gdcm.h
1 // gdcm.h
2
3 // gdcmlib Intro:  
4 // * gdcmlib is a library dedicated to reading and writing dicom files.
5 // * LGPL for the license
6 // * lightweigth as opposed to CTN or DCMTK wich come bundled which try
7 //   to implement the full DICOM standard (networking...). gdcmlib concentrates
8 //   on reading and writing
9 // * Formats: this lib should be able to read ACR-NEMA v1 and v2, Dicom v3 (as
10 //   stated in part10). [cf dcmtk/dcmdata/docs/datadict.txt]
11 // * Targeted plateforms: Un*xes and Win32/VC++6.0
12 //
13 //
14 // TODO
15 // The declarations commented out and starting with "TODO Swig" needed
16 // to be temporarily removed for swig to proceed correctly (in fact
17 // problems appears at loading of _gdcm.[so/dll]). So, simply uncomment
18 // the declaration once you provided the definition of the method...
19
20 #include <string>
21 #ifdef _MSC_VER
22 using namespace std;  // string type lives in the std namespace on VC++
23 #endif
24
25 #include <iostream>
26 #include <stddef.h>   // For size_t
27 #include <stdio.h>    // FIXME For FILE on GCC only
28 #include <list>
29 #include <map>
30
31                       // The requirement for the hash table (or map) that
32                       // we shall use:
33                       // 1/ First, next, last (iterators)
34                       // 2/ should be sortable (i.e. sorted by TagKey). This
35                       //    condition shall be droped since the Win32/VC++
36                       //    implementation doesn't look a sorted one. Pffff....
37                       // 3/ Make sure we can setup some default size value,
38                       //    which should be around 4500 entries which is the
39                       //    average dictionary size (said JPR)
40                       //
41                       // En fait, je disais que dans LE Directory Dicom (dans son etat 2002)
42                       // il y a 1600 entrees.
43                       // Une valeur raisonable pour un  majorant du nombre d'entrees
44                       // dans une entete DICOM d'une image semble semble etre 300
45                       // Si on 'decortique' les elements SQ (ce qui ne semble pas etre fait pour le moment)
46                       // on risque en fait de depasser ... un nombre non previsible dans le cas d'une entree SQ
47                       // contenant lui même un tres grand nombre d'entrees ?!?)
48                       // Quant au nombre d'entrees dans un DICOMDIR, c'est encore pire : il n'est limité
49                       // que par la taille d'un CD-ROM (les DVD-ROM ne sont pas encore pris en compte)
50                       // On peut s'attendre a 30 entrees par fichier dicom présent sur le CD-ROM
51                       // Remarque : il faudra se pencher sur le pb de la creation du DICOMDIR lorsqu'on voudra 
52                       // exporter des images lisibles par les consoles cliniques 
53                       // et pas seulement importables dans e-film. 
54
55
56 #ifdef __GNUC__
57 #include <stdint.h>
58 #define guint16 uint16_t
59 #define guint32 uint32_t
60 #endif
61
62 #ifdef _MSC_VER 
63 typedef  unsigned short guint16;
64 typedef  unsigned int guint32;
65 #endif
66
67 #ifdef _MSC_VER
68 #define GDCM_EXPORT __declspec( dllexport )
69 #else
70 #define GDCM_EXPORT
71 #endif
72
73
74 //
75 // ---------------------------------------------------- gdcmDictEntry
76 //
77 //      c'est une ligne du Dictionnaire Dicom
78 //
79
80
81 ////////////////////////////////////////////////////////////////////////////
82 // Tag based hash tables.
83 // We shall use as keys the strings (as the C++ type) obtained by
84 // concatenating the group value and the element value (both of type
85 // unsigned 16 bit integers in Dicom) expressed in hexadecimal.
86 // Example: consider the tag given as (group, element) = (0x0010, 0x0010).
87 // Then the corresponding TagKey shall be the string 0010|0010 (where
88 // the | (pipe symbol) acts as a separator). Refer to 
89 // gdcmDictEntry::TranslateToKey for this conversion function.
90
91 typedef string TagKey;
92
93 class GDCM_EXPORT gdcmDictEntry {
94 private:
95         guint16 group;    // e.g. 0x0010
96         guint16 element;  // e.g. 0x0103
97         string  vr;       // Value Representation i.e. some clue about the nature
98                           // of the data represented e.g. "FD" short for
99                           // "Floating Point Double"
100         // CLEANME: find the official dicom name for this field !
101         string  fourth;   // Fourth field containing some semantics.
102         string  name;     // e.g. "Patient_Name"
103         TagKey  key;      // Redundant with (group, element) but we add it
104                           // on efficiency purposes.
105         // DCMTK has many fields for handling a DictEntry (see below). What are the
106         // relevant ones for gdcmlib ?
107         //      struct DBI_SimpleEntry {
108         //         Uint16 upperGroup;
109         //         Uint16 upperElement;
110         //         DcmEVR evr;
111         //         const char* tagName;
112         //         int vmMin;
113         //         int vmMax;
114         //         const char* standardVersion;
115         //         DcmDictRangeRestriction groupRestriction;
116         //         DcmDictRangeRestriction elementRestriction;
117         //       };
118 public:
119         
120         // fabrique une ligne de Dictionnaire Dicom à partir des parametres en entrée
121
122
123         gdcmDictEntry(guint16 group, guint16 element,
124                       string vr     = "Unknown",
125                       string fourth = "Unknown",
126                       string name   = "Unknown");
127                                           
128         // fabrique une 'clé' par concaténation du numGroupe et du numElement
129
130         static TagKey TranslateToKey(guint16 group, guint16 element);
131         
132         guint16 GetGroup(void)  { return group;};
133         guint16 GetElement(void){return element;};
134         string  GetVR(void)     {return vr; };
135         void    SetVR(string);
136         bool    IsVrUnknown(void);
137         string  GetFourth(void) {return fourth;};
138         string  GetName(void)   {return name;};
139         string  GetKey(void)    {return key;};
140 };
141   
142 //
143 // ---------------------------------------------------- gdcmDict
144 // 
145 //      c'est le Dictionnaire Dicom
146 //
147
148   
149 ////////////////////////////////////////////////////////////////////////////
150 // A single DICOM dictionary i.e. a container for a collection of dictionary
151 // entries. There should be a single public dictionary (THE dictionary of
152 // the actual DICOM v3) but as many shadow dictionaries as imagers 
153 // combined with all software versions...
154
155 typedef map<TagKey, gdcmDictEntry*> TagHT;
156         // Table de Hachage  (group,Elem) --> ligne du Dictionnaire Dicom
157
158 typedef map<TagKey, gdcmDictEntry*> TagHT;
159
160 class GDCM_EXPORT gdcmDict {
161         string name;
162         string filename;
163         TagHT entries;
164 public:
165         // rempli le Dictionnaire Dicom à partir d'un fichier texte
166         gdcmDict(const char* FileName);   // Read Dict from disk
167         
168         // TODO Swig int AppendEntry(gdcmDictEntry* NewEntry);
169         
170         // renvoie une ligne de Dictionnaire Dicom à partir de (numGroup, numElement)
171         gdcmDictEntry * GetTag(guint32 group, guint32 element);
172         void Print(ostream&);
173         TagHT & GetEntries(void) { return entries; }
174 };
175
176
177 //
178 // ---------------------------------------------------- gdcmDictSet
179 //
180 //      Ensemble de Dictionnaires Dicom (le public + 'des' privés)
181 //      Au cas ou l'on traiterait un jour les 'dictionnaires privés'
182 //       - pratiquement un par constructeur, par machine, et par version du logiciel -
183 //
184 //
185
186 ////////////////////////////////////////////////////////////////////////////
187 // Container for managing a set of loaded dictionaries. Sharing dictionaries
188 // should avoid :
189 // * reloading an allready loaded dictionary,
190 // * having many in memory representations of the same dictionary.
191
192 typedef string DictKey;
193 typedef map<DictKey, gdcmDict*> DictSetHT;
194
195 class GDCM_EXPORT gdcmDictSet {
196 private:
197         string DictPath;      // Directory path to dictionaries
198         DictSetHT dicts;
199         int AppendDict(gdcmDict* NewDict);
200         int LoadDictFromFile(string filename, DictKey);
201         void SetDictPath(void);
202 public:
203         gdcmDictSet(void);    // loads THE DICOM v3 dictionary
204         // TODO Swig int LoadDictFromFile(string filename);
205    // QUESTION: the following function might not be thread safe !? Maybe
206    //           we need some mutex here, to avoid concurent creation of
207    //           the same dictionary !?!?!
208         // TODO Swig int LoadDictFromName(string filename);
209         // TODO Swig int LoadAllDictFromDirectory(string DirectoryName);
210         // TODO Swig string* GetAllDictNames();
211         //
212         // Question : ne faudra-t-il pas mettre LE dictionnaire DICOM dans un Directory
213         // et les eventuels 'dictionnaires prives' dans un autre?
214         //
215         int LoadDicomV3Dict(void);
216         void Print(ostream&);
217         gdcmDict* GetDict(DictKey DictName);
218         gdcmDict* GetDefaultPublicDict(void);
219 };
220
221
222 //
223 // ---------------------------------------------------- ElValue
224 //
225 //      C'est un Element Dicom
226 //      (ce qu'on a trouve dans l'entete de l'image
227 //      + ce qu'on est allé chercher dans le Dictionnaire Dicom)
228 //
229
230
231 // The dicom header of a Dicom file contains a set of such ELement VALUES
232 // (when successfuly parsed against a given Dicom dictionary)
233
234 class GDCM_EXPORT ElValue {
235 private:
236         gdcmDictEntry *entry;
237         guint32 LgrElem;
238         bool ImplicitVr;       // Even when reading explicit vr files, some
239                                // elements happen to be implicit. Flag them here
240                                // since we can't use the entry->vr without breaking
241                                // the underlying dictionary.
242         // Might prove of some interest (see _ID_DCM_ELEM)
243         // int Swap;
244 public:
245         string  value;     // used to be char * valeurElem
246         size_t Offset;     // Offset from the begining of file for direct user access
247         ElValue(gdcmDictEntry*);
248         void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
249
250         bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
251         void SetLength(guint32 l){ LgrElem = l; };
252         void SetValue(string val){ value = val; };
253         void SetOffset(size_t of){ Offset = of; };
254         void SetImplicitVr(void) { ImplicitVr = true; };
255         bool  IsImplicitVr(void) { return ImplicitVr; };
256         void    SetVR(string);
257         string  GetVR(void);
258         string  GetValue(void)   { return value; };
259         guint32 GetLength(void)  { return LgrElem; };
260         size_t  GetOffset(void)  { return Offset; };
261         guint16 GetGroup(void)   { return entry->GetGroup(); };
262         guint16 GetElement(void) { return entry->GetElement(); };
263         string  GetKey(void)     { return entry->GetKey(); };
264         string  GetName(void)    { return entry->GetName();};
265 };
266
267
268 //
269 // ---------------------------------------------------- ElValSet
270 //
271 //      ... un ensemble d'Elements Dicom 
272 //
273
274 ////////////////////////////////////////////////////////////////////////////
275 // Container for a set of succefully parsed ElValues.
276 typedef map<TagKey, ElValue*> TagElValueHT;
277 typedef map<string, ElValue*> TagElValueNameHT;
278
279 class GDCM_EXPORT ElValSet {
280                 // We need both accesses with a TagKey and the Dictentry.Name
281         TagElValueHT tagHt;
282         TagElValueNameHT NameHt;
283 public:
284         void Add(ElValue*);
285         void Print(ostream &);
286         void PrintByName(ostream &);
287         ElValue* GetElementByNumber(guint32 group, guint32 element);
288         ElValue* GetElementByName(string);
289         string GetElValueByNumber(guint32 group, guint32 element);
290         string GetElValueByName(string);
291         TagElValueHT & GetTagHt(void);
292 };
293
294
295 //
296 // ---------------------------------------------------- gdcmHeader
297 //
298 //      C'est le Dicom Header d'une image donnée
299 //      (tous les elements Dicom qui la composent
300 //      + des info 'de service')
301 //
302
303 ////////////////////////////////////////////////////////////////////////////
304 // The typical usage of instances of class gdcmHeader is to classify a set of
305 // dicom files according to header information e.g. to create a file hierarchy
306 // reflecting the Patient/Study/Serie informations, or extracting a given
307 // SerieId. Accesing the content (image[s] or volume[s]) is beyond the
308 // functionality of this class and belong to gdmcFile (see below).
309 // Notes:
310 // * the various entries of the explicit value representation (VR) shall
311 //   be managed within a dictionary which is shared by all gdcmHeader instances
312 // * the gdcmHeader::Set*Tag* family members cannot be defined as protected
313 //   (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
314  
315
316 typedef string VRKey;
317 typedef string VRAtr;
318 typedef map<TagKey, VRAtr> VRHT;    // Value Representation Hash Table
319                 // Cette Table de Hachage ne devrait servir qu'a determiner
320                 // si deux caractères correspondent à une VR existante ?        
321
322 class GDCM_EXPORT gdcmHeader {
323         void SkipBytes(guint32);
324 private:
325         static VRHT *dicom_vr;
326         // Dictionaries of data elements:
327         static gdcmDictSet* Dicts;  // global dictionary container
328         gdcmDict* RefPubDict;       // public dictionary
329         gdcmDict* RefShaDict;       // shadow dictionary (optional)
330         // Parsed element values:
331         ElValSet PubElVals;         // parsed with Public Dictionary
332         ElValSet ShaElVals;         // parsed with Shadow Dictionary
333         string filename;            // refering underlying file
334         FILE * fp;
335         // The tag Image Location ((0028,0200) containing the address of
336         // the pixels) is not allways present. When we store this information
337         // FIXME
338         // outside of the elements:
339         guint16 grPixel;
340         guint16 numPixel;
341         
342         // Swap code (little, big, big-bad endian): this code is not fixed
343         // during parsing.FIXME sw should be an enum e.g.
344         //enum EndianType {
345                 //LittleEndian, 
346                 //BadLittleEndian,
347                 //BigEndian, 
348                 //BadBigEndian};
349         int sw;
350
351         // Only the elements whose size are below this bound shall be loaded.
352         // By default, this upper bound is limited to 1024 (which looks reasonable
353         // when one considers the definition of the various VR contents).
354         guint32 MaxSizeLoadElementValue;
355
356         guint16 ReadInt16(void);
357         guint32 ReadInt32(void);
358         guint16 SwapShort(guint16);
359         guint32 SwapLong(guint32);
360         void Initialise(void);
361         void CheckSwap(void);
362         void FindLength(ElValue *);
363         guint32 FindLengthOB(void);
364         void FindVR(ElValue *);
365         void LoadElementValue(ElValue *);
366         void LoadElementValueSafe(ElValue *);
367         void SkipElementValue(ElValue *);
368         void InitVRDict(void);
369         void SwitchSwapToBigEndian(void);
370         void FixFoundLength(ElValue*, guint32);
371         bool IsAnInteger(ElValue *);
372         bool IsBigEndianTransferSyntax(void);
373         void SetMaxSizeLoadElementValue(long);
374         ElValue       * ReadNextElement(void);
375         gdcmDictEntry * IsInDicts(guint32, guint32);
376 protected:
377         enum FileType {
378                 Unknown = 0,
379                 TrueDicom,
380                 ExplicitVR,
381                 ImplicitVR,
382                 ACR,
383                 ACR_LIBIDO};  // CLEANME
384         FileType filetype;
385         int write(ostream&);   
386         int anonymize(ostream&);  // FIXME : anonymize should be a friend ?
387 public:
388         void LoadElements(void);
389         virtual void ParseHeader(void);
390         gdcmHeader(const char* filename);
391         virtual ~gdcmHeader();
392         
393         size_t GetPixelOffset(void);
394         void   GetPixels(size_t, void *);
395         int    GetSwapCode(void) { return sw; }
396
397         // TODO Swig int SetPubDict(string filename);
398         // When some proprietary shadow groups are disclosed, we can set
399         // up an additional specific dictionary to access extra information.
400         // TODO Swig int SetShaDict(string filename);
401
402         // Retrieve all potentially available tag [tag = (group, element)] names
403         // from the standard (or public) dictionary. Typical usage: enable the
404         // user of a GUI based interface to select his favorite fields for sorting
405         // or selection.
406         list<string> * GetPubTagNames(void);
407         map<string, list<string> > * GetPubTagNamesByCategory(void);
408         // Get the element values themselves:
409         
410         string GetPubElValByName(string TagName);
411         string GetPubElValByNumber(guint16 group, guint16 element);
412
413         // Getting the element value representation (VR) might be needed by caller
414         // to convert the string typed content to caller's native type (think
415         // of C/C++ vs Python).
416
417         string GetPubElValRepByName(string TagName);
418         string GetPubElValRepByNumber(guint16 group, guint16 element);
419
420         TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
421         void   PrintPubElVal(ostream & os = cout);
422         void   PrintPubDict(ostream &);
423           
424         // Same thing with the shadow :
425         // TODO Swig string* GetShaTagNames(); 
426         string GetShaElValByName(string TagName);
427         string GetShaElValByNumber(guint16 group, guint16 element);
428         string GetShaElValRepByName(string TagName);
429         string GetShaElValRepByNumber(guint16 group, guint16 element);
430
431         // Wrappers of the above (public is privileged over shadow) to avoid
432         // bugging the caller with knowing if ElVal is from the public or shadow
433         // dictionary.
434         string GetElValByName(string TagName);
435         string GetElValByNumber(guint16 group, guint16 element);
436         string GetElValRepByName(string TagName);
437         string GetElValRepByNumber(guint16 group, guint16 element);
438
439         // TODO Swig int SetPubElValByName(string content, string TagName);
440         // TODO Swig int SetPubElValByNumber(string content, guint16 group, guint16 element);
441         // TODO Swig int SetShaElValByName(string content, string ShadowTagName);
442         // TODO Swig int SetShaElValByNumber(string content, guint16 group, guint16 element);
443
444         // TODO Swig int GetSwapCode();
445 };
446
447 //
448 // ---------------------------------------------------- gdcmFile
449 //
450 //      un fichier EST_UNE entete, ou A_UNE entete ?
451 //
452 //
453
454
455 ////////////////////////////////////////////////////////////////////////////
456 // In addition to Dicom header exploration, this class is designed
457 // for accessing the image/volume content. One can also use it to
458 // write Dicom files.
459 ////// QUESTION: this looks still like an open question wether the
460 //////           relationship between a gdcmFile and gdcmHeader is of
461 //////           type IS_A or HAS_A !
462
463 class GDCM_EXPORT gdcmFile: gdcmHeader
464 {
465 private:
466         void* Data;
467         int Parsed;          // weather allready parsed
468         string OrigFileName; // To avoid file overwrite
469 public:
470         // Constructor dedicated to writing a new DICOMV3 part10 compliant
471         // file (see SetFileName, SetDcmTag and Write)
472         // TODO Swig gdcmFile();
473         // Opens (in read only and when possible) an existing file and checks
474         // for DICOM compliance. Returns NULL on failure.
475         // Note: the in-memory representation of all available tags found in
476         //    the DICOM header is post-poned to first header information access.
477         //    This avoid a double parsing of public part of the header when
478         //    one sets an a posteriori shadow dictionary (efficiency can be
479         //    seen as a side effect).
480         
481         gdcmFile(string & filename);
482         
483         // For promotion (performs a deepcopy of pointed header object)
484         // TODO Swig gdcmFile(gdcmHeader* header);
485         // TODO Swig ~gdcmFile();
486
487         // On writing purposes. When instance was created through
488         // gdcmFile(string filename) then the filename argument MUST be different
489         // from the constructor's one (no overwriting aloud).
490         // TODO Swig int SetFileName(string filename);
491
492         // Allocates necessary memory, copies the data (image[s]/volume[s]) to
493         // newly allocated zone and return a pointer to it:
494         // TODO Swig void * GetImageData();
495         
496         // Returns size (in bytes) of required memory to contain data
497         // represented in this file.
498         // TODO Swig size_t GetImageDataSize();
499         
500         // Copies (at most MaxSize bytes) of data to caller's memory space.
501         // Returns an error code on failure (if MaxSize is not big enough)
502         // TODO Swig int PutImageDataHere(void* destination, size_t MaxSize );
503         
504         // Allocates ExpectedSize bytes of memory at this->Data and copies the
505         // pointed data to it.
506         // TODO Swig int SetImageData(void * Data, size_t ExpectedSize);
507         // Push to disk.
508         // TODO Swig int Write();
509 };
510
511 //
512 // ---------------------------------------------------- gdcmSerie
513 //
514 //      une serie EST_UN fichier ????
515 //
516 //
517
518 //class gdcmSerie : gdcmFile;
519
520 //
521 // ---------------------------------------------------- gdcmMultiFrame
522 //
523 //      un fichierMultiFrame EST_UN fichier 
524 //
525 //
526
527 //class gdcmMultiFrame : gdcmFile;
528
529