]> Creatis software - gdcm.git/commitdiff
* src/gdcmHeader.cxx added a post header parsing AddAndDefaultElements
authorfrog <frog>
Tue, 28 Jan 2003 08:41:00 +0000 (08:41 +0000)
committerfrog <frog>
Tue, 28 Jan 2003 08:41:00 +0000 (08:41 +0000)
        method. Doxygenation.
      * src/gdcm.h clean up of JPR spurious comments. --- Frog

ChangeLog
Dicts/README
Testing/ExceptionAndPython/.cvsignore
src/gdcm.h
src/gdcmDict.cxx
src/gdcmElValSet.cxx
src/gdcmElValue.cxx
src/gdcmHeader.cxx

index 8f854425118b2dc7ecdf2c34ec14fa8b7773d771..1c3899d4813c2ac8ad0f36d53d88df0a76b00b32 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-01-28 Eric Boix <Eric.Boix@creatis.insa-lyon.fr>
+      * src/gdcmHeader.cxx added a post header parsing AddAndDefaultElements
+        method. Doxygenation.
+      * src/gdcm.h clean up of JPR spurious comments.
+
 2003-01-17 Eric Boix <Eric.Boix@creatis.insa-lyon.fr>
       * python/distutilsSwigCPlusPlus.py now properly collects the
         shadow classes generated by "swig -c++" (gdcm.py in our case)
index 23fdf288b9f6f4ff4e46aa2b9d7293c95d9d2cca..8d27cd6a36ece620ecb71dc4c58479a96811d21b 100644 (file)
@@ -1,4 +1,6 @@
 Sources for dicom public dictionaries:
+ * the official source is the part 6 of the dicom standard (see
+   http://www.dclunie.com/dicom-status/status.html#BaseStandard2001).
  * http://www.fpimage.com/Manuals/Imp/dicomdic.html
    an html group based presentation.
  * ftp://rsbweb.nih.gov/pub/nih-image/documents/dicom-dict.txt
index d89fdcc749aec65fc7fff0d5785314ea75476f59..5b6861ed6174ba9f1cc206d8a933619149b94384 100644 (file)
@@ -4,3 +4,4 @@ foo.cxx
 main
 *.o
 *.so
+*.pyc
index c2c139c037c6f1abaffbf90f07dfecfd3aa01847..c4737561aa279a4ee532a1a00a47a72c4acec373 100644 (file)
@@ -69,13 +69,6 @@ typedef  unsigned int   guint32;
 #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
@@ -87,6 +80,7 @@ typedef  unsigned int   guint32;
 // gdcmDictEntry::TranslateToKey for this conversion function.
 
 typedef string TagKey;
+typedef string TagName;
 
 class GDCM_EXPORT gdcmDictEntry {
 private:
@@ -114,75 +108,54 @@ private:
        //         DcmDictRangeRestriction elementRestriction;
        //       };
 public:
-       
-       // fabrique une ligne de Dictionnaire Dicom à partir des parametres en entrée
-
        gdcmDictEntry(guint16 group, 
-                         guint16 element,
+                     guint16 element,
                      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);
-       void    SetKey(string k){ key = k;              }
+       void    SetKey(string k){ key = k;     }
        bool    IsVrUnknown(void);
        string  GetFourth(void) {return fourth;};
        string  GetName(void)   {return name;  };
        string  GetKey(void)    {return key;   };
 };
   
-//
-// ---------------------------------------------------- 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) --> pointeur vers une ligne du Dictionnaire Dicom
+typedef map<TagKey,  gdcmDictEntry*> TagKeyHT;
+typedef map<TagName, gdcmDictEntry*> TagNameHT;
 
 class GDCM_EXPORT gdcmDict {
        string name;
        string filename;
-       TagHT entries;
+       TagKeyHT  KeyHt;                // Both accesses with a TagKey or with a
+       TagNameHT NameHt;               // TagName are required.
 public:
-       // rempli le Dictionnaire Dicom à partir d'un fichier texte
-       gdcmDict(const char* FileName);   // Read Dict from disk
-       
+       gdcmDict(const char* FileName);   // Reads Dict from ascii file
        int AddNewEntry (gdcmDictEntry* NewEntry);
        int ReplaceEntry(gdcmDictEntry* NewEntry);
-       int RemoveEntry (TagKey k);
+       int RemoveEntry (TagKey key);
        int RemoveEntry (guint16 group, guint16 element);
-       
-       // renvoie une ligne de Dictionnaire Dicom à partir de (numGroup, numElement)
-       gdcmDictEntry * GetTag(guint32 group, guint32 element);
-       
+       gdcmDictEntry * GetTagByKey(guint16 group, guint16 element);
+       gdcmDictEntry * GetTagByName(TagName name);
        void Print(ostream&);
-       TagHT & GetEntries(void) { return entries; }
+       void PrintByKey(ostream&);
+       void PrintByName(ostream&);
+       TagKeyHT & GetEntries(void) { return KeyHt; }
 };
 
 
-//
-// ---------------------------------------------------- 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 :
@@ -219,25 +192,9 @@ public:
        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)
