]> Creatis software - gdcm.git/blobdiff - src/gdcm.h
Commenataires?
[gdcm.git] / src / gdcm.h
index 72a513a03fa47113ebd5485876ca15151e4eb256..c8bf4d046deaff68b79fe0ae34a51283a4748700 100644 (file)
@@ -1,9 +1,11 @@
+// gdcm.h
+
 // gdcmlib Intro:  
 // * gdcmlib is a library dedicated to reading and writing dicom files.
 // * LGPL for the license
 // * lightweigth as opposed to CTN or DCMTK wich come bundled which try
 //   to implement the full DICOM standard (networking...). gdcmlib concentrates
-//   on reading and 
+//   on reading and writing
 // * Formats: this lib should be able to read ACR-NEMA v1 and v2, Dicom v3 (as
 //   stated in part10). [cf dcmtk/dcmdata/docs/datadict.txt]
 // * Targeted plateforms: Un*xes and Win32/VC++6.0
 // the declaration once you provided the definition of the method...
 
 #include <string>
+#ifdef _MSC_VER
+using namespace std;  // string type lives in the std namespace on VC++
+#endif
+
 #include <iostream>
 #include <stddef.h>   // For size_t
-#include <glib.h>
-#include <stdio.h>    // CLEANME
-#include <map>        // The requirement for the hash table (or map) that
+#include <stdio.h>    // FIXME For FILE on GCC only
+#include <list>
+#include <map>
+
+                     // The requirement for the hash table (or map) that
                       // we shall use:
                       // 1/ First, next, last (iterators)
                       // 2/ should be sortable (i.e. sorted by TagKey). This
                       // 3/ Make sure we can setup some default size value,
                       //    which should be around 4500 entries which is the
                       //    average dictionary size (said JPR)
+                      //
+                      // En fait, je disais que dans LE Directory Dicom (dans son etat 2002)
+                      // il y a 1600 entrees.
+                      // Une valeur raisonable pour un  majorant du nombre d'entrees
+                      // dans une entete DICOM d'une image semble semble etre 300
+                      // Si on 'decortique' les elements SQ (ce qui ne semble pas etre fait pour le moment)
+                      // on risque en fait de depasser ... un nombre non previsible dans le cas d'une entree SQ
+                      // contenant lui même un tres grand nombre d'entrees ?!?)
+                      // Quant au nombre d'entrees dans un DICOMDIR, c'est encore pire : il n'est limité
+                      // que par la taille d'un CD-ROM (les DVD-ROM ne sont pas encore pris en compte)
+                      // On peut s'attendre a 30 entrees par fichier dicom présent sur le CD-ROM
+                      // Remarque : il faudra se pencher sur le pb de la creation du DICOMDIR lorsqu'on voudra 
+                      // exporter des images lisibles par les consoles cliniques 
+                      // et pas seulement importables dans e-film. 
 
-#ifdef _MSC_VER
-       using namespace std;  // string type lives in the std namespace on VC++
+
+#ifdef __GNUC__
+#include <stdint.h>
+#define guint16 uint16_t
+#define guint32 uint32_t
 #endif
+
+#ifdef _MSC_VER 
+typedef  unsigned short guint16;
+typedef  unsigned int guint32;
+#endif
+
 #ifdef _MSC_VER
 #define GDCM_EXPORT __declspec( dllexport )
 #else
 #define GDCM_EXPORT
 #endif
 
+
+//
+// ---------------------------------------------------- gdcmDictEntry
+//
+//     c'est une ligne du Dictionnaire Dicom
+//
+
+
+////////////////////////////////////////////////////////////////////////////
 // Tag based hash tables.
 // We shall use as keys the strings (as the C++ type) obtained by
 // concatenating the group value and the element value (both of type
 // Then the corresponding TagKey shall be the string 0010|0010 (where
 // the | (pipe symbol) acts as a separator). Refer to 
 // gdcmDictEntry::TranslateToKey for this conversion function.
