X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmHeader.cxx;h=8096eb16503fd2d30f4162095497756d87be819b;hb=279aed8cb3483318205a8b652e05457a7fc94dec;hp=f0fdcf33d2e2ba2fdd5d2d878798ad6dd3ab8336;hpb=0e82725d64f17545e782c18039ced7ea898f8cad;p=gdcm.git diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index f0fdcf33..8096eb16 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -1,34 +1,36 @@ // gdcmHeader.cxx //----------------------------------------------------------------------------- -#include -#include -#include // for isalpha -#include - #include "gdcmHeader.h" +#include "gdcmGlobal.h" #include "gdcmUtil.h" #include "gdcmDebug.h" #include "gdcmTS.h" +#include + //----------------------------------------------------------------------------- // Constructor / Destructor /** - * \ingroup gdcmHeader * \brief Constructor - * @param InFilename name of the file whose header we want to analyze - * @param exception_on_error whether we want to throw an exception or not - * @param enable_sequences = true to allow the header - * to be parsed *inside* the SeQuences, - * when they have an actual length - * @param ignore_shadow = true if user wants to skip shadow groups - * during parsing, to save memory space + * @param InFilename name of the file whose header we want to analyze + * @param exception_on_error whether we want to throw an exception or not + * @param enable_sequences = true to allow the header + * to be parsed *inside* the SeQuences, when they have an actual length + * @param ignore_shadow = true if user wants to skip shadow groups + * during parsing, to save memory space */ gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error, bool enable_sequences, - bool ignore_shadow): + 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 @@ -41,29 +43,139 @@ gdcmHeader::gdcmHeader(const char *InFilename, // This IS the right place for the code - std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200); - if ( ImageLocation == GDCM_UNFOUND ) { // Image Location - GrPixel = 0x7fe0; // default value - } else { - GrPixel = (guint16) atoi( ImageLocation.c_str() ); - } - if (GrPixel == 0xe07f) // sometimes Image Location value doesn't follow - GrPixel = 0x7fe0; // the supposed processor endianity. - // see gdcmData/cr172241.dcm - if (GrPixel != 0x7fe0) - // This is a kludge for old dirty Philips imager. - NumPixel = 0x1010; - else - NumPixel = 0x0010; - - TagKey key = gdcmDictEntry::TranslateToKey(GrPixel, NumPixel); - countGrPixel = GetEntry().count(key); + std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200); + if ( ImageLocation == GDCM_UNFOUND ) { // Image Location + GrPixel = 0x7fe0; // default value + } else { + GrPixel = (guint16) atoi( ImageLocation.c_str() ); + } + if (GrPixel == 0xe07f) // sometimes Image Location value doesn't follow + GrPixel = 0x7fe0; // the supposed processor endianity. + // see gdcmData/cr172241.dcm + if (GrPixel != 0x7fe0) + // This is a kludge for old dirty Philips imager. + NumPixel = 0x1010; + else + NumPixel = 0x0010; + + 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 << " "; + + // GDCM_DEBUG + // 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) { +#ifdef GDCM_DEBUG + std::cout << "Kaie ! Kaie! SQ Stack Overflow" << std::endl; +#endif //GDCM_DEBUG + return; + } +#ifdef GDCM_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' + +#ifdef GDCM_DEBUG + std::cout << "fffe,e0dd : depile" << std::endl; +#endif //GDCM_DEBUG + + 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) { +#ifdef GDCM_DEBUG + std::cout << "totalSeQlength == 0xffffffff" << std::endl; +#endif //GDCM_DEBUG + } else { +#ifdef GDCM_DEBUG + std::cout << "alrdyPseLgt:" + << pile[top].alreadyParsedlength << " totSeQlgt: " + << pile[top].totalSQlength << " curPseLgt: " + << currentParsedlength + << std::endl; +#endif //GDCM_DEBUG + while (pile[top].alreadyParsedlength==pile[top].totalSQlength) { +#ifdef GDCM_DEBUG + std::cout << " \n<<<<<< On depile niveau " << top + << " \n" << std::endl; +#endif //GDCM_DEBUG + (*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 + +#ifdef GDCM_DEBUG + std::cout << pile[top].alreadyParsedlength << " " + << pile[top].totalSQlength << " " + << currentParsedlength + << std::endl; +#endif //GDCM_DEBUG + } + if (top == -1) { + currentParsedlength = 0; + break; + } + } + } + } + } // end : 'inside a SeQuence' + } +#ifdef GDCM_DEBUG + for (int k=0; k<(*i)->GetSQDepthLevel();k++) { + std::cout << tab; + } + (*i)->SetPrintLevel(2); + (*i)->Print(); +#endif //GDCM_DEBUG + } // end for } /** - * \ingroup gdcmHeader * \brief Constructor - * @param exception_on_error whether we want to throw an exception or not + * @param exception_on_error whether we want to throw an exception or not */ gdcmHeader::gdcmHeader(bool exception_on_error) : gdcmParser(exception_on_error) @@ -81,6 +193,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 @@ -445,7 +608,10 @@ size_t gdcmHeader::GetPixelOffset(void) { // pb : sometimes , (0x0088,0x0200) exists, but doesn't contain *anything* // see gdcmData/MxTwinLossLess.dcm ... - //std::string icone = GetEntryByNumber(0x0088,0x0200); //icone image sequence + /** + * \todo Clean me + *std::string icone = GetEntryByNumber(0x0088,0x0200); //icone image sequence + */ IterHT it = GetHeaderEntrySameNumber(GrPixel,NumPixel); TagKey key = gdcmDictEntry::TranslateToKey(GrPixel,NumPixel); @@ -458,9 +624,11 @@ size_t gdcmHeader::GetPixelOffset(void) { if (PixelElement) { return PixelElement->GetOffset(); } else { -/* std::cout << "Big trouble : Pixel Element (" +#ifdef GDCM_DEBUG + std::cout << "Big trouble : Pixel Element (" << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" - << std::endl; */ + << std::endl; +#endif //GDCM_DEBUG return 0; } } @@ -487,9 +655,11 @@ size_t gdcmHeader::GetPixelAreaLength(void) { if (PixelElement) { return PixelElement->GetLength(); } else { -/* std::cout << "Big trouble : Pixel Element (" +#ifdef GDCM_DEBUG + std::cout << "Big trouble : Pixel Element (" << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" - << std::endl;*/ + << std::endl; +#endif //GDCM_DEBUG return 0; } } @@ -523,7 +693,9 @@ bool gdcmHeader::HasLUT(void) { return false; // Blue Palette Color Lookup Table Data if ( !GetHeaderEntryByNumber(0x0028,0x1203) ) - return false; + return false; + // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent) + // NOT taken into account, but we don't know how to use it ... return true; } @@ -576,7 +748,7 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { // if Photometric Interpretation # PALETTE COLOR, no LUT to be done if (GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") { - return NULL; + return NULL; } int lengthR, debR, nbitsR; int lengthG, debG, nbitsG; @@ -626,16 +798,16 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { GetEntryVoidAreaByNumber(0x0028,0x1203); if (!lutR || !lutG || !lutB ) { - return NULL; + return NULL; } // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT - unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) + unsigned char *LUTRGBA = new unsigned char[1024]; // 256 * 4 (R, G, B, Alpha) if (!LUTRGBA) { return NULL; } memset(LUTRGBA, 0, 1024); - // Bits Allocated + // Bits Allocated int nb; std::string str_nb = GetEntryByNumber(0x0028,0x0100); if (str_nb == GDCM_UNFOUND ) { @@ -716,17 +888,17 @@ std::string gdcmHeader::GetTransfertSyntaxName(void) { void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { std::string content1; char car[20]; - + // Assumes HeaderEntry (GrPixel, NumPixel) is unique ... - // TODO deal with multiplicity (see gdcmData/icone.dcm) + //\todo deal with multiplicity (see gdcmData/icone.dcm) sprintf(car,"%d",ImageDataSize); gdcmHeaderEntry *a = GetHeaderEntryByNumber(GrPixel, NumPixel); a->SetLength(ImageDataSize); - + ImageDataSize+=8; sprintf(car,"%d",ImageDataSize); - content1=car; + content1=car; SetEntryByNumber(content1, GrPixel, NumPixel); } @@ -747,30 +919,30 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { s1=this->GetEntryByNumber(0x0010,0x0010); s2=header.GetEntryByNumber(0x0010,0x0010); if(s1 < s2) - return(true); + return(true); else if(s1 > s2) - return(false); + return(false); else { // Patient ID s1=this->GetEntryByNumber(0x0010,0x0020); s2=header.GetEntryByNumber(0x0010,0x0020); if (s1 < s2) - return(true); + return(true); else if (s1 > s2) return(1); else { - // Study Instance UID + // Study Instance UID s1=this->GetEntryByNumber(0x0020,0x000d); s2=header.GetEntryByNumber(0x0020,0x000d); if (s1 < s2) - return(true); + return(true); else if(s1 > s2) - return(false); + return(false); else { - // Serie Instance UID + // Serie Instance UID s1=this->GetEntryByNumber(0x0020,0x000e); s2=header.GetEntryByNumber(0x0020,0x000e); if (s1 < s2) @@ -783,6 +955,36 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { return(false); } +bool gdcmHeader::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type) +{ + guint32 length = tag->GetLength(); + + // The value of a tag MUST (see the DICOM norm) be an odd number of + // bytes. When this is not the case, pad with an additional byte: + if(length%2==1) + { + tag->SetValue(tag->GetValue()+"\0"); + tag->SetLength(tag->GetReadLength()+1); + } + + WriteEntryTagVRLength(tag, _fp, type); + + // Pixels are never loaded in the element ! + // we stop writting when Pixel are processed + // FIX : we loose trailing elements (RAB, right now) + guint16 el = tag->GetElement(); + guint16 group = tag->GetGroup(); + int compte =0; + if ((group == GrPixel) && (el == NumPixel) ) { + compte++; + if (compte == countGrPixel) {// we passed *all* the GrPixel,NumPixel + return false; + } + } + WriteEntryValue(tag, _fp, type); + return true; +} + //----------------------------------------------------------------------------- // Protected @@ -805,7 +1007,7 @@ bool gdcmHeader::anonymizeHeader() { if (StudyInstanceUID !=GDCM_UNFOUND) ReplaceOrCreateByNumber(StudyInstanceUID, 0x0010, 0x0010); else - ReplaceOrCreateByNumber("anonymised", 0x0010, 0x0010); + ReplaceOrCreateByNumber(std::string("anonymised"), 0x0010, 0x0010); } // Just for fun :-( @@ -860,7 +1062,7 @@ bool gdcmHeader::anonymizeHeader() { //300a 022c DA RT Air Kerma Rate Reference Date //300e 0004 DA RT Review Date return true; - } +} //----------------------------------------------------------------------------- // Private