-//
-
-// QUESTION:
-//
-// Ne faudrait-il pas trouver un autre nom, qui preterait moins à confusion?
-// ElValue n'EST PAS la 'valeur d'un Element', mais la reunion d'infos
-// trouvees dans l'Entete du fichier ET 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;
@@ -246,65 +203,48 @@ private:
                               // 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
+       string  value;
        size_t Offset;     // Offset from the begining of file for direct user access
        
        ElValue(gdcmDictEntry*);
        void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; };
        bool   IsVrUnknown(void) { return entry->IsVrUnknown(); };
-       void SetImplicitVr(void) { ImplicitVr = true;                   };
-       bool  IsImplicitVr(void) { return ImplicitVr;                   };
-
-       guint16 GetGroup(void)   { return entry->GetGroup();    };      
-       guint16 GetElement(void) { return entry->GetElement();  };
-       string  GetKey(void)     { return entry->GetKey();      };
-       string  GetName(void)    { return entry->GetName();     };
+       void SetImplicitVr(void) { ImplicitVr = true; };
+       bool  IsImplicitVr(void) { return ImplicitVr; };
        
-       string  GetVR(void)              { return entry->GetVR();               };
-       void    SetVR(string v)  { entry->SetVR(v);                     }; 
-               
-       // Question :
-       // Un champ privé, accessible en consultation et en modif (sans restriction)
-       // interet par rapport à un champ public ? 
-       // --> pouvoir en changer la définition sans toucher à l'API
-
-       void SetLength(guint32 l){ LgrElem = l;         };
-       guint32 GetLength(void)  { return LgrElem;      };
+       guint16 GetGroup(void)   { return entry->GetGroup();  };
+       guint16 GetElement(void) { return entry->GetElement();};
+       string  GetKey(void)     { return entry->GetKey();    };
+       string  GetName(void)    { return entry->GetName();   };
+       string  GetVR(void)      { return entry->GetVR();     };
+       void    SetVR(string v)  { entry->SetVR(v);           }; 
+       void SetLength(guint32 l){ LgrElem = l;               };
+       guint32 GetLength(void)  { return LgrElem;            };
        
        // Question : SetLength est public 
        // (sinon, on ne pourrait pas l'appeler dans ElValSet)
        // alors que *personne* ne devrait s'en servir !
        // c'est *forcément* la lgr de la string 'value', non?
 
-       void SetValue(string val){ value = val;         };
-       string  GetValue(void)   { return value;        };
+       void SetValue(string val){ value = val; };
+       string  GetValue(void)   { return value;};
 
-       void SetOffset(size_t of){ Offset = of;         };
-       size_t  GetOffset(void)  { return Offset;       };
+       void SetOffset(size_t of){ Offset = of; };
+       size_t  GetOffset(void)  { return Offset;};
        // Question : SetOffset est public ...
        // Quel utilisateur serait ammené à modifier l'Offset ?
 };
 
 
-//
-// ---------------------------------------------------- ElValSet
-//
-//     ... un ensemble d'Elements Dicom 
-//     ... le résultat de l'analyse d'une entete d'image, par exemple
-
 ////////////////////////////////////////////////////////////////////////////
 // Container for a set of successfully parsed ElValues.
 typedef map<TagKey, ElValue*> TagElValueHT;
 typedef map<string, ElValue*> TagElValueNameHT;
 
 class GDCM_EXPORT ElValSet {
-               // We need both accesses with a TagKey and the Dictentry.Name
-
-       TagElValueHT tagHt;
-       TagElValueNameHT NameHt;
+       TagElValueHT tagHt;             // Both accesses with a TagKey or with a
+       TagElValueNameHT NameHt;        // the DictEntry.Name are required.
 public:        
        void Add(ElValue*);             
        void Print(ostream &);
@@ -321,16 +261,11 @@ public:
        int SetElValueByName(string content, string TagName);
 };
 