+
 typedef string TagKey;
 
 class GDCM_EXPORT gdcmDictEntry {
 private:
        guint16 group;    // e.g. 0x0010
-       guint16 element;  // e.g. 0x0010
+       guint16 element;  // e.g. 0x0103
        string  vr;       // Value Representation i.e. some clue about the nature
                          // of the data represented e.g. "FD" short for
                          // "Floating Point Double"
-       // CLEAN ME: find the official dicom name for this field !
+       // CLEANME: find the official dicom name for this field !
        string  fourth;   // Fourth field containing some semantics.
        string  name;     // e.g. "Patient_Name"
-       TagKey  key;      // This is redundant zith (group, element) but we add
+       TagKey  key;      // Redundant with (group, element) but we add it
                          // on efficiency purposes.
        // DCMTK has many fields for handling a DictEntry (see below). What are the
        // relevant ones for gdcmlib ?
        //      struct DBI_SimpleEntry {
-       //         Uint16 group;
-       //         Uint16 element;
        //         Uint16 upperGroup;
        //         Uint16 upperElement;
        //         DcmEVR evr;
@@ -77,42 +116,82 @@ private:
        //         DcmDictRangeRestriction elementRestriction;
        //       };
 public:
-       //CLEANME gdcmDictEntry();
+       
+       // fabrique une ligne de Dictionnaire Dicom à partir des parametres en entrée
+
+
        gdcmDictEntry(guint16 group, guint16 element,
-                     string vr, string fourth, string name);
+                     string vr     = "Unknown",
+                     string fourth = "Unknown",
+                     string name   = "Unknown");
+                                         
+       // fabrique une 'clé' par concaténation du numGroupe et du numElement
+
        static TagKey TranslateToKey(guint16 group, guint16 element);
+       
        guint16 GetGroup(void)  { return group;};
        guint16 GetElement(void){return element;};
        string  GetVR(void)     {return vr; };
-       void    SetVR(string in){vr = in; };
+       void    SetVR(string);
+       bool    IsVrUnknown(void);
        string  GetFourth(void) {return fourth;};
        string  GetName(void)   {return name;};
        string  GetKey(void)    {return key;};
 };
   
-typedef map<TagKey, gdcmDictEntry*> TagHT;
+//
+// ---------------------------------------------------- gdcmDict
+// 
+//     c'est le Dictionnaire Dicom
+//
 
+  
+////////////////////////////////////////////////////////////////////////////
 // A single DICOM dictionary i.e. a container for a collection of dictionary
 // entries. There should be a single public dictionary (THE dictionary of
 // the actual DICOM v3) but as many shadow dictionaries as imagers 
 // combined with all software versions...
+
+typedef map<TagKey, gdcmDictEntry*> TagHT;
+       // Table de Hachage  (group,Elem) --> ligne du Dictionnaire Dicom
+
+typedef map<TagKey, gdcmDictEntry*> TagHT;
+
 class GDCM_EXPORT gdcmDict {
        string name;
        string filename;
        TagHT entries;
 public:
+       // rempli le Dictionnaire Dicom à partir d'un fichier texte
        gdcmDict(const char* FileName);   // Read Dict from disk
+       
        // TODO Swig int AppendEntry(gdcmDictEntry* NewEntry);
+       
+       // renvoie une ligne de Dictionnaire Dicom à partir de (numGroup, numElement)
        gdcmDictEntry * GetTag(guint32 group, guint32 element);
        void Print(ostream&);
+       TagHT & GetEntries(void) { return entries; }
 };
 
+
+//
+// ---------------------------------------------------- gdcmDictSet
+//
+//     Ensemble de Dictionnaires Dicom (le public + 'des' privés)
+//     Au cas ou l'on traiterait un jour les 'dictionnaires privés'
+//      - pratiquement un par constructeur, par machine, et par version du logiciel -
+//
+//
+
+////////////////////////////////////////////////////////////////////////////
 // Container for managing a set of loaded dictionaries. Sharing dictionaries
 // should avoid :
-// * reloading an allready loaded dictionary.
+// * reloading an allready loaded dictionary,
 // * having many in memory representations of the same dictionary.
+
 typedef string DictKey;
 typedef map<DictKey, gdcmDict*> DictSetHT;
