From 8a806c5653d7832005f2c6f658cf8b5fa612f656 Mon Sep 17 00:00:00 2001 From: frog Date: Fri, 17 Sep 2004 13:11:14 +0000 Subject: [PATCH] * ENH: added some utility method that builds a flat dictionnary holding all the Dicom entries contained in the recursive structure of a gdcmElementSet. Refer to add FlatHashTablePrint.cxx for an example of usage. - src/gdcmDocument.[h|cxx] added BuildFlatHashTableRecurse() and BuildFlatHashTable() that build a flat dictionary. - src/gdcmElementSet.h: added a new private GetTag() accessor. gdcmDocument is now a friend of gdcmElementSet. - src/gdcmElementSet.cxx: clean up. - Example/FlatHashTablePrint.cxx added. - Example/CmakeLists.txt changed accordingly --- ChangeLog | 13 +++++ Example/CMakeLists.txt | 3 ++ Example/FlatHashTablePrint.cxx | 29 ++++++++++ src/gdcmDocument.cxx | 96 ++++++++++++++++++++++++++++++++-- src/gdcmDocument.h | 8 ++- src/gdcmElementSet.cxx | 14 ++--- src/gdcmElementSet.h | 13 +++-- 7 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 Example/FlatHashTablePrint.cxx diff --git a/ChangeLog b/ChangeLog index bf85521c..e2f2ca87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2004-09-17 Eric Boix + * ENH: added some utility method that builds a flat dictionnary + holding all the Dicom entries contained in the recursive structure + of a gdcmElementSet. Refer to add FlatHashTablePrint.cxx for + an example of usage. + - src/gdcmDocument.[h|cxx] added BuildFlatHashTableRecurse() and + BuildFlatHashTable() that build a flat dictionary. + - src/gdcmElementSet.h: added a new private GetTag() accessor. + gdcmDocument is now a friend of gdcmElementSet. + - src/gdcmElementSet.cxx: clean up. + - Example/FlatHashTablePrint.cxx added. + - Example/CmakeLists.txt changed accordingly + 2004-09-16 Eric Boix * gdcmDocEntrySet::SQDepthLevel and gdcmDocEntrySet::BaseTagKey attributes moved away from gdcmDocEntrySet (since this class is an abstract class diff --git a/Example/CMakeLists.txt b/Example/CMakeLists.txt index 791748f3..b49dbe1a 100644 --- a/Example/CMakeLists.txt +++ b/Example/CMakeLists.txt @@ -55,3 +55,6 @@ TARGET_LINK_LIBRARIES(TestChangeHeader gdcm) ADD_EXECUTABLE(TestReadWriteReadCompare TestReadWriteReadCompare.cxx) TARGET_LINK_LIBRARIES(TestReadWriteReadCompare gdcm) + +ADD_EXECUTABLE(FlatHashTablePrint FlatHashTablePrint.cxx) +TARGET_LINK_LIBRARIES(FlatHashTablePrint gdcm) diff --git a/Example/FlatHashTablePrint.cxx b/Example/FlatHashTablePrint.cxx new file mode 100644 index 00000000..bc9e599f --- /dev/null +++ b/Example/FlatHashTablePrint.cxx @@ -0,0 +1,29 @@ +#include "gdcmHeader.h" + +// Iterate on all the Dicom entries encountered in the gdcmFile (given +// as line argument) and print them. This is an illustration of the +// usage of \ref gdcmDocument::BuildFlatHashTable(). + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cerr << "Usage :" << std::endl << + argv[0] << " input_dicom " << std::endl; + return 1; + } + + gdcmHeader* header = new gdcmHeader( argv[1] ); + TagDocEntryHT* Ht = header->BuildFlatHashTable(); + + for (TagDocEntryHT::iterator tag = Ht->begin(); tag != Ht->end(); ++tag) + { + tag->second->Print(); + std::cout << std::endl; + } + + return 0; +} + + + diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 95bd1147..16adce6f 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2004/09/16 19:21:57 $ - Version: $Revision: 1.80 $ + Date: $Date: 2004/09/17 13:11:16 $ + Version: $Revision: 1.81 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -2893,7 +2893,6 @@ uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement) /** * \brief Parse pixel data from disk for multi-fragment Jpeg/Rle files * No other way so 'skip' the Data - * */ void gdcmDocument::Parse7FE0 () { @@ -2995,6 +2994,97 @@ void gdcmDocument::Parse7FE0 () } } +/** + * \brief Walk recursively the given \ref gdcmDocEntrySet, and feed + * the given hash table (\ref TagDocEntryHT) with all the + * \ref gdcmDocEntry (Dicom entries) encountered. + * This method does the job for \ref BuildFlatHashTable. + * @param builtHT Where to collect all the \ref gdcmDocEntry encountered + * when recursively walking the given set. + * @param set The structure to be traversed (recursively). + */ +void gdcmDocument::BuildFlatHashTableRecurse( TagDocEntryHT& builtHT, + gdcmDocEntrySet* set ) +{ + if (gdcmElementSet* elementSet = dynamic_cast< gdcmElementSet* > ( set ) ) + { + TagDocEntryHT* currentHT = elementSet->GetTagHT(); + for( TagDocEntryHT::const_iterator i = currentHT->begin(); + i != currentHT->end(); + ++i) + { + gdcmDocEntry* entry = i->second; + if ( gdcmSeqEntry* seqEntry = dynamic_cast(entry) ) + { + ListSQItem& items = seqEntry->GetSQItems(); + for( ListSQItem::const_iterator item = items.begin(); + item != items.end(); + ++item) + { + BuildFlatHashTableRecurse( builtHT, *item ); + } + continue; + } + builtHT[entry->GetKey()] = entry; + } + return; + } + + if (gdcmSQItem* SQItemSet = dynamic_cast< gdcmSQItem* > ( set ) ) + { + ListDocEntry& currentList = SQItemSet->GetDocEntries(); + for (ListDocEntry::iterator i = currentList.begin(); + i != currentList.end(); + ++i) + { + gdcmDocEntry* entry = *i; + if ( gdcmSeqEntry* seqEntry = dynamic_cast(entry) ) + { + ListSQItem& items = seqEntry->GetSQItems(); + for( ListSQItem::const_iterator item = items.begin(); + item != items.end(); + ++item) + { + BuildFlatHashTableRecurse( builtHT, *item ); + } + continue; + } + builtHT[entry->GetKey()] = entry; + } + + } +} + +/** + * \brief Build a \ref TagDocEntryHT (i.e. a std::map<>) from the current + * gdcmDocument. + * + * The structure used by a gdcmDocument (through \ref gdcmElementSet), + * in order to old the parsed entries of a Dicom header, is a recursive + * one. This is due to the fact that the sequences (when present) + * can be nested. Additionaly, the sequence items (represented in + * gdcm as \ref gdcmSQItem) add an extra complexity to the data + * structure. Hence, a gdcm user whishing to visit all the entries of + * a Dicom header will need to dig in the gdcm internals (which + * implies exposing all the internal data structures to the API). + * In order to avoid this burden to the user, \ref BuildFlatHashTable + * recursively builds a temporary hash table, which olds all the + * Dicom entries in a flat structure (a \ref TagDocEntryHT i.e. a + * std::map<>). + * \warning Of course there is NO integrity constrain between the + * returned \ref TagDocEntryHT and the \ref gdcmElemenSet used + * to build it. Hence if the underlying \ref gdcmElemenSet is + * altered, then it is the caller responsability to invoke + * \ref BuildFlatHashTable again... + * @return The flat std::map<> we juste build. + */ +TagDocEntryHT* gdcmDocument::BuildFlatHashTable() +{ + TagDocEntryHT* FlatHT = new TagDocEntryHT; + BuildFlatHashTableRecurse( *FlatHT, this ); + return FlatHT; +} + /** diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index 8e63544c..e7518c66 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2004/09/16 06:48:00 $ - Version: $Revision: 1.37 $ + Date: $Date: 2004/09/17 13:11:16 $ + Version: $Revision: 1.38 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -197,6 +197,7 @@ public: gdcmBinEntry* GetBinEntryByNumber(uint16_t group, uint16_t element); void LoadDocEntrySafe(gdcmDocEntry* entry); + TagDocEntryHT* BuildFlatHashTable(); private: // Read @@ -235,6 +236,9 @@ private: gdcmDocEntry* ReadNextDocEntry(); uint32_t GenerateFreeTagKeyInGroup(uint16_t group); + void BuildFlatHashTableRecurse( TagDocEntryHT& builtHT, + gdcmDocEntrySet* set ); + public: // Accessors: diff --git a/src/gdcmElementSet.cxx b/src/gdcmElementSet.cxx index ee6d9658..88547c87 100644 --- a/src/gdcmElementSet.cxx +++ b/src/gdcmElementSet.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmElementSet.cxx,v $ Language: C++ - Date: $Date: 2004/09/16 19:21:57 $ - Version: $Revision: 1.19 $ + Date: $Date: 2004/09/17 13:11:16 $ + Version: $Revision: 1.20 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -69,16 +69,12 @@ void gdcmElementSet::Print(std::ostream & os) { gdcmDocEntry* entry = i->second; entry->Print(os); - bool PrintEndLine = true; if ( gdcmSeqEntry* seqEntry = dynamic_cast(entry) ) { - (void)seqEntry; //not used - PrintEndLine = false; - } - if( PrintEndLine ) - { - os << std::endl; + // Avoid the newline for a sequence: + continue; } + os << std::endl; } } diff --git a/src/gdcmElementSet.h b/src/gdcmElementSet.h index df2f32a8..0c58214d 100644 --- a/src/gdcmElementSet.h +++ b/src/gdcmElementSet.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmElementSet.h,v $ Language: C++ - Date: $Date: 2004/09/10 14:32:04 $ - Version: $Revision: 1.15 $ + Date: $Date: 2004/09/17 13:11:16 $ + Version: $Revision: 1.16 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -45,18 +45,23 @@ public: virtual void Print(std::ostream &os = std::cout); virtual void Write(FILE *fp, FileType filetype); - /// Accessor to \ref gdcmElementSet::TagHT + /// Accessor to \ref TagHT // Do not expose this to user (public API) ! // I re-add it temporaryly JPRx TagDocEntryHT &GetEntry() { return TagHT; }; + protected: // Variables /// Hash Table (map), to provide fast access TagDocEntryHT TagHT; private: - //friend class gdcmDicomDir; + /// Just for following ::GetTagHT() + friend class gdcmDocument; + + /// Accessor to \ref TagHT + TagDocEntryHT* GetTagHT() { return &TagHT; }; }; //----------------------------------------------------------------------------- -- 2.45.1