-
-//
-// ---------------------------------------------------- gdcmHeader
-//
-//     C'est le Dicom Header d'une image donnée
-//     (tous les elements Dicom qui la composent
-//     + des info 'de service')
-//
-
 ////////////////////////////////////////////////////////////////////////////
+// The purpous of an instance of gdcmHeader is to act as a container of
+// all the elements and their corresponding values (and additionaly the
+// corresponding DICOM dictionary entry) of the header of a DICOM file.
+//
 // 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
@@ -341,13 +276,11 @@ public:
 //   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)
 
 typedef string VRKey;
 typedef string VRAtr;
 typedef map<VRKey, VRAtr> VRHT;    // Value Representation Hash Table
 
-
 class GDCM_EXPORT gdcmHeader {
        void SkipBytes(guint32);
 private:
@@ -362,16 +295,6 @@ private:
        ElValSet ShaElVals;         // parsed with Shadow Dictionary
        string filename;            // refering underlying file
        FILE * fp;
-       // The tag Image Location (0028,0200) - containing the address of
-       // the pixels - is not allways present. Then we store this information
-       // il etait facultatif en ACR-NEMA, il n'existe plus en DICOM 3
-       // FIXME
-       
-       // Question :
-       // Qu'y a-t-il a corriger ?
-       //
-       // outside of the elements:
-       
        guint16 grPixel;
        guint16 numPixel;
        // Ne faudrait-il pas une indication sur la presence ou non
@@ -396,16 +319,26 @@ private:
        guint32 ReadInt32(void);
        guint16 SwapShort(guint16);
        guint32 SwapLong(guint32);
+       guint32 FindLengthOB(void);
        void Initialise(void);
        void CheckSwap(void);
+       void InitVRDict(void);
+       void SwitchSwapToBigEndian(void);
+       void AddAndDefaultElements(void);
+       void SetMaxSizeLoadElementValue(long);
+
+       gdcmDictEntry * GetDictEntryByKey(guint16, guint16);
+       gdcmDictEntry * GetDictEntryByName(string name);
+
+       // ElValue related utilities
+       ElValue * ReadNextElement(void);
+       ElValue * NewElValueByKey(guint16 group, guint16 element);
+       ElValue * NewElValueByName(string name);
        void FindLength(ElValue *);
-       guint32 FindLengthOB(void);
        void FindVR(ElValue *);
        void LoadElementValue(ElValue *);
        void LoadElementValueSafe(ElValue *);
        void SkipElementValue(ElValue *);
-       void InitVRDict(void);
-       void SwitchSwapToBigEndian(void);
        void FixFoundLength(ElValue*, guint32);
        bool IsAnInteger(ElValue *);
        
@@ -417,15 +350,7 @@ private:
        bool IsJPEGExtendedProcess2_4TransferSyntax(void);      
        bool IsJPEGExtendedProcess3_5TransferSyntax(void);
        bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void);     
-//
-// Euhhhhhhh
-// Il y en a encore DIX-SEPT, comme ça.
-// Il faudrait trouver qq chose + rusé ...
-//     
                