+
 class GDCM_EXPORT gdcmDictSet {
 private:
        string DictPath;      // Directory path to dictionaries
@@ -123,37 +202,61 @@ private:
 public:
        gdcmDictSet(void);    // loads THE DICOM v3 dictionary
        // TODO Swig int LoadDictFromFile(string filename);
-///// QUESTION: the following function might not be thread safe !? Maybe
-/////           we need some mutex here, to avoid concurent creation of
-/////           the same dictionary !?!?!
+   // QUESTION: the following function might not be thread safe !? Maybe
+   //           we need some mutex here, to avoid concurent creation of
+   //           the same dictionary !?!?!
        // TODO Swig int LoadDictFromName(string filename);
        // TODO Swig int LoadAllDictFromDirectory(string DirectoryName);
        // TODO Swig string* GetAllDictNames();
+       //
+       // Question : ne faudra-t-il pas mettre LE dictionnaire DICOM dans un Directory
+       // et les eventuels 'dictionnaires prives' dans un autre?
+       //
        int LoadDicomV3Dict(void);
        void Print(ostream&);
        gdcmDict* GetDict(DictKey DictName);
        gdcmDict* GetDefaultPublicDict(void);
 };
 
+
+//
+// ---------------------------------------------------- ElValue
+//
+//     C'est un Element Dicom
+//     (ce qu'on a trouve dans l'entete de l'image
+//     + ce qu'on est allé chercher dans le Dictionnaire Dicom)
+//
+
+
 // The dicom header of a Dicom file contains a set of such ELement VALUES
 // (when successfuly parsed against a given Dicom dictionary)
+
 class GDCM_EXPORT ElValue {
 private:
        gdcmDictEntry *entry;
        guint32 LgrElem;
+       bool ImplicitVr;       // Even when reading explicit vr files, some
+                              // elements happen to be implicit. Flag them here
+                              // since we can't use the entry->vr without breaking
+                              // the underlying dictionary.
        // Might prove of some interest (see _ID_DCM_ELEM)
        // int Swap;
 public:
        string  value;     // used to be char * valeurElem
        size_t Offset;     // Offset from the begining of file for direct user access
        ElValue(gdcmDictEntry*);
-       void   SetVR(string);
-       string GetVR(void);
-       void SetLength(guint32 l){LgrElem = l; };
+       void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
+
+       bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
+       void SetLength(guint32 l){ LgrElem = l; };
        void SetValue(string val){ value = val; };
        void SetOffset(size_t of){ Offset = of; };
+       void SetImplicitVr(void) { ImplicitVr = true; };
+       bool  IsImplicitVr(void) { return ImplicitVr; };
+       void    SetVR(string);
+       string  GetVR(void);
        string  GetValue(void)   { return value; };
-       guint32 GetLength(void) { return LgrElem; };
+       guint32 GetLength(void)  { return LgrElem; };
        size_t  GetOffset(void)  { return Offset; };
        guint16 GetGroup(void)   { return entry->GetGroup(); };
        guint16 GetElement(void) { return entry->GetElement(); };
@@ -161,63 +264,95 @@ public:
        string  GetName(void)    { return entry->GetName();};
 };
 
+
+//
+// ---------------------------------------------------- ElValSet
+//
+//     ... un ensemble d'Elements Dicom 
+//
+
+////////////////////////////////////////////////////////////////////////////
+// Container for a set of succefully parsed ElValues.
 typedef map<TagKey, ElValue*> TagElValueHT;
 typedef map<string, ElValue*> TagElValueNameHT;
-// Container for a set of succefully parsed ElValues.
+
 class GDCM_EXPORT ElValSet {
-       // We need both accesses with a TagKey and the Dicentry.Name
+               // We need both accesses with a TagKey and the Dictentry.Name
        TagElValueHT tagHt;
        TagElValueNameHT NameHt;
 public:
        void Add(ElValue*);
        void Print(ostream &);
        void PrintByName(ostream &);
-       ElValue* GetElement(guint32 group, guint32 element);
-       string GetElValue(guint32 group, guint32 element);
-       string GetElValue(string);
+       ElValue* GetElementByNumber(guint32 group, guint32 element);
+       ElValue* GetElementByName(string);
+       string GetElValueByNumber(guint32 group, guint32 element);
+       string GetElValueByName(string);
        TagElValueHT & GetTagHt(void);
 };
 
