]> Creatis software - gdcm.git/blob - src/gdcm.h
gcdmPutDataHere
[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 // QUESTION:
231 //
232 // Ne faudrait-il pas trouver un autre nom, qui preterait moins à confusion?
233 // ElValue n'EST PAS la 'valeur d'un Element', mais la reunion d'infos
234 // trouvees dans l'Entete" du fichier ET dans le Dictionnaire
235 //
236
237 // The dicom header of a Dicom file contains a set of such ELement VALUES
238 // (when successfuly parsed against a given Dicom dictionary)
239
240 class GDCM_EXPORT ElValue {
241 private:
242         gdcmDictEntry *entry;
243         guint32 LgrElem;
244         bool ImplicitVr;       // Even when reading explicit vr files, some
245                                // elements happen to be implicit. Flag them here
246                                // since we can't use the entry->vr without breaking
247                                // the underlying dictionary.
248         // Might prove of some interest (see _ID_DCM_ELEM)
249         // int Swap;
250 public:
251         string  value;     // used to be char * valeurElem
252         size_t Offset;     // Offset from the begining of file for direct user access
253         ElValue(gdcmDictEntry*);
254         void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
255
256         bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
257         void SetLength(guint32 l){ LgrElem = l; };
258         void SetValue(string val){ value = val; };
259         void SetOffset(size_t of){ Offset = of; };
260         void SetImplicitVr(void) { ImplicitVr = true; };
261         bool  IsImplicitVr(void) { return ImplicitVr; };
262         void    SetVR(string);
263         string  GetVR(void);
264         string  GetValue(void)   { return value; };
265         guint32 GetLength(void)  { return LgrElem; };
266         size_t  GetOffset(void)  { return Offset; };
267         guint16 GetGroup(void)   { return entry->GetGroup(); };
268         guint16 GetElement(void) { return entry->GetElement(); };
269         string  GetKey(void)     { return entry->GetKey(); };
270         string  GetName(void)    { return entry->GetName();};
271 };
272
273
274 //
275 // ---------------------------------------------------- ElValSet
276 //
277 //      ... un ensemble d'Elements Dicom 
278 //
279
280 ////////////////////////////////////////////////////////////////////////////
281 // Container for a set of successfully parsed ElValues.
282 typedef map<TagKey, ElValue*> TagElValueHT;
283 typedef map<string, ElValue*> TagElValueNameHT;
284
285 class GDCM_EXPORT ElValSet {
286                 // We need both accesses with a TagKey and the Dictentry.Name
287         TagElValueHT tagHt;
288         TagElValueNameHT NameHt;
289 public:
290         void Add(ElValue*);
291         void Print(ostream &);
292         void PrintByName(ostream &);
293         ElValue* GetElementByNumber(guint32 group, guint32 element);
294         ElValue* GetElementByName  (string);
295         string   GetElValueByNumber(guint32 group, guint32 element);
296         string   GetElValueByName  (string);
297         TagElValueHT & GetTagHt(void);
298 };
299
300
301 //
302 // ---------------------------------------------------- gdcmHeader
303 //
304 //      C'est le Dicom Header d'une image donnée
305 //      (tous les elements Dicom qui la composent
306 //      + des info 'de service')
307 //
308
309 ////////////////////////////////////////////////////////////////////////////
310 // The typical usage of instances of class gdcmHeader is to classify a set of
311 // dicom files according to header information e.g. to create a file hierarchy
312 // reflecting the Patient/Study/Serie informations, or extracting a given
313 // SerieId. Accesing the content (image[s] or volume[s]) is beyond the
314 // functionality of this class and belong to gdmcFile (see below).
315 // Notes:
316 // * the various entries of the explicit value representation (VR) shall
317 //   be managed within a dictionary which is shared by all gdcmHeader instances
318 // * the gdcmHeader::Set*Tag* family members cannot be defined as protected
319 //   (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
320  
321
322 typedef string VRKey;
323 typedef string VRAtr;
324 typedef map<TagKey, VRAtr> VRHT;    // Value Representation Hash Table
325                 // Cette Table de Hachage ne devrait servir qu'a determiner
326                 // si deux caractères correspondent à une VR existante ?        
327
328 class GDCM_EXPORT gdcmHeader {
329         void SkipBytes(guint32);
330 private:
331         static VRHT *dicom_vr;
332         // Dictionaries of data elements:
333         static gdcmDictSet* Dicts;  // global dictionary container
334         gdcmDict* RefPubDict;       // public dictionary
335         gdcmDict* RefShaDict;       // shadow dictionary (optional)
336         // Parsed element values:
337         ElValSet PubElVals;         // parsed with Public Dictionary
338         ElValSet ShaElVals;         // parsed with Shadow Dictionary
339         string filename;            // refering underlying file
340         FILE * fp;
341         // The tag Image Location ((0028,0200) containing the address of
342         // the pixels) is not allways present. When we store this information
343         // FIXME
344         // outside of the elements:
345         guint16 grPixel;
346         guint16 numPixel;
347         // Ne faudrait-il pas une indication sur la presence ou non
348         // du 'groupe des pixels' dans l'entete?
349         // (voir pb du DICOMDIR)
350         
351         // Swap code (little, big, big-bad endian): this code is not fixed
352         // during parsing.FIXME sw should be an enum e.g.
353         //enum EndianType {
354                 //LittleEndian, 
355                 //BadLittleEndian,
356                 //BigEndian, 
357                 //BadBigEndian};
358         int sw;
359
360         // Only the elements whose size are below this bound shall be loaded.
361         // By default, this upper bound is limited to 1024 (which looks reasonable
362         // when one considers the definition of the various VR contents).
363         guint32 MaxSizeLoadElementValue;
364
365         guint16 ReadInt16(void);
366         guint32 ReadInt32(void);
367         guint16 SwapShort(guint16);
368         guint32 SwapLong(guint32);
369         void Initialise(void);
370         void CheckSwap(void);
371         void FindLength(ElValue *);
372         guint32 FindLengthOB(void);
373         void FindVR(ElValue *);
374         void LoadElementValue(ElValue *);
375         void LoadElementValueSafe(ElValue *);
376         void SkipElementValue(ElValue *);
377         void InitVRDict(void);
378         void SwitchSwapToBigEndian(void);
379         void FixFoundLength(ElValue*, guint32);
380         bool IsAnInteger(ElValue *);
381         
382         bool IsImplicitVRLittleEndianTransferSyntax(void);
383         bool IsExplicitVRLittleEndianTransferSyntax(void);
384         bool IsDeflatedExplicitVRLittleEndianTransferSyntax(void);
385         bool IsExplicitVRBigEndianTransferSyntax(void);
386         bool IsJPEGBaseLineProcess1TransferSyntax(void);
387         bool IsJPEGExtendedProcess2_4TransferSyntax(void);      
388         bool IsJPEGExtendedProcess3_5TransferSyntax(void);
389         bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void);     
390 //
391 // Euhhhhhhh
392 // Il y en a encore DIX-SEPT, comme ça.
393 // Il faudrait trouver qq chose + rusé ...
394 //      
395         
396         
397         
398         void SetMaxSizeLoadElementValue(long);
399         ElValue       * ReadNextElement(void);
400         gdcmDictEntry * IsInDicts(guint32, guint32);
401 protected:
402         enum FileType {
403                 Unknown = 0,
404                 TrueDicom,
405                 ExplicitVR,
406                 ImplicitVR,
407                 ACR,
408                 ACR_LIBIDO};  // CLEANME
409         FileType filetype;
410         int write(ostream&);   
411         int anonymize(ostream&);  // FIXME : anonymize should be a friend ?
412 public:
413         void LoadElements(void);
414         virtual void ParseHeader(void);
415         gdcmHeader(const char* filename);
416         virtual ~gdcmHeader();
417         
418         size_t GetPixelOffset(void);
419         void   GetPixels(size_t, void *);
420         int    GetSwapCode(void) { return sw; }
421
422         // TODO Swig int SetPubDict(string filename);
423         // When some proprietary shadow groups are disclosed, we can set
424         // up an additional specific dictionary to access extra information.
425         // TODO Swig int SetShaDict(string filename);
426
427         // Retrieve all potentially available tag [tag = (group, element)] names
428         // from the standard (or public) dictionary. Typical usage: enable the
429         // user of a GUI based interface to select his favorite fields for sorting
430         // or selection.
431         list<string> * GetPubTagNames(void);
432         map<string, list<string> > * GetPubTagNamesByCategory(void);
433         // Get the element values themselves:
434         
435         string GetPubElValByName(string TagName);
436         string GetPubElValByNumber(guint16 group, guint16 element);
437
438         // Getting the element value representation (VR) might be needed by caller
439         // to convert the string typed content to caller's native type (think
440         // of C/C++ vs Python).
441
442         string GetPubElValRepByName(string TagName);
443         string GetPubElValRepByNumber(guint16 group, guint16 element);
444
445         TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
446         void   PrintPubElVal(ostream & os = cout);
447         void   PrintPubDict(ostream &);
448           
449         // Same thing with the shadow :
450         // TODO Swig string* GetShaTagNames(); 
451         string GetShaElValByName(string TagName);
452         string GetShaElValByNumber(guint16 group, guint16 element);
453         string GetShaElValRepByName(string TagName);
454         string GetShaElValRepByNumber(guint16 group, guint16 element);
455
456         // Wrappers of the above (public is privileged over shadow) to avoid
457         // bugging the caller with knowing if ElVal is from the public or shadow
458         // dictionary.
459         string GetElValByName(string TagName);
460         string GetElValByNumber(guint16 group, guint16 element);
461         string GetElValRepByName(string TagName);
462         string GetElValRepByNumber(guint16 group, guint16 element);
463
464         // TODO Swig int SetPubElValByName(string content, string TagName);
465         // TODO Swig int SetPubElValByNumber(string content, guint16 group, guint16 element);
466         // TODO Swig int SetShaElValByName(string content, string ShadowTagName);
467         // TODO Swig int SetShaElValByNumber(string content, guint16 group, guint16 element);
468
469         // TODO Swig int GetSwapCode();
470 };
471
472 //
473 // ---------------------------------------------------- gdcmFile
474 //
475 //      un fichier EST_UNE entete, ou A_UNE entete ?
476 //
477 //
478
479
480 ////////////////////////////////////////////////////////////////////////////
481 // In addition to Dicom header exploration, this class is designed
482 // for accessing the image/volume content. One can also use it to
483 // write Dicom files.
484 ////// QUESTION: this looks still like an open question wether the
485 //////           relationship between a gdcmFile and gdcmHeader is of
486 //////           type IS_A or HAS_A !
487
488 class GDCM_EXPORT gdcmFile: public gdcmHeader
489 {
490 private:
491         void* Data;
492         int Parsed;          // weather allready parsed
493         string OrigFileName; // To avoid file overwrite
494 public:
495         // Constructor dedicated to writing a new DICOMV3 part10 compliant
496         // file (see SetFileName, SetDcmTag and Write)
497         // TODO Swig gdcmFile();
498         // Opens (in read only and when possible) an existing file and checks
499         // for DICOM compliance. Returns NULL on failure.
500         // Note: the in-memory representation of all available tags found in
501         //    the DICOM header is post-poned to first header information access.
502         //    This avoid a double parsing of public part of the header when
503         //    one sets an a posteriori shadow dictionary (efficiency can be
504         //    seen as a side effect).
505         
506         gdcmFile(string & filename);
507         
508         // For promotion (performs a deepcopy of pointed header object)
509         // TODO Swig gdcmFile(gdcmHeader* header);
510         // TODO Swig ~gdcmFile();
511
512         // On writing purposes. When instance was created through
513         // gdcmFile(string filename) then the filename argument MUST be different
514         // from the constructor's one (no overwriting aloud).
515         // TODO Swig int SetFileName(string filename);
516
517         // Allocates necessary memory, copies the data (image[s]/volume[s]) to
518         // newly allocated zone and return a pointer to it:
519         
520          void * GetImageData();
521         
522         // Returns size (in bytes) of required memory to contain data
523         // represented in this file.
524         
525         size_t GetImageDataSize();
526         
527         // Copies (at most MaxSize bytes) of data to caller's memory space.
528         // Returns an error code on failure (if MaxSize is not big enough)
529         
530         int PutImageDataHere(void* destination, size_t MaxSize );
531         
532         // Allocates ExpectedSize bytes of memory at this->Data and copies the
533         // pointed data to it.
534         // TODO Swig int SetImageData(void * Data, size_t ExpectedSize);
535         // Push to disk.
536         // TODO Swig int Write();
537 };
538
539 //
540 // ---------------------------------------------------- gdcmSerie
541 //
542 //      une serie EST_UN fichier ????
543 //
544 //
545
546 //class gdcmSerie : gdcmFile;
547
548 //
549 // ---------------------------------------------------- gdcmMultiFrame
550 //
551 //      un fichierMultiFrame EST_UN fichier 
552 //
553 //
554
555 //class gdcmMultiFrame : gdcmFile;
556
557