-       void SetMaxSizeLoadElementValue(long);
-       ElValue       * ReadNextElement(void);
-       gdcmDictEntry * IsInDicts(guint32, guint32);
 protected:
        enum FileType {
                Unknown = 0,
index 70768a0d0afd73d23c7f86ddb242e67f6bbb3ce9..2ad026e8f1c9dbc8732eb3d16b924148fa02b249 100644 (file)
@@ -10,7 +10,10 @@ gdcmDict::gdcmDict(const char* FileName) {
        guint16 group, element;
        // CLEANME : use defines for all those constants
        char buff[1024];
-       TagKey key, vr, fourth, name;
+       TagKey key;
+       TagName vr;
+       TagName fourth;
+       TagName name;
        while (!from.eof()) {
                from >> hex >> group >> element;
                eatwhite(from);
@@ -23,37 +26,85 @@ gdcmDict::gdcmDict(const char* FileName) {
                name = buff;
                gdcmDictEntry * newEntry = new gdcmDictEntry(group, element,
                                                         vr, fourth, name);
-               entries[gdcmDictEntry::TranslateToKey(group, element)] = newEntry;
+               NameHt[name] = newEntry;
+               KeyHt[gdcmDictEntry::TranslateToKey(group, element)] = newEntry;
        }
-   from.close();
+       from.close();
 }
 
 void gdcmDict::Print(ostream& os) {
-       for (TagHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){
-       os << "Tag : ";
-       os << "(" << hex << tag->second->GetGroup() << ',';
-       os << hex << tag->second->GetElement() << ") = " << dec;
-       os << tag->second->GetVR() << ", ";
-       os << tag->second->GetFourth() << ", ";
-       os << tag->second->GetName() << "."  << endl;
-    }
+       PrintByKey(os);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Print all the dictionary entries contained in this dictionary.
+ *          Entries will be sorted by tag i.e. the couple (group, element).
+ * @param   os The output stream to be written to.
+ */
+void gdcmDict::PrintByKey(ostream& os) {
+       for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag){
+               os << "Tag : ";
+               os << "(" << hex << tag->second->GetGroup() << ',';
+               os << hex << tag->second->GetElement() << ") = " << dec;
+               os << tag->second->GetVR() << ", ";
+               os << tag->second->GetFourth() << ", ";
+               os << tag->second->GetName() << "."  << endl;
+       }
 }
 
-// renvoie une ligne de Dictionnaire Dicom à partir de (numGroup, numElement)
+/**
+ * \ingroup gdcmHeader
+ * \brief   Print all the dictionary entries contained in this dictionary.
+ *          Entries will be sorted by the name of the dictionary entries.
+ * @param   os The output stream to be written to.
+ */
+void gdcmDict::PrintByName(ostream& os) {
+       for (TagNameHT::iterator tag = NameHt.begin(); tag != NameHt.end(); ++tag){
+               os << "Tag : ";
+               os << tag->second->GetName() << ",";
+               os << tag->second->GetVR() << ", ";
+               os << tag->second->GetFourth() << ", ";
+               os << "(" << hex << tag->second->GetGroup() << ',';
+               os << hex << tag->second->GetElement() << ") = " << dec << endl;
+       }
+}
 
-gdcmDictEntry * gdcmDict::GetTag(guint32 group, guint32 element) {
+/**
+ * \ingroup gdcmHeader
+ * \brief   Get the dictionnary entry identified by a given tag (group,element)
+ * @param   group   group of the entry to be found
+ * @param   element element of the entry to be found
+ * @return  the corresponding dictionnary entry when existing, NULL otherwise
+ */
+gdcmDictEntry * gdcmDict::GetTagByKey(guint16 group, guint16 element) {
        TagKey key = gdcmDictEntry::TranslateToKey(group, element);
-       if ( ! entries.count(key))
+       if ( ! KeyHt.count(key))
                return (gdcmDictEntry*)0; 
-       if (entries.count(key) > 1)
-               dbg.Verbose(0, "gdcmDict::GetTag", 
+       if (KeyHt.count(key) > 1)
+               dbg.Verbose(0, "gdcmDict::GetTagByName", 
                            "multiple entries for this key (FIXME) !");
-       return entries.find(key)->second;
+       return KeyHt.find(key)->second;
 }
 
+/**
+ * \ingroup gdcmHeader
+ * \brief   Get the dictionnary entry identified by it's name.
+ * @param   name element of the ElVal to modify
+ * @return  the corresponding dictionnary entry when existing, NULL otherwise
+ */
+gdcmDictEntry * gdcmDict::GetTagByName(TagName name) {
+       if ( ! NameHt.count(name))
+               return (gdcmDictEntry*)0; 
+       if (NameHt.count(name) > 1)
+               dbg.Verbose(0, "gdcmDict::GetTagByName", 
+                           "multiple entries for this key (FIXME) !");
+       return NameHt.find(name)->second;
+}
 
-int gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) {
 
+int gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) {
+       //JPRCLEAN
        // au cas ou la NewEntry serait incomplete
        // Question : cela peut-il se produire ?
        //
@@ -66,10 +117,11 @@ int gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) {
        //                      );
        //}
        
-       entries.erase (NewEntry->gdcmDictEntry::GetKey());
-       entries[ NewEntry->GetKey()] = NewEntry;
+       KeyHt.erase (NewEntry->gdcmDictEntry::GetKey());
+       KeyHt[ NewEntry->GetKey()] = NewEntry;
        return (1);
-       // Question : Dans quel cas ça peut planter ?
+       // Question(jpr): Dans quel cas ça peut planter ?
+       // Reponse(frog): dans les mauvais cas...
 }
  
 
@@ -78,19 +130,19 @@ int gdcmDict::AddNewEntry(gdcmDictEntry* NewEntry) {
        TagKey key;
        key = NewEntry->GetKey();
        
-       if(entries.count(key) >= 1) {
+       if(KeyHt.count(key) >= 1) {
                printf("gdcmDict::AddNewEntry %s deja present\n", key.c_str());
                return(0);
        } else {
-               entries[NewEntry->GetKey()] = NewEntry;
+               KeyHt[NewEntry->GetKey()] = NewEntry;
                return(1);
        }
        }
 
 
 int gdcmDict::RemoveEntry(TagKey key) {        
-       if(entries.count(key) == 1) {
-               entries.erase(key);
+       if(KeyHt.count(key) == 1) {
+               KeyHt.erase(key);
                return (1);
        } else {
                printf("gdcmDict::RemoveEntry %s non trouve\n", key.c_str());
index 39ba3c1a02c989f99a9b82cac71ad1d43d5a9fad..aef6800ffec75fcb544a0543a8520bb44a4e1fb3 100644 (file)
@@ -82,10 +82,8 @@ int ElValSet::SetElValueByNumber(string content, guint32 group, guint32 element)
                return (0); 
        }                                      
        tagHt[key]->SetValue(content);
-       // Question : m à j LgrElem ?
-       tagHt[key]->SetLength(strlen(content.c_str()));  
-                               // Ou trouver les fonctions d'une classe donnée?
-                               // lgr d'une string, p.ex 
+       // FIXME should we really update the element length ?
+       tagHt[key]->SetLength(content.length());         
        return(1);              
 }
 
index 339069021ba1525f4766c6eb402c6279eaeeb44e..3a8a7156929186f299ce44b58804f0d6e69705f6 100644 (file)
@@ -2,11 +2,12 @@
 
 #include "gdcm.h"
 
-       // void    ElValue::SetVR(string v)      { entry->SetVR(v);       };
-
+/**
+ * \ingroup gdcmElValue
+ * \brief   Constructor from a given gdcmDictEntry
+ * @param   in Pointer to existing dictionary entry
+ */
 ElValue::ElValue(gdcmDictEntry* in) {
        ImplicitVr = false;
        entry = in;
 }
-
-
index dd8cdc09ee68b2768c3f491b06ffb4bba0816552..afe3ed329bf5ce308a6f188720a1b6501f4f4afa 100644 (file)
@@ -44,6 +44,7 @@ gdcmHeader::gdcmHeader (const char* InFilename) {
        fp=fopen(InFilename,"rw");
        dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename);
        ParseHeader();
+       AddAndDefaultElements();
 }
 
 gdcmHeader::~gdcmHeader (void) {
@@ -600,7 +601,7 @@ void gdcmHeader::FindLength(ElValue * ElVal) {
                        // and the dictionary entry depending on them.
                        guint16 CorrectGroup   = SwapShort(ElVal->GetGroup());
                        guint16 CorrectElem    = SwapShort(ElVal->GetElement());
-                       gdcmDictEntry * NewTag = IsInDicts(CorrectGroup, CorrectElem);
+                       gdcmDictEntry * NewTag = GetDictEntryByKey(CorrectGroup, CorrectElem);
                        if (!NewTag) {
                                // This correct tag is not in the dictionary. Create a new one.
                                NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
@@ -840,6 +841,52 @@ guint32 gdcmHeader::ReadInt32(void) {
        return g;
 }
 
+/**
+ * \ingroup gdcmHeader
+ * \brief   Build a new Element Value from all the low level arguments. 
+ *          Check for existence of dictionary entry, and build
+ *          a default one when absent.
+ * @param   Group group   of the underlying DictEntry
+ * @param   Elem  element of the underlying DictEntry
+ */
+ElValue* gdcmHeader::NewElValueByKey(guint16 Group, guint16 Elem) {
+       // Find out if the tag we encountered is in the dictionaries:
+       gdcmDictEntry * NewTag = GetDictEntryByKey(Group, Elem);
+       if (!NewTag)
+               NewTag = new gdcmDictEntry(Group, Elem);
+
+       ElValue* NewElVal = new ElValue(NewTag);
+       if (!NewElVal) {
+               dbg.Verbose(1, "gdcmHeader::NewElValueByKey",
+                           "failed to allocate ElValue");
+               return (ElValue*)0;
+       }
+   return NewElVal;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Build a new Element Value from all the low level arguments. 
+ *          Check for existence of dictionary entry, and build
+ *          a default one when absent.
+ * @param   Name    Name of the underlying DictEntry
+ */
+ElValue* gdcmHeader::NewElValueByName(string Name) {
+
+   gdcmDictEntry * NewTag = GetDictEntryByName(Name);
+   if (!NewTag)
+      NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
+
+   ElValue* NewElVal = new ElValue(NewTag);
+   if (!NewElVal) {
+      dbg.Verbose(1, "gdcmHeader::ObtainElValueByName",
+                  "failed to allocate ElValue");
+      return (ElValue*)0;
+   }
+   return NewElVal;
+}  
+
+
 /**
  * \ingroup gdcmHeader
  * \brief   Read the next tag without loading it's value
@@ -857,18 +904,8 @@ ElValue * gdcmHeader::ReadNextElement(void) {
                // We reached the EOF (or an error occured) and header parsing
                // has to be considered as finished.
                return (ElValue *)0;
-
-       // Find out if the tag we encountered is in the dictionaries:
-       gdcmDictEntry * NewTag = IsInDicts(g, n);
-       if (!NewTag)
-               NewTag = new gdcmDictEntry(g, n);
-
-       NewElVal = new ElValue(NewTag);
-       if (!NewElVal) {
-               dbg.Verbose(1, "ReadNextElement: failed to allocate ElValue");
-               return (ElValue*)0;
-       }
-
+       
+       NewElVal = NewElValueByKey(g, n);
        FindVR(NewElVal);
        FindLength(NewElVal);
        if (errno == 1)
@@ -908,25 +945,9 @@ bool gdcmHeader::IsAnInteger(ElValue * ElVal) {
                return true;
        
        if ( (group == 0x0028) && (element == 0x0005) )
-               // This tag is retained from ACR/NEMA
-               // CHECKME Why should "Image Dimensions" be a single integer ?
-               //
-               // "Image Dimensions", c'est en fait le 'nombre de dimensions'
-               // de l'objet ACR-NEMA stocké
-               // 1 : Signal
-               // 2 : Image
-               // 3 : Volume
-               // 4 : Sequence
-               //
-               // DICOM V3 ne retient pas cette information
-               // Par defaut, tout est 'Image',
-               // C'est a l'utilisateur d'explorer l'ensemble des entetes
-               // pour savoir à quoi il a a faire
-               //
-               // Le Dicom Multiframe peut etre utilise pour stocker,
-               // dans un seul fichier, une serie temporelle (cardio vasculaire GE, p.ex)
-               // ou un volume (medecine Nucleaire, p.ex)
-               //
+               // The "Image Dimensions" tag is retained from ACR/NEMA and contains
+               // the number of dimensions of the contained object (1 for Signal,
+               // 2 for Image, 3 for Volume, 4 for Sequence).
                return true;
        
        if ( (group == 0x0028) && (element == 0x0200) )
@@ -969,23 +990,56 @@ size_t gdcmHeader::GetPixelOffset(void) {
                return 0;
 }
 
-gdcmDictEntry * gdcmHeader::IsInDicts(guint32 group, guint32 element) {
-       //
-       // Y a-t-il une raison de lui passer des guint32
-       // alors que group et element sont des guint16?
-       //
+/**
+ * \ingroup gdcmHeader
+ * \brief   Searches both the public and the shadow dictionary (when they
+ *          exist) for the presence of the DictEntry with given
+ *          group and element. The public dictionary has precedence on the
+ *          shadow one.
+ * @param   group   group of the searched DictEntry
+ * @earam   element element of the searched DictEntry
+ * @return  Corresponding DictEntry when it exists, NULL otherwise.
+ */
+gdcmDictEntry * gdcmHeader::GetDictEntryByKey(guint16 group, guint16 element) {
+       gdcmDictEntry * found = (gdcmDictEntry*)0;
+       if (!RefPubDict && !RefShaDict) {
+               dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
+                     "we SHOULD have a default dictionary");
+       }
+       if (RefPubDict) {
+               found = RefPubDict->GetTagByKey(group, element);
+               if (found)
+                       return found;
+       }
+       if (RefShaDict) {
+               found = RefShaDict->GetTagByKey(group, element);
+               if (found)
+                       return found;
+       }
+       return found;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Searches both the public and the shadow dictionary (when they
+ *          exist) for the presence of the DictEntry with given name.
+ *          The public dictionary has precedence on the shadow one.
+ * @earam   Name name of the searched DictEntry
+ * @return  Corresponding DictEntry when it exists, NULL otherwise.
+ */
+gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) {
        gdcmDictEntry * found = (gdcmDictEntry*)0;
        if (!RefPubDict && !RefShaDict) {
-               //FIXME build a default dictionary !
-               printf("FIXME in gdcmHeader::IsInDicts\n");
+               dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
+                     "we SHOULD have a default dictionary");
        }
        if (RefPubDict) {
-               found = RefPubDict->GetTag(group, element);
+               found = RefPubDict->GetTagByName(Name);
                if (found)
                        return found;
        }
        if (RefShaDict) {
-               found = RefShaDict->GetTag(group, element);
+               found = RefShaDict->GetTagByName(Name);
                if (found)
                        return found;
        }
@@ -994,9 +1048,9 @@ gdcmDictEntry * gdcmHeader::IsInDicts(guint32 group, guint32 element) {
 
 list<string> * gdcmHeader::GetPubTagNames(void) {
        list<string> * Result = new list<string>;
-       TagHT entries = RefPubDict->GetEntries();
+       TagKeyHT entries = RefPubDict->GetEntries();
 
-       for (TagHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){
+       for (TagKeyHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){
       Result->push_back( tag->second->GetName() );
        }
        return Result;
@@ -1004,9 +1058,9 @@ list<string> * gdcmHeader::GetPubTagNames(void) {
 
 map<string, list<string> > * gdcmHeader::GetPubTagNamesByCategory(void) {
        map<string, list<string> > * Result = new map<string, list<string> >;
-       TagHT entries = RefPubDict->GetEntries();
+       TagKeyHT entries = RefPubDict->GetEntries();
 
-       for (TagHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){
+       for (TagKeyHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){
                (*Result)[tag->second->GetFourth()].push_back(tag->second->GetName());
        }
        return Result;
@@ -1056,7 +1110,6 @@ string gdcmHeader::GetShaElValRepByName(string TagName) {
        return elem->GetVR();
 }
 
-
 string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) {
        string pub = GetPubElValByNumber(group, element);
        if (pub.length())
@@ -1087,57 +1140,63 @@ string gdcmHeader::GetElValRepByName(string TagName) {
 
 /**
  * \ingroup gdcmHeader
- * \brief   Modifie la valeur d'un ElValue déja existant
- * \   dans le PubElVals du gdcmHeader,
- * \   accédé par ses numero de groupe et d'element.
+ * \brief   Accesses an existing ElValue in the PubElVals of this instance
+ *          through it's (group, element) and modifies it's content with
+ *          the given value.
+ * @param   content new value to substitute with
+ * @param   group   group of the ElVal to modify
+ * @param   element element of the ElVal to modify
  */
-int gdcmHeader::SetPubElValByNumber(string content, guint16 group, guint16 element) {
-       //TagKey key = gdcmDictEntry::TranslateToKey(group, element);
-       //PubElVals.tagHt[key]->SetValue(content);
-       
+int gdcmHeader::SetPubElValByNumber(string content, guint16 group,
+                                    guint16 element)
+{
+       //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element);
+       //CLEANME PubElVals.tagHt[key]->SetValue(content);
        return (  PubElVals.SetElValueByNumber (content, group, element) );
 }
 
-
 /**
  * \ingroup gdcmHeader
- * \brief   Modifie la valeur d'un ElValue déja existant
- * \   dans le PubElVals du gdcmHeader,
- * \   accédé par son nom
+ * \brief   Accesses an existing ElValue in the PubElVals of this instance
+ *          through tag name and modifies it's content with the given value.
+ * @param   content new value to substitute with
+ * @param   TagName name of the tag to be modified
  */
 int gdcmHeader::SetPubElValByName(string content, string TagName) {
-       //TagKey key = gdcmDictEntry::TranslateToKey(group, element);
-       //PubElVals.tagHt[key]->SetValue(content);
-       
+       //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element);
+       //CLEANME PubElVals.tagHt[key]->SetValue(content);
        return (  PubElVals.SetElValueByName (content, TagName) );
 }
 
-
 /**
  * \ingroup gdcmHeader
- * \brief   Modifie la valeur d'un ElValue déja existant
- * \   dans le ShaElVals du gdcmHeader,
- * \   accédé par ses numero de groupe et d'element.
+ * \brief   Accesses an existing ElValue in the ShaElVals of this instance
+ *          through it's (group, element) and modifies it's content with
+ *          the given value.
+ * @param   content new value to substitute with
+ * @param   group   group of the ElVal to modify
+ * @param   element element of the ElVal to modify
  */
-int gdcmHeader::SetShaElValByNumber(string content, guint16 group, guint16 element) {
-       
+int gdcmHeader::SetShaElValByNumber(string content,
+                                    guint16 group, guint16 element)
+{
        return (  ShaElVals.SetElValueByNumber (content, group, element) );
 }
 
-
 /**
  * \ingroup gdcmHeader
- * \brief   Modifie la valeur d'un ElValue déja existant
- * \   dans le ShaElVals du gdcmHeader,
- * \   accédé par son nom
+ * \brief   Accesses an existing ElValue in the ShaElVals of this instance
+ *          through tag name and modifies it's content with the given value.
+ * @param   content new value to substitute with
+ * @param   TagName name of the tag to be modified
  */
 int gdcmHeader::SetShaElValByName(string content, string TagName) {
-       
        return (  ShaElVals.SetElValueByName (content, TagName) );
 }
+
 /**
  * \ingroup gdcmHeader
- * \brief   Parses the header of the file but does NOT load element values.
+ * \brief   Parses the header of the file but WITHOUT loading element values.
  */
 void gdcmHeader::ParseHeader(void) {
        ElValue * newElValue = (ElValue *)0;
@@ -1150,17 +1209,42 @@ void gdcmHeader::ParseHeader(void) {
        }
 }
 
+/**
+ * \ingroup gdcmHeader
+ * \brief   Once the header is parsed add some gdcm convenience/helper elements
+ *          in the ElValSet. For example add:
+ *          - gdcmImageType which is an entry containing a short for the
+ *            type of image and whose value ranges in 
+ *               I8   (unsigned 8 bit image)
+ *               I16  (unsigned 8 bit image)
+ *               IS16 (signed 8 bit image)
+ *          - gdcmXsize, gdcmYsize, gdcmZsize whose values are respectively
+ *            the ones of the official DICOM fields Rows, Columns and Planes.
+ */
+void gdcmHeader::AddAndDefaultElements(void) {
+       ElValue* NewEntry = (ElValue*)0;
+
+       NewEntry = NewElValueByName("gdcmXSize");
+       NewEntry->SetValue(GetElValByName("Rows"));
+       PubElVals.Add(NewEntry);
+
+       NewEntry = NewElValueByName("gdcmYSize");
+       NewEntry->SetValue(GetElValByName("Columns"));
+       PubElVals.Add(NewEntry);
+
+       NewEntry = NewElValueByName("gdcmZSize");
+       NewEntry->SetValue(GetElValByName("Planes"));
+       PubElVals.Add(NewEntry);
+}
+
 /**
  * \ingroup gdcmHeader
  * \brief   Loads the element values of all the elements present in the
  *          public tag based hash table.
  */
 void gdcmHeader::LoadElements(void) {
-
        rewind(fp);   
-
        TagElValueHT ht = PubElVals.GetTagHt();
-       
        for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
                LoadElementValue(tag->second);
                }