-// The various entries of the explicit value representation (VR) shall
-// be managed within a dictionary. 
-typedef string VRKey;
-typedef string VRAtr;
-typedef map<TagKey, VRAtr> VRHT;    // Value Representation Hash Table
 
-// The typical usage of objects of this class is to classify a set of
-// dicom files according to header information e.g. to create a file hierachy
+//
+// ---------------------------------------------------- gdcmHeader
+//
+//     C'est le Dicom Header d'une image donnée
+//     (tous les elements Dicom qui la composent
+//     + des info 'de service')
+//
+
+////////////////////////////////////////////////////////////////////////////
+// The typical usage of instances of class gdcmHeader is to classify a set of
+// dicom files according to header information e.g. to create a file hierarchy
 // reflecting the Patient/Study/Serie informations, or extracting a given
 // SerieId. Accesing the content (image[s] or volume[s]) is beyond the
-// functionality of this class (see dmcFile below).
+// functionality of this class and belong to gdmcFile (see below).
 // Notes:
+// * the various entries of the explicit value representation (VR) shall
+//   be managed within a dictionary which is shared by all gdcmHeader instances
 // * the gdcmHeader::Set*Tag* family members cannot be defined as protected
 //   (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
-class GDCM_EXPORT gdcmHeader { 
-//FIXME sw should be qn EndianType !!!
-       //enum EndianType {
-               //LittleEndian, 
-               //BadLittleEndian,
-               //BigEndian, 
-               //BadBigEndian};
+
+typedef string VRKey;
+typedef string VRAtr;
+typedef map<TagKey, VRAtr> VRHT;    // Value Representation Hash Table
+               // Cette Table de Hachage ne devrait servir qu'a determiner
+               // si deux caractères correspondent à une VR existante ?        
+
+class GDCM_EXPORT gdcmHeader {
+       void SkipBytes(guint32);
 private:
-       // All instances share the same value representation dictionary
        static VRHT *dicom_vr;
-       static gdcmDictSet* Dicts;  // Global dictionary container
-       gdcmDict* RefPubDict;       // Public Dictionary
-       gdcmDict* RefShaDict;       // Shadow Dictionary (optional)
-       ElValSet PubElVals;     // Element Values parsed with Public Dictionary
-       ElValSet ShaElVals;     // Element Values parsed with Shadow Dictionary
-       // In order to inspect/navigate through the file
-       string filename;
+       // Dictionaries of data elements:
+       static gdcmDictSet* Dicts;  // global dictionary container
+       gdcmDict* RefPubDict;       // public dictionary
+       gdcmDict* RefShaDict;       // shadow dictionary (optional)
+       // Parsed element values:
+       ElValSet PubElVals;         // parsed with Public Dictionary
+       ElValSet ShaElVals;         // parsed with Shadow Dictionary
+       string filename;            // refering underlying file
        FILE * fp;
-       // The tag Image Location ((0028,0200) containing the adress of
+       // The tag Image Location ((0028,0200) containing the address of
        // the pixels) is not allways present. When we store this information
        // FIXME
        // outside of the elements:
        guint16 grPixel;
        guint16 numPixel;
+       
+       // Swap code (little, big, big-bad endian): this code is not fixed
+       // during parsing.FIXME sw should be an enum e.g.
+       //enum EndianType {
+               //LittleEndian, 
+               //BadLittleEndian,
+               //BigEndian, 
+               //BadBigEndian};
        int sw;
 
+       // Only the elements whose size are below this bound shall be loaded.
+       // By default, this upper bound is limited to 1024 (which looks reasonable
+       // when one considers the definition of the various VR contents).
+       guint32 MaxSizeLoadElementValue;
+
        guint16 ReadInt16(void);
        guint32 ReadInt32(void);
        guint16 SwapShort(guint16);
@@ -225,14 +360,19 @@ private:
        void Initialise(void);
        void CheckSwap(void);
        void FindLength(ElValue *);
+       guint32 FindLengthOB(void);
        void FindVR(ElValue *);
        void LoadElementValue(ElValue *);
+       void LoadElementValueSafe(ElValue *);
        void SkipElementValue(ElValue *);
        void InitVRDict(void);
-       bool IsAnInteger(guint16, guint16, string, guint32);
-       ElValue * ReadNextElement(void);
+       void SwitchSwapToBigEndian(void);
+       void FixFoundLength(ElValue*, guint32);
+       bool IsAnInteger(ElValue *);
+       bool IsBigEndianTransferSyntax(void);
+       void SetMaxSizeLoadElementValue(long);
+       ElValue       * ReadNextElement(void);
        gdcmDictEntry * IsInDicts(guint32, guint32);
-       size_t GetPixelOffset(void);
 protected:
        enum FileType {
                Unknown = 0,
@@ -240,54 +380,61 @@ protected:
                ExplicitVR,
                ImplicitVR,
                ACR,
-               ACR_LIBIDO};
+               ACR_LIBIDO};  // CLEANME
        FileType filetype;
-///// QUESTION: Maybe Print is a better name than write !?
        int write(ostream&);   
-///// QUESTION: Maybe anonymize should be a friend function !?!?
-/////           See below for an example of how anonymize might be implemented.
-       int anonymize(ostream&);
+       int anonymize(ostream&);  // FIXME : anonymize should be a friend ?
 public:
        void LoadElements(void);
        virtual void ParseHeader(void);
        gdcmHeader(const char* filename);
        virtual ~gdcmHeader();
+       
+       size_t GetPixelOffset(void);
+       void   GetPixels(size_t, void *);
+       int    GetSwapCode(void) { return sw; }
 
        // TODO Swig int SetPubDict(string filename);
-       // When some proprietary shadow groups are disclosed, whe can set
+       // When some proprietary shadow groups are disclosed, we can set
        // up an additional specific dictionary to access extra information.
        // TODO Swig int SetShaDict(string filename);
 
        // Retrieve all potentially available tag [tag = (group, element)] names
-       // from the standard (or public) dictionary (hence static). Typical usage:
-       // enable the user of a GUI based interface to select his favorite fields
-       // for sorting or selection.
-       // TODO Swig string* GetPubTagNames();
+       // from the standard (or public) dictionary. Typical usage: enable the
+       // user of a GUI based interface to select his favorite fields for sorting
+       // or selection.
+       list<string> * GetPubTagNames(void);
+       map<string, list<string> > * GetPubTagNamesByCategory(void);
        // Get the element values themselves:
+       
        string GetPubElValByName(string TagName);
        string GetPubElValByNumber(guint16 group, guint16 element);
-       // Get the element value representation: (VR) might be needed by caller
+
+       // Getting the element value representation (VR) might be needed by caller
        // to convert the string typed content to caller's native type (think
        // of C/C++ vs Python).
-       // TODO Swig string GetPubElValRepByName(string TagName);
-       // TODO Swig string GetPubElValRepByNumber(guint16 group, guint16 element);
+
+       string GetPubElValRepByName(string TagName);
+       string GetPubElValRepByNumber(guint16 group, guint16 element);
+
        TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
        void   PrintPubElVal(ostream & os = cout);
        void   PrintPubDict(ostream &);
          
        // Same thing with the shadow :
        // TODO Swig string* GetShaTagNames(); 
-       // TODO Swig string GetShaElValByName(string TagName);
-       // TODO Swig string GetShaElValByNumber(guint16 group, guint16 element);
-       // TODO Swig string GetShaElValRepByName(string TagName);
-       // TODO Swig string GetShaElValRepByNumber(guint16 group, guint16 element);
-
-       // Wrappers of the above (both public and shadow) to avoid bugging the
-       // caller with knowing if ElVal is from the public or shadow dictionary.
-       // TODO Swig string GetElValByName(string TagName);
-       // TODO Swig string GetElValByNumber(guint16 group, guint16 element);
-       // TODO Swig string GetElValRepByName(string TagName);
-       // TODO Swig string GetElValRepByNumber(guint16 group, guint16 element);
+       string GetShaElValByName(string TagName);
+       string GetShaElValByNumber(guint16 group, guint16 element);
+       string GetShaElValRepByName(string TagName);
+       string GetShaElValRepByNumber(guint16 group, guint16 element);
+
+       // Wrappers of the above (public is privileged over shadow) to avoid
+       // bugging the caller with knowing if ElVal is from the public or shadow
+       // dictionary.
+       string GetElValByName(string TagName);
+       string GetElValByNumber(guint16 group, guint16 element);
+       string GetElValRepByName(string TagName);
+       string GetElValRepByNumber(guint16 group, guint16 element);
 
        // TODO Swig int SetPubElValByName(string content, string TagName);
        // TODO Swig int SetPubElValByNumber(string content, guint16 group, guint16 element);
@@ -297,18 +444,28 @@ public:
        // TODO Swig int GetSwapCode();
 };
 
