From: frog Date: Tue, 28 Jan 2003 08:41:00 +0000 (+0000) Subject: * src/gdcmHeader.cxx added a post header parsing AddAndDefaultElements X-Git-Tag: April2003~47 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=add079705405296ac0e1f811afbd0f237371dd52;p=gdcm.git * src/gdcmHeader.cxx added a post header parsing AddAndDefaultElements method. Doxygenation. * src/gdcm.h clean up of JPR spurious comments. --- Frog --- diff --git a/ChangeLog b/ChangeLog index 8f854425..1c3899d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-01-28 Eric Boix + * 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 * python/distutilsSwigCPlusPlus.py now properly collects the shadow classes generated by "swig -c++" (gdcm.py in our case) diff --git a/Dicts/README b/Dicts/README index 23fdf288..8d27cd6a 100644 --- a/Dicts/README +++ b/Dicts/README @@ -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 diff --git a/Testing/ExceptionAndPython/.cvsignore b/Testing/ExceptionAndPython/.cvsignore index d89fdcc7..5b6861ed 100644 --- a/Testing/ExceptionAndPython/.cvsignore +++ b/Testing/ExceptionAndPython/.cvsignore @@ -4,3 +4,4 @@ foo.cxx main *.o *.so +*.pyc diff --git a/src/gdcm.h b/src/gdcm.h index c2c139c0..c4737561 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -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 TagHT; - // Table de Hachage : (group,Elem) --> pointeur vers une ligne du Dictionnaire Dicom +typedef map TagKeyHT; +typedef map 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 TagElValueHT; typedef map 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 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, diff --git a/src/gdcmDict.cxx b/src/gdcmDict.cxx index 70768a0d..2ad026e8 100644 --- a/src/gdcmDict.cxx +++ b/src/gdcmDict.cxx @@ -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()); diff --git a/src/gdcmElValSet.cxx b/src/gdcmElValSet.cxx index 39ba3c1a..aef6800f 100644 --- a/src/gdcmElValSet.cxx +++ b/src/gdcmElValSet.cxx @@ -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); } diff --git a/src/gdcmElValue.cxx b/src/gdcmElValue.cxx index 33906902..3a8a7156 100644 --- a/src/gdcmElValue.cxx +++ b/src/gdcmElValue.cxx @@ -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; } - - diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index dd8cdc09..afe3ed32 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -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 * gdcmHeader::GetPubTagNames(void) { list * Result = new list; - 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 * gdcmHeader::GetPubTagNames(void) { map > * gdcmHeader::GetPubTagNamesByCategory(void) { map > * Result = new map >; - 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); }