From: jpr Date: Wed, 28 Apr 2004 16:24:30 +0000 (+0000) Subject: 2004-04-28 Jean-Pierre Roux X-Git-Tag: Version0.5.bp~231 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=e037a39af09b4df452992e1129fa2a370171c44e;p=gdcm.git 2004-04-28 Jean-Pierre Roux * ENH add the provisional gdcmHeader::SQDepthLevel to allow SeQuence indented printing of Dicom Header * ENH merge methods gdcmParser::Parse and gdcmParser::LoadHeaderEntries into the single gdcmParser::LoadHeaderEntries for efficiency purpose Computation of SQDepthLevel is now part of gdcmHeader constructor --- diff --git a/src/gdcmCommon.h b/src/gdcmCommon.h index 2b42c8cd..0af21208 100644 --- a/src/gdcmCommon.h +++ b/src/gdcmCommon.h @@ -44,8 +44,8 @@ #else typedef unsigned short guint16; typedef unsigned int guint32; -typedef short gint16; -typedef int gint32; +typedef short gint16; +typedef int gint32; #define UINT32_MAX (4294967295U) #endif //HAVE_NO_STDINT_H #endif @@ -53,8 +53,8 @@ typedef int gint32; #ifdef _MSC_VER typedef unsigned short guint16; typedef unsigned int guint32; -typedef short gint16; -typedef int gint32; +typedef short gint16; +typedef int gint32; #define UINT32_MAX (4294967295U) #endif @@ -76,13 +76,13 @@ typedef int gint32; // Centralize information about the gdcm dictionary in only one file: #ifndef PUB_DICT_PATH -# define PUB_DICT_PATH "../Dicts/" +# define PUB_DICT_PATH "../Dicts/" #endif #define PUB_DICT_NAME "DicomV3Dict" #define PUB_DICT_FILENAME "dicomV3.dic" -#define DICT_ELEM "DicomDir.dic" -#define DICT_TS "dicomTS.dic" -#define DICT_VR "dicomVR.dic" +#define DICT_ELEM "DicomDir.dic" +#define DICT_TS "dicomTS.dic" +#define DICT_VR "dicomVR.dic" #include @@ -93,7 +93,7 @@ typedef std::string TagName; enum FileType { Unknown = 0, - ExplicitVR, // gdcmDicomDir are in this case + ExplicitVR, // gdcmDicomDir is in this case ImplicitVR, ACR, ACR_LIBIDO diff --git a/src/gdcmFile.h b/src/gdcmFile.h index da6ce949..e978703b 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -72,7 +72,7 @@ public: bool WriteDcmImplVR(const char * fileName); bool WriteDcmExplVR(std::string fileName); bool WriteAcr (std::string fileName); - + // Body in file gdcmParse.cxx bool ParsePixelData(void); diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 8c64575d..3dbcb1ac 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -28,6 +28,12 @@ gdcmHeader::gdcmHeader(const char *InFilename, bool ignore_shadow): gdcmParser(InFilename,exception_on_error,enable_sequences,ignore_shadow) { + + typedef struct { + guint32 totalSQlength; + guint32 alreadyParsedlength; + } pileElem; + // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010 // We may encounter the 'RETired' (0x0028, 0x0200) tag @@ -57,6 +63,110 @@ gdcmHeader::gdcmHeader(const char *InFilename, TagKey key = gdcmDictEntry::TranslateToKey(GrPixel, NumPixel); countGrPixel = GetEntry().count(key); + + // we set the SQ Depth of each Header Entry + + int top =-1; + int countSQ = 0; + pileElem pile[100]; // Hope embedded sequence depth is no that long ! + + int currentParsedlength = 0; + int totalElementlength; + std::ostringstream tab; + tab << " "; + + int DEBUG = 0; // Sorry; Dealing with e-film breaker images + // will (certainly) cause a lot of troubles ... + // I prefer keeping my 'trace' on . + + for (ListTag::iterator i = listEntries.begin(); + i != listEntries.end(); + ++i) { + (*i)->SetSQDepthLevel(countSQ); + if ( (*i)->GetVR() == "SQ" && (*i)->GetReadLength() != 0) { // SQ found + countSQ++; + top ++; + if ( top >= 20) { + std::cout << "Kaie ! Kaie! SQ Stack Overflow" << std::endl; + return; + } + if (DEBUG) std::cout << "\n >>>>> empile niveau " << top + << "; Lgr SeQ: " << (*i)->GetReadLength() + << "\n" <GetReadLength(); + pile[top].alreadyParsedlength = 0; + currentParsedlength = 0; + + } else { // non SQ found + + if (countSQ != 0) { // we are 'inside a SeQuence' + if ( (*i)->GetGroup()==0xfffe && (*i)->GetElement()==0xe0dd){ + // we just found 'end of SeQuence' + + if (DEBUG) + std::cout << "fffe,e0dd : depile" << std::endl; + currentParsedlength += 8; // gr:2 elem:2 vr:2 lgt:2 + countSQ --; + top --; + pile[top].alreadyParsedlength += currentParsedlength; + } else { + // we are on a 'standard' elem + // or a Zero-length SeQuence + + totalElementlength = (*i)->GetFullLength(); + currentParsedlength += totalElementlength; + pile[top].alreadyParsedlength += totalElementlength; + + if (pile[top].totalSQlength == 0xffffffff) { + if (DEBUG) + std::cout << "totalSeQlength == 0xffffffff" + << std::endl; + } else { + if (DEBUG) + std::cout << "alrdyPseLgt:" + << pile[top].alreadyParsedlength << " totSeQlgt: " + << pile[top].totalSQlength << " curPseLgt: " + << currentParsedlength + << std::endl; + while (pile[top].alreadyParsedlength==pile[top].totalSQlength) { + + if (DEBUG) + std::cout << " \n<<<<<< On depile niveau " << top + << " \n" << std::endl; + (*i)->SetSQDepthLevel(countSQ); + currentParsedlength = pile[top].alreadyParsedlength; + countSQ --; + top --; + if (top >=0) { + + pile[top].alreadyParsedlength += currentParsedlength +12; + // 12 : length of 'SQ embedded' SQ element + currentParsedlength += 8; // gr:2 elem:2 vr:2 lgt:2 + + if (DEBUG) + std::cout << pile[top].alreadyParsedlength << " " + << pile[top].totalSQlength << " " + << currentParsedlength + << std::endl; + } + if (top == -1) { + currentParsedlength = 0; + break; + } + } + } + } + } // end : 'inside a SeQuence' + } + if (DEBUG) { + for (int k=0; k<(*i)->GetSQDepthLevel();k++) { + cout << tab; + } + (*i)->SetPrintLevel(2); + (*i)->Print(); + } + } // end for } /** @@ -79,6 +189,57 @@ gdcmHeader::~gdcmHeader (void) { // Print // see gdcmParser.cxx + +/** + * \ingroup gdcmHeader + * \brief Prints the Header Entries (Dicom Elements) + * from the chained list + * and skips the elements belonging to a SeQuence + * @return + */ +void gdcmHeader::PrintEntryNoSQ(std::ostream & os) { + + int depth; + for (ListTag::iterator i = listEntries.begin(); + i != listEntries.end(); + ++i) + { + depth= (*i)->GetSQDepthLevel(); + if ( depth != 0 /*|| (*i)->GetVR() =="SQ" */){ + continue; + } + (*i)->SetPrintLevel(printLevel); + (*i)->Print(os); + } +} + +/** + * \ingroup gdcmHeader + * \brief Prints the Header Entries (Dicom Elements) + * from the chained list + * and indents the elements belonging to any SeQuence + * \warning : will be removed + * @return + */ +void gdcmHeader::PrintEntryNiceSQ(std::ostream & os) { + std::ostringstream tab; + tab << " "; + + int depth; + for (ListTag::iterator i = listEntries.begin(); + i != listEntries.end(); + ++i) { + depth= (*i)->GetSQDepthLevel(); + if (depth != 0) { + for (int k=0;kSetPrintLevel(printLevel); + (*i)->Print(os); + + } // end for +} + //----------------------------------------------------------------------------- // Public diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index a2cece0a..273305c1 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -45,6 +45,7 @@ protected: /// the image itself. Hence the tag (GrPixel,NumPixel) might appear /// several times. countGrPixel is the number of occurences of the /// tag of pixels (i.e. (GrPixel,NumPixel)) contained in the header. + /// TODO : will be dealt with SQ tree-like stucture int countGrPixel; public: gdcmHeader(bool exception_on_error = false); @@ -140,8 +141,11 @@ public: bool operator<(gdcmHeader &header); bool WriteEntry(gdcmHeaderEntry *tag,FILE *_fp,FileType type); - - + + + virtual void PrintEntryNoSQ (std::ostream &os = std::cout); + virtual void PrintEntryNiceSQ(std::ostream &os = std::cout); + protected: //CLEANME int write(std::ostream&); //CLEANME int anonymize(std::ostream&);//FIXME: anonymize should be a friend diff --git a/src/gdcmHeaderEntry.h b/src/gdcmHeaderEntry.h index 8210809b..e27892ca 100644 --- a/src/gdcmHeaderEntry.h +++ b/src/gdcmHeaderEntry.h @@ -193,7 +193,15 @@ public: */ void SetPrintLevel(int level) { printLevel = level; }; void Print (std::ostream & os = std::cout); - + + /** + * \ingroup gdcmHeaderEntry + * \brief Gets the depth level of a Dicom Header Entry + * embedded in a SeQuence + */ + inline int GetSQDepthLevel(void) + { return (SQDepthLevel); }; + guint32 GetFullLength(void); private: @@ -202,6 +210,14 @@ private: friend class gdcmHeader; + /** + * \ingroup gdcmHeaderEntry + * \brief Sets the depth level of a Dicom Header Entry + * embedded in a SeQuence + */ + inline void SetSQDepthLevel(int depthLevel) + { SQDepthLevel = depthLevel; }; + // Variables gdcmDictEntry *entry; /// Updated from ReadLength, by FixFoungLentgh() @@ -234,6 +250,9 @@ private: size_t Offset; /// How many details are to be printed (value : 0,1,2) int printLevel; + + /// Gives the depth level of elements inside SeQuences + int SQDepthLevel; }; //----------------------------------------------------------------------------- diff --git a/src/gdcmParser.cxx b/src/gdcmParser.cxx index 327a3753..acd248eb 100644 --- a/src/gdcmParser.cxx +++ b/src/gdcmParser.cxx @@ -1,5 +1,8 @@ // gdcmParser.cxx //----------------------------------------------------------------------------- +//#define UINT32_MAX (4294967295U) + + #include "gdcmParser.h" #include "gdcmGlobal.h" #include "gdcmUtil.h" @@ -68,9 +71,8 @@ gdcmParser::gdcmParser(const char *inFilename, if ( !OpenFile(exception_on_error)) return; - if (ParseHeader()) { - LoadHeaderEntries(); - } + + LoadHeaderEntries(); CloseFile(); wasUpdated = 0; // will be set to 1 if user adds an entry @@ -121,147 +123,6 @@ void gdcmParser::PrintEntry(std::ostream & os) { } } -/** - * \ingroup gdcmParser - * \brief Prints the Header Entries (Dicom Elements) - * from the chained list - * and skips the elements belonging to a 'no length' SeQuence - * @return - */ -void gdcmParser::PrintEntryNoSQ(std::ostream & os) { - int countSQ = 0; - for (ListTag::iterator i = listEntries.begin(); - i != listEntries.end(); - ++i) - { - if ( (*i)->GetVR() == "SQ"){ - countSQ ++; - } - - if ( (*i)->GetGroup() == 0xfffe && (*i)->GetElement() == 0xe0dd){ - countSQ --; - continue; - } - - if (countSQ == 0) { - (*i)->SetPrintLevel(printLevel); - (*i)->Print(os); - } - } -} - -/** - * \ingroup gdcmParser - * \brief Prints the Header Entries (Dicom Elements) - * from the chained list - * and indents the elements belonging to any SeQuence - * \warning : will be removed - * @return - */ -void gdcmParser::PrintEntryNiceSQ(std::ostream & os) { - pileElem pile[50]; // Hope embedded sequence depth is no more than 50 - int top =-1; - int countSQ = 0; - int currentParsedlength = 0; - int totalElementlength; - std::ostringstream tab; - tab << " "; - - int DEBUG = 0; // Sorry; Dealing with e-film breaker images - // will (certainly) cause a lot of troubles ... - // I prefer keeping my 'trace' on . - - for (ListTag::iterator i = listEntries.begin(); - i != listEntries.end(); - ++i) { - if ( (*i)->GetVR() == "SQ" && (*i)->GetReadLength() != 0) { // SQ found - countSQ++; - top ++; - if ( top >= 50) { - std::cout << "Kaie ! Kaie! SQ stack overflow" << std::endl; - return; - } - if (DEBUG) std::cout << "\n >>>>> empile niveau " << top - << "; Lgr SeQ: " << (*i)->GetReadLength() - << "\n" <GetReadLength(); - pile[top].alreadyParsedlength = 0; - currentParsedlength = 0; - - } else { // non SQ found - - if (countSQ != 0) { // we are 'inside a SeQuence' - if ( (*i)->GetGroup()==0xfffe && (*i)->GetElement()==0xe0dd){ - // we just found 'end of SeQuence' - - if (DEBUG) - std::cout << "fffe,e0dd : depile" << std::endl; - currentParsedlength += 8; // gr:2 elem:2 vr:2 lgt:2 - countSQ --; - top --; - pile[top].alreadyParsedlength += currentParsedlength; - } else { - // we are on a 'standard' elem - // or a Zero-length SeQuence - - totalElementlength = (*i)->GetFullLength(); - currentParsedlength += totalElementlength; - pile[top].alreadyParsedlength += totalElementlength; - - if (pile[top].totalSQlength == 0xffffffff) { - if (DEBUG) - std::cout << "totalSeQlength == 0xffffffff" - << std::endl; - } else { - if (DEBUG) - std::cout << "alrdyPseLgt:" - << pile[top].alreadyParsedlength << " totSeQlgt: " - << pile[top].totalSQlength << " curPseLgt: " - << currentParsedlength - << std::endl; - while (pile[top].alreadyParsedlength==pile[top].totalSQlength) { - - if (DEBUG) - std::cout << " \n<<<<<< On depile niveau " << top - << "\n" << std::endl; - - currentParsedlength = pile[top].alreadyParsedlength; - countSQ --; - top --; - if (top >=0) { - - pile[top].alreadyParsedlength += currentParsedlength +12; - // 12 : length of 'SQ embedded' SQ element - currentParsedlength += 8; // gr:2 elem:2 vr:2 lgt:2 - - if (DEBUG) - std::cout << pile[top].alreadyParsedlength << " " - << pile[top].totalSQlength << " " - << currentParsedlength - << std::endl; - } - if (top == -1) { - currentParsedlength = 0; - break; - } - } - } - } - } // end : 'inside a SeQuence' - } - - if (countSQ != 0) { - for (int i=0;iSetPrintLevel(printLevel); - (*i)->Print(os); - - } // end for -} - - /** * \brief Prints The Dict Entries of THE public Dicom Dictionary @@ -1247,7 +1108,7 @@ bool gdcmParser::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type) bool gdcmParser::WriteEntries(FILE *_fp,FileType type) { - // TODO (?) tester les echecs en ecriture (apres chaque fwrite) + // TODO (?) check write failures (after *each* fwrite) for (ListTag::iterator tag2=listEntries.begin(); tag2 != listEntries.end(); @@ -1260,13 +1121,10 @@ bool gdcmParser::WriteEntries(FILE *_fp,FileType type) if ((*tag2)->GetElement() %2) // Ignore the "shadow" groups continue; - if ((*tag2)->GetVR() == "SQ" ) - // For the time being sequences are simply ignored - // TODO : find a trick not to *skip* the SeQuences ! - continue; - if ((*tag2)->GetGroup() == 0xfffe ) - // Ignore the documented delimiter + if ((*tag2)->GetVR() == "SQ" ) // ignore Sequences continue; + if ((*tag2)->GetSQDepthLevel() != 0) // Not only ignore the SQ element + continue; } if (! WriteEntry(*tag2,_fp,type) ) return false; @@ -1299,13 +1157,10 @@ void gdcmParser::WriteEntriesDeprecated(FILE *_fp,FileType type) { tag2 != tagHT.end(); ++tag2){ if ( type == ACR ){ - if ((*tag2->second).GetGroup() < 0x0008) continue; // ignore pure DICOM V3 groups - if ((*tag2->second).GetElement() %2) continue; // ignore shadow groups - if ((*tag2->second).GetVR() == "SQ" ) continue; // ignore Sequences - // TODO : find a trick to *skip* the SeQuences ! - // Not only ignore the SQ element - // --> will be done with the next organization - if ((*tag2->second).GetGroup() == 0xfffe ) continue; // ignore delimiters + if ((*tag2->second).GetGroup() < 0x0008) continue; // ignore pure DICOM V3 groups + if ((*tag2->second).GetElement() %2) continue; // ignore shadow groups + if ((*tag2->second).GetVR() == "SQ" ) continue; // ignore Sequences + if ((*tag2->second).GetSQDepthLevel() != 0) continue; // Not only ignore the SQ element } if ( ! WriteEntry(tag2->second,_fp,type)) break; @@ -1375,10 +1230,10 @@ guint16 gdcmParser::UnswapShort(guint16 a) { // Private /** * \ingroup gdcmParser - * \brief Parses the header of the file but WITHOUT loading element values. + * \brief Parses the header of the file and load element values. * @return false if file is not ACR-NEMA / DICOM */ -bool gdcmParser::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { +bool gdcmParser::LoadHeaderEntries(bool exception_on_error) throw(gdcmFormatError) { (void)exception_on_error; rewind(fp); if (!CheckSwap()) @@ -1389,28 +1244,13 @@ bool gdcmParser::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { SkipHeaderEntry(newHeaderEntry); if ( (ignoreShadow==0) || (newHeaderEntry->GetGroup()%2) == 0) { AddHeaderEntry(newHeaderEntry); + LoadHeaderEntry(newHeaderEntry); } } - return true; -} - -/** - * \ingroup gdcmParser - * \brief Loads the element values of all the Header Entries pointed in the - * public Chained List. - */ -void gdcmParser::LoadHeaderEntries(void) { - rewind(fp); - for (ListTag::iterator i = GetListEntry().begin(); - i != GetListEntry().end(); - ++i) - { - LoadHeaderEntry(*i); - } - rewind(fp); - // Load 'non string' values + // Load 'non string' values + std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004); if( PhotometricInterpretation == "PALETTE COLOR " ) { LoadEntryVoidArea(0x0028,0x1200); // gray LUT @@ -1422,7 +1262,7 @@ void gdcmParser::LoadHeaderEntries(void) { LoadEntryVoidArea(0x0028,0x1222); // Segmented Green Palette Color LUT Data LoadEntryVoidArea(0x0028,0x1223); // Segmented Blue Palette Color LUT Data } - //FIXME : how to use it? + //FIXME later : how to use it? LoadEntryVoidArea(0x0028,0x3006); //LUT Data (CTX dependent) // -------------------------------------------------------------- @@ -1442,7 +1282,8 @@ void gdcmParser::LoadHeaderEntries(void) { SetEntryByNumber(columns, 0x0028, 0x0010); SetEntryByNumber(rows , 0x0028, 0x0011); } - // ----------------- End of Special Patch ---------------- + // ----------------- End of Special Patch ---------------- + return true; } /** diff --git a/src/gdcmParser.h b/src/gdcmParser.h index 1b07a174..ef75bced 100644 --- a/src/gdcmParser.h +++ b/src/gdcmParser.h @@ -109,9 +109,8 @@ public: virtual void Print (std::ostream &os = std::cout) {PrintEntry(os);}; virtual void PrintEntry (std::ostream &os = std::cout); - virtual void PrintEntryNoSQ (std::ostream &os = std::cout); + // the 2 following will be merged - virtual void PrintEntryNiceSQ(std::ostream &os = std::cout); virtual void PrintPubDict (std::ostream &os = std::cout); virtual void PrintShaDict (std::ostream &os = std::cout); @@ -199,9 +198,8 @@ protected: private: // Read - bool ParseHeader(bool exception_on_error = false) throw(gdcmFormatError); + bool LoadHeaderEntries(bool exception_on_error = false) throw(gdcmFormatError); - void LoadHeaderEntries (void); void LoadHeaderEntry (gdcmHeaderEntry *); void FindHeaderEntryLength(gdcmHeaderEntry *); void FindHeaderEntryVR (gdcmHeaderEntry *);