+//
+// ---------------------------------------------------- gdcmFile
+//
+//     un fichier EST_UNE entete, ou A_UNE entete ?
+//
+//
+
+
+////////////////////////////////////////////////////////////////////////////
 // In addition to Dicom header exploration, this class is designed
 // for accessing the image/volume content. One can also use it to
 // write Dicom files.
 ////// QUESTION: this looks still like an open question wether the
 //////           relationship between a gdcmFile and gdcmHeader is of
 //////           type IS_A or HAS_A !
+
 class GDCM_EXPORT gdcmFile: gdcmHeader
 {
 private:
        void* Data;
-       int Parsed;                             // weather allready parsed
-       string OrigFileName;    // To avoid file overwrite
+       int Parsed;          // weather allready parsed
+       string OrigFileName; // To avoid file overwrite
 public:
        // Constructor dedicated to writing a new DICOMV3 part10 compliant
        // file (see SetFileName, SetDcmTag and Write)
@@ -319,8 +476,10 @@ public:
        //    the DICOM header is post-poned to first header information access.
        //    This avoid a double parsing of public part of the header when
        //    one sets an a posteriori shadow dictionary (efficiency can be
-       //    seen a a side effect).
+       //    seen as a side effect).
+       
        gdcmFile(string & filename);
+       
        // For promotion (performs a deepcopy of pointed header object)
        // TODO Swig gdcmFile(gdcmHeader* header);
        // TODO Swig ~gdcmFile();
@@ -333,12 +492,15 @@ public:
        // Allocates necessary memory, copies the data (image[s]/volume[s]) to
        // newly allocated zone and return a pointer to it:
        // TODO Swig void * GetImageData();
+       
        // Returns size (in bytes) of required memory to contain data
        // represented in this file.
        // TODO Swig size_t GetImageDataSize();
+       
        // Copies (at most MaxSize bytes) of data to caller's memory space.
        // Returns an error code on failure (if MaxSize is not big enough)
        // TODO Swig int PutImageDataHere(void* destination, size_t MaxSize );
+       
        // Allocates ExpectedSize bytes of memory at this->Data and copies the
        // pointed data to it.
        // TODO Swig int SetImageData(void * Data, size_t ExpectedSize);
@@ -346,25 +508,22 @@ public:
        // TODO Swig int Write();
 };
 
+//
+// ---------------------------------------------------- gdcmSerie
+//
+//     une serie EST_UN fichier ????
+//
+//
+
 //class gdcmSerie : gdcmFile;
-//class gdcmMultiFrame : gdcmFile;
 
 //
-//Examples:
-// * gdcmFile WriteDicom;
-//   WriteDicom.SetFileName("MyDicomFile.dcm");
-//     string * AllTags = gdcmHeader.GetDcmTagNames();
-//   WriteDicom.SetDcmTag(AllTags[5], "253");
-//   WriteDicom.SetDcmTag("Patient Name", "bozo");
-//   WriteDicom.SetDcmTag("Patient Name", "bozo");
-//     WriteDicom.SetImageData(Image);
-//   WriteDicom.Write();
-//
-//
-//   Anonymize(ostream& output) {
-//   a = gdcmFile("toto1");
-//   a.SetPubValueByName("Patient Name", "");
-//   a.SetPubValueByName("Date", "");
-//   a.SetPubValueByName("Study Date", "");
-//   a.write(output);
-//   }
+// ---------------------------------------------------- gdcmMultiFrame
+//
+//     un fichierMultiFrame EST_UN fichier 
+//
+//
+
+//class gdcmMultiFrame : gdcmFile;
+
+