#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
#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
// 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 <string>
enum FileType {
Unknown = 0,
- ExplicitVR, // gdcmDicomDir are in this case
+ ExplicitVR, // gdcmDicomDir is in this case
ImplicitVR,
ACR,
ACR_LIBIDO
bool WriteDcmImplVR(const char * fileName);
bool WriteDcmExplVR(std::string fileName);
bool WriteAcr (std::string fileName);
-
+
// Body in file gdcmParse.cxx
bool ParsePixelData(void);
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
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" <<std::endl;
+
+ pile[top].totalSQlength = (*i)->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
}
/**
// 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;k<depth;k++)
+ os << tab.str();
+ }
+ (*i)->SetPrintLevel(printLevel);
+ (*i)->Print(os);
+
+ } // end for
+}
+
//-----------------------------------------------------------------------------
// Public
/// 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);
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
*/
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:
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()
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;
};
//-----------------------------------------------------------------------------
// gdcmParser.cxx
//-----------------------------------------------------------------------------
+//#define UINT32_MAX (4294967295U)
+
+
#include "gdcmParser.h"
#include "gdcmGlobal.h"
#include "gdcmUtil.h"
if ( !OpenFile(exception_on_error))
return;
- if (ParseHeader()) {
- LoadHeaderEntries();
- }
+
+ LoadHeaderEntries();
CloseFile();
wasUpdated = 0; // will be set to 1 if user adds an entry
}
}
-/**
- * \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" <<std::endl;
-
- pile[top].totalSQlength = (*i)->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;i<countSQ;i++)
- os << tab.str();
- }
- (*i)->SetPrintLevel(printLevel);
- (*i)->Print(os);
-
- } // end for
-}
-
-
/**
* \brief Prints The Dict Entries of THE public Dicom Dictionary
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();
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;
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;
// 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())
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
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)
// --------------------------------------------------------------
SetEntryByNumber(columns, 0x0028, 0x0010);
SetEntryByNumber(rows , 0x0028, 0x0011);
}
- // ----------------- End of Special Patch ----------------
+ // ----------------- End of Special Patch ----------------
+ return true;
}
/**
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);
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 *);