]> Creatis software - gdcm.git/blob - src/gdcm.h
Dernier commit avant supsension provisoire des travaux DCMLib.
[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 which 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 2001)
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 #ifdef __GNUC__
56 #include <stdint.h>
57 #define guint16 uint16_t
58 #define guint32 uint32_t
59 #endif
60
61 #ifdef _MSC_VER 
62 typedef  unsigned short guint16;
63 typedef  unsigned int   guint32;
64 #endif
65
66 #ifdef _MSC_VER
67 #define GDCM_EXPORT __declspec( dllexport )
68 #else
69 #define GDCM_EXPORT
70 #endif
71
72 ////////////////////////////////////////////////////////////////////////////
73 // Tag based hash tables.
74 // We shall use as keys the strings (as the C++ type) obtained by
75 // concatenating the group value and the element value (both of type
76 // unsigned 16 bit integers in Dicom) expressed in hexadecimal.
77 // Example: consider the tag given as (group, element) = (0x0010, 0x0010).
78 // Then the corresponding TagKey shall be the string 0010|0010 (where
79 // the | (pipe symbol) acts as a separator). Refer to 
80 // gdcmDictEntry::TranslateToKey for this conversion function.
81
82 typedef string TagKey;
83 typedef string TagName;
84
85 class GDCM_EXPORT gdcmDictEntry {
86 private:
87         guint16 group;    // e.g. 0x0010
88         guint16 element;  // e.g. 0x0103
89         string  vr;       // Value Representation i.e. some clue about the nature
90                           // of the data represented e.g. "FD" short for
91                           // "Floating Point Double"
92         // CLEANME: find the official dicom name for this field !
93         string  fourth;   // Fourth field containing some semantics.
94         string  name;     // e.g. "Patient_Name"
95         TagKey  key;      // Redundant with (group, element) but we add it
96                           // on efficiency purposes.
97         // DCMTK has many fields for handling a DictEntry (see below). What are the
98         // relevant ones for gdcmlib ?
99         //      struct DBI_SimpleEntry {
100         //         Uint16 upperGroup;
101         //         Uint16 upperElement;
102         //         DcmEVR evr;
103         //         const char* tagName;
104         //         int vmMin;
105         //         int vmMax;
106         //         const char* standardVersion;
107         //         DcmDictRangeRestriction groupRestriction;
108         //         DcmDictRangeRestriction elementRestriction;
109         //       };
110 public:
111         gdcmDictEntry(guint16 group, 
112                       guint16 element,
113                       string vr     = "Unknown",
114                       string fourth = "Unknown",
115                       string name   = "Unknown");
116         // fabrique une 'clé' par concaténation du numGroupe et du numElement
117         static TagKey TranslateToKey(guint16 group, guint16 element);
118         
119         guint16 GetGroup(void)  { return group; };
120         guint16 GetElement(void){return element;};
121         string  GetVR(void)     {return vr;     };
122         void    SetVR(string);
123         void    SetKey(string k){ key = k;     }
124         bool    IsVrUnknown(void);
125         string  GetFourth(void) {return fourth;};
126         string  GetName(void)   {return name;  };
127         string  GetKey(void)    {return key;   };
128 };
129   
130 ////////////////////////////////////////////////////////////////////////////
131 // A single DICOM dictionary i.e. a container for a collection of dictionary
132 // entries. There should be a single public dictionary (THE dictionary of
133 // the actual DICOM v3) but as many shadow dictionaries as imagers 
134 // combined with all software versions...
135
136 typedef map<TagKey,  gdcmDictEntry*> TagKeyHT;
137 typedef map<TagName, gdcmDictEntry*> TagNameHT;
138
139 class GDCM_EXPORT gdcmDict {
140         string name;
141         string filename;
142         TagKeyHT  KeyHt;                // Both accesses with a TagKey or with a
143         TagNameHT NameHt;               // TagName are required.
144 public:
145         gdcmDict(const char* FileName);   // Reads Dict from ascii file
146         int AddNewEntry (gdcmDictEntry* NewEntry);
147         int ReplaceEntry(gdcmDictEntry* NewEntry);
148         int RemoveEntry (TagKey key);
149         int RemoveEntry (guint16 group, guint16 element);
150         gdcmDictEntry * GetTagByKey(guint16 group, guint16 element);
151         gdcmDictEntry * GetTagByName(TagName name);
152         void Print(ostream&);
153         void PrintByKey(ostream&);
154         void PrintByName(ostream&);
155         TagKeyHT & GetEntries(void) { return KeyHt; }
156 };
157
158
159 ////////////////////////////////////////////////////////////////////////////
160 // Container for managing a set of loaded dictionaries. Sharing dictionaries
161 // should avoid :
162 // * reloading an allready loaded dictionary,
163 // * having many in memory representations of the same dictionary.
164
165 typedef string DictKey;
166 typedef map<DictKey, gdcmDict*> DictSetHT;
167
168 class GDCM_EXPORT gdcmDictSet {
169 private:
170         string DictPath;      // Directory path to dictionaries
171         DictSetHT dicts;
172         int AppendDict(gdcmDict* NewDict);
173         int LoadDictFromFile(string filename, DictKey);
174         void SetDictPath(void);
175 public:
176         gdcmDictSet(void);    // loads THE DICOM v3 dictionary
177         // TODO Swig int LoadDictFromFile(string filename);
178    // QUESTION: the following function might not be thread safe !? Maybe
179    //           we need some mutex here, to avoid concurent creation of
180    //           the same dictionary !?!?!
181         // TODO Swig int LoadDictFromName(string filename);
182         // TODO Swig int LoadAllDictFromDirectory(string DirectoryName);
183         // TODO Swig string* GetAllDictNames();
184         //
185         // Question : ne faudra-t-il pas mettre LE dictionnaire DICOM dans un Directory
186         // et les eventuels 'dictionnaires prives' dans un autre?
187         // (pour eviter a un utilisateur mal dégourdi de tout saccager ?)
188         //
189         int LoadDicomV3Dict(void);
190         void Print(ostream&);
191         gdcmDict* GetDict(DictKey DictName);
192         gdcmDict* GetDefaultPublicDict(void);
193 };
194
195 ///////////////////////////////////////////////////////////////////////////
196 // The dicom header of a Dicom file contains a set of such ELement VALUES
197 // (when successfuly parsed against a given Dicom dictionary)
198 class GDCM_EXPORT ElValue {
199 private:
200         gdcmDictEntry *entry;
201         guint32 LgrElem;
202         bool ImplicitVr;       // Even when reading explicit vr files, some
203                                // elements happen to be implicit. Flag them here
204                                // since we can't use the entry->vr without breaking
205                                // the underlying dictionary.
206 public:
207         string  value;
208         size_t Offset;     // Offset from the begining of file for direct user access
209         
210         ElValue(gdcmDictEntry*);
211         void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
212         bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
213         void SetImplicitVr(void) { ImplicitVr = true; };
214         bool  IsImplicitVr(void) { return ImplicitVr; };
215         
216         guint16 GetGroup(void)   { return entry->GetGroup();  };
217         guint16 GetElement(void) { return entry->GetElement();};
218         string  GetKey(void)     { return entry->GetKey();    };
219         string  GetName(void)    { return entry->GetName();   };
220         string  GetVR(void)      { return entry->GetVR();     };
221         void    SetVR(string v)  { entry->SetVR(v);           }; 
222         void SetLength(guint32 l){ LgrElem = l;               };
223         guint32 GetLength(void)  { return LgrElem;            };
224         
225         // Question : SetLength est public 
226         // (sinon, on ne pourrait pas l'appeler dans ElValSet)
227         // alors que *personne* ne devrait s'en servir !
228         // c'est *forcément* la lgr de la string 'value', non?
229
230         void SetValue(string val){ value = val; };
231         string  GetValue(void)   { return value;};
232
233         void SetOffset(size_t of){ Offset = of; };
234         size_t  GetOffset(void)  { return Offset;};
235         // Question : SetOffset est public ...
236         // Quel utilisateur serait ammené à modifier l'Offset ?
237 };
238
239
240 ////////////////////////////////////////////////////////////////////////////
241 // Container for a set of successfully parsed ElValues.
242 typedef map<TagKey, ElValue*> TagElValueHT;
243 typedef map<string, ElValue*> TagElValueNameHT;
244
245 class GDCM_EXPORT ElValSet {
246         TagElValueHT tagHt;             // Both accesses with a TagKey or with a
247         TagElValueNameHT NameHt;        // the DictEntry.Name are required.
248 public: 
249         void Add(ElValue*);             
250         void Print(ostream &);
251         void PrintByName(ostream &);
252         int  Write(FILE *fp);
253         ElValue* GetElementByNumber(guint32 group, guint32 element);
254         ElValue* GetElementByName  (string);
255         string   GetElValueByNumber(guint32 group, guint32 element);
256         string   GetElValueByName  (string);
257         
258         TagElValueHT & GetTagHt(void);  
259         
260         int SetElValueByNumber(string content, guint32 group, guint32 element);
261         int SetElValueByName  (string content, string TagName);
262         
263         int SetElValueLengthByNumber(guint32 l, guint32 group, guint32 element);
264         int SetElValueLengthByName  (guint32 l, string TagName);
265
266 };
267
268 ////////////////////////////////////////////////////////////////////////////
269 // The purpous of an instance of gdcmHeader is to act as a container of
270 // all the elements and their corresponding values (and additionaly the
271 // corresponding DICOM dictionary entry) of the header of a DICOM file.
272 //
273 // The typical usage of instances of class gdcmHeader is to classify a set of
274 // dicom files according to header information e.g. to create a file hierarchy
275 // reflecting the Patient/Study/Serie informations, or extracting a given
276 // SerieId. Accesing the content (image[s] or volume[s]) is beyond the
277 // functionality of this class and belong to gdmcFile (see below).
278 // Notes:
279 // * the various entries of the explicit value representation (VR) shall
280 //   be managed within a dictionary which is shared by all gdcmHeader instances
281 // * the gdcmHeader::Set*Tag* family members cannot be defined as protected
282 //   (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
283
284 typedef string VRKey;
285 typedef string VRAtr;
286 typedef map<VRKey, VRAtr> VRHT;    // Value Representation Hash Table
287
288 class GDCM_EXPORT gdcmHeader {
289         void SkipBytes(guint32);
290 private:
291         static VRHT *dicom_vr;
292         // Dictionaries of data elements:
293
294         static gdcmDictSet* Dicts;  // global dictionary container
295         gdcmDict* RefPubDict;       // public dictionary
296         gdcmDict* RefShaDict;       // shadow dictionary (optional)
297         // Parsed element values:
298         ElValSet PubElVals;         // parsed with Public Dictionary
299         ElValSet ShaElVals;         // parsed with Shadow Dictionary
300         string filename;            // refering underlying file
301         FILE * fp;
302         guint16 grPixel;
303         guint16 numPixel;
304         // Ne faudrait-il pas une indication sur la presence ou non
305         // du 'groupe des pixels' dans l'entete?
306         // (voir pb du DICOMDIR)
307         
308         // Swap code (little, big, bad-big, bad-little endian): this code is not fixed
309         // during parsing.FIXME sw should be an enum e.g.
310         //enum EndianType {
311                 //LittleEndian, 
312                 //BadLittleEndian,
313                 //BigEndian, 
314                 //BadBigEndian};
315         int sw;
316
317         // Only the elements whose size is below this bound will be loaded.
318         // By default, this upper bound is limited to 1024 (which looks reasonable
319         // when one considers the definition of the various VR contents).
320         guint32 MaxSizeLoadElementValue;
321
322         guint16 ReadInt16(void);
323         guint32 ReadInt32(void);
324         guint16 SwapShort(guint16);
325         guint32 SwapLong(guint32);
326         guint32 FindLengthOB(void);
327         void Initialise(void);
328         void CheckSwap(void);
329         void InitVRDict(void);
330         void SwitchSwapToBigEndian(void);
331         void AddAndDefaultElements(void);
332         void SetMaxSizeLoadElementValue(long);
333
334         gdcmDictEntry * GetDictEntryByKey(guint16, guint16);
335         gdcmDictEntry * GetDictEntryByName(string name);
336
337         // ElValue related utilities
338         ElValue * ReadNextElement(void);
339         ElValue * NewElValueByKey(guint16 group, guint16 element);
340         ElValue * NewElValueByName(string name);
341         void FindLength(ElValue *);
342         void FindVR(ElValue *);
343         void LoadElementValue(ElValue *);
344         void LoadElementValueSafe(ElValue *);
345         void SkipElementValue(ElValue *);
346         void FixFoundLength(ElValue*, guint32);
347         bool IsAnInteger(ElValue *);
348         
349         bool IsImplicitVRLittleEndianTransferSyntax(void);
350         bool IsExplicitVRLittleEndianTransferSyntax(void);
351         bool IsDeflatedExplicitVRLittleEndianTransferSyntax(void);
352         bool IsExplicitVRBigEndianTransferSyntax(void);
353         bool IsJPEGBaseLineProcess1TransferSyntax(void);
354         bool IsJPEGExtendedProcess2_4TransferSyntax(void);      
355         bool IsJPEGExtendedProcess3_5TransferSyntax(void);
356         bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void);     
357                 
358 protected:
359         enum FileType {
360                 Unknown = 0,
361                 TrueDicom,
362                 ExplicitVR,
363                 ImplicitVR,
364                 ACR,
365                 ACR_LIBIDO};  // CLEANME
366         FileType filetype;
367         int write(ostream&);   
368         int anonymize(ostream&);  // FIXME : anonymize should be a friend ?
369 public:
370         void LoadElements(void);
371         virtual void ParseHeader(void);
372         gdcmHeader(const char* filename);
373         virtual ~gdcmHeader();
374         
375         size_t GetPixelOffset(void);
376         void   GetPixels(size_t, void *);
377         int    GetSwapCode(void) { return sw; }
378
379         // TODO Swig int SetPubDict(string filename);
380         // When some proprietary shadow groups are disclosed, we can set up
381         // an additional specific dictionary to access extra information.
382         // TODO Swig int SetShaDict(string filename);
383
384         // Retrieve all potentially available tag [tag = (group, element)] names
385         // from the standard (or public) dictionary. Typical usage : enable the
386         // user of a GUI based interface to select his favorite fields for sorting
387         // or selecting.
388         list<string> * GetPubTagNames(void);
389         map<string, list<string> > * GetPubTagNamesByCategory(void);
390         // Get the element values themselves:
391         
392         string GetPubElValByName(string TagName);
393         string GetPubElValByNumber(guint16 group, guint16 element);
394
395         // Getting the element value representation (VR) might be needed by caller
396         // to convert the string typed content to caller's native type 
397         // (think of C/C++ vs Python).
398
399         string GetPubElValRepByName(string TagName);
400         string GetPubElValRepByNumber(guint16 group, guint16 element);
401
402         TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
403         void   PrintPubElVal(ostream & os = cout);
404         void   PrintPubDict(ostream &);
405           
406         // Same thing with the shadow :
407         // TODO Swig string* GetShaTagNames(); 
408         string GetShaElValByName(string TagName);
409         string GetShaElValByNumber(guint16 group, guint16 element);
410         string GetShaElValRepByName(string TagName);
411         string GetShaElValRepByNumber(guint16 group, guint16 element);
412
413         // Wrappers of the above (public is privileged over shadow) to avoid
414         // bugging the caller with knowing if ElVal is from the public or shadow
415         // dictionary.
416         string GetElValByName(string TagName);
417         string GetElValByNumber(guint16 group, guint16 element);
418         string GetElValRepByName(string TagName);
419         string GetElValRepByNumber(guint16 group, guint16 element);
420
421         int SetPubElValByName(string content, string TagName);
422         int SetPubElValByNumber(string content, guint16 group, guint16 element);
423         int SetShaElValByName(string content, string ShadowTagName);
424         int SetShaElValByNumber(string content, guint16 group, guint16 element);
425
426         ElValSet GetPubElVals() { return(PubElVals); }
427 };
428
429 //
430 // ---------------------------------------------------- gdcmFile
431 //
432 //      un fichier EST_UNE entete, ou A_UNE entete ?
433 // 
434 //      On dit 'EST_UNE' ...
435
436
437 ////////////////////////////////////////////////////////////////////////////
438 // In addition to Dicom header exploration, this class is designed
439 // for accessing the image/volume content. One can also use it to
440 // write Dicom files.
441 ////// QUESTION: this looks still like an open question whether the
442 //////           relationship between a gdcmFile and gdcmHeader is of
443 //////           type IS_A or HAS_A !
444
445 class GDCM_EXPORT gdcmFile: public gdcmHeader
446 {
447 private:
448         // QUESTION :
449         // Data pointe sur quoi?
450         // sur les Pixels lus?
451         // --> j'ajoute un champ public : Pixels
452         // (il faudra que l'utilisateur puisse modifier les pixels ?)
453         
454         void* Data;
455         int Parsed;          // weather allready parsed
456         string OrigFileName; // To avoid file overwrite
457 public:
458         // je ne suis pas sur d'avoir compris *où* il serait légitime de ranger ca.
459         // on pourra tjs le deplacer, et mettre des accesseurs
460         void * Pixels;
461         size_t lgrTotale;
462         
463         // Constructor dedicated to writing a new DICOMV3 part10 compliant
464         // file (see SetFileName, SetDcmTag and Write)
465         // TODO Swig gdcmFile();
466         // Opens (in read only and when possible) an existing file and checks
467         // for DICOM compliance. Returns NULL on failure.
468         // Note: the in-memory representation of all available tags found in
469         //    the DICOM header is post-poned to first header information access.
470         //    This avoid a double parsing of public part of the header when
471         //    one sets an a posteriori shadow dictionary (efficiency can be
472         //    seen as a side effect).
473         
474         gdcmFile(string & filename);
475         
476         // For promotion (performs a deepcopy of pointed header object)
477         // TODO Swig gdcmFile(gdcmHeader* header);
478         // TODO Swig ~gdcmFile();
479
480         // On writing purposes. When instance was created through
481         // gdcmFile(string filename) then the filename argument MUST be different
482         // from the constructor's one (no overwriting allowed).
483         // TODO Swig int SetFileName(string filename);
484
485         // Allocates necessary memory, copies the data (image[s]/volume[s]) to
486         // newly allocated zone and return a pointer to it:
487         
488          void * GetImageData();
489         
490         // Returns size (in bytes) of required memory to contain data
491         // represented in this file.
492         
493         size_t GetImageDataSize();
494         
495         // Copies (at most MaxSize bytes) of data to caller's memory space.
496         // Returns an error code on failure (if MaxSize is not big enough)
497         
498         int GetImageDataIntoVector(void* destination, size_t MaxSize );
499         
500         // Question :
501         //
502         //      GetImageData et GetImageDataIntoVector
503         // Get et Put pour 2 fonctions qui font presque la meme chose :-(
504         //
505         
506         // Allocates ExpectedSize bytes of memory at this->Data and copies the
507         // pointed data to it.
508         
509         // Question :
510         // Pourquoi dupliquer les pixels, alors qu'on les a deja en mémoire,
511         // et que Data (dans le gdcmHeader) est un pointeur ?
512         
513         // TODO Swig int SetImageData(void * Data, size_t ExpectedSize);
514         
515         // Push to disk.
516         // A NE PAS OUBLIER : que fait-on en cas de Transfert Syntax (dans l'entete)
517         // incohérente avec l'ordre des octets en mémoire  
518         // TODO Swig int Write();
519         
520         // Ecrit sur disque les pixels d'UNE image
521         // Aucun test n'est fait sur l'"Endiannerie" du processeur.
522         // Ca sera à l'utilisateur d'appeler son Reader correctement
523                 
524         int WriteRawData (string nomFichier);
525         int WriteDcm     (string nomFichier);
526 };
527
528 //
529 // ---------------------------------------------------- gdcmSerie
530 //
531 //      une serie EST_UN fichier ????
532 //
533 //
534
535 //class gdcmSerie : gdcmFile;
536
537 //
538 // ---------------------------------------------------- gdcmMultiFrame
539 //
540 //      un fichierMultiFrame EST_UN fichier 
541 //
542 //
543
544 //class gdcmMultiFrame : gdcmFile;
545
546