From: jpr Date: Thu, 15 Jan 2004 16:03:10 +0000 (+0000) Subject: Write uses now chained list instead of (now unuable for this purpose) H Table X-Git-Tag: Version0.4~98 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=49484255e3674c038cbf2259a8c3325c0039cd41;p=gdcm.git Write uses now chained list instead of (now unuable for this purpose) H Table --- diff --git a/src/gdcmDictEntry.h b/src/gdcmDictEntry.h index 5c6abff3..115ed7ac 100644 --- a/src/gdcmDictEntry.h +++ b/src/gdcmDictEntry.h @@ -7,6 +7,8 @@ //----------------------------------------------------------------------------- /* + * \defgroup gdcmDictEntry + * \brief * the gdcmDictEntry in an element contained by the gdcmDict. * It contains : * - the key referenced by the DICOM norm or the constructor (for private keys) diff --git a/src/gdcmDictSet.h b/src/gdcmDictSet.h index 6588e53b..5ca9cad5 100644 --- a/src/gdcmDictSet.h +++ b/src/gdcmDictSet.h @@ -28,24 +28,24 @@ public: // TODO Swig int LoadDictFromName(std::string filename); // TODO Swig int LoadAllDictFromDirectory(std::string DirectoryName); // TODO Swig std::string* GetAllDictNames(); - gdcmDictSet(void); - ~gdcmDictSet(void); + gdcmDictSet(void); + ~gdcmDictSet(void); - void Print(std::ostream& os); + void Print(std::ostream& os); std::list * GetPubDictTagNames(void); std::map >* GetPubDictTagNamesByCategory(void); - void LoadDictFromFile(std::string FileName, DictKey Name); + void LoadDictFromFile(std::string FileName, DictKey Name); gdcmDict* GetDict(DictKey DictName); - gdcmDict* GetDefaultPubDict(void); + gdcmDict* GetDefaultPubDict(void); static std::string BuildDictPath(void); protected: - bool AppendDict(gdcmDict* NewDict,DictKey Name); + bool AppendDict(gdcmDict* NewDict,DictKey Name); private: /// Hash table of all dictionaries contained in this gdcmDictSet diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index 4ead10ad..e94c9c4f 100644 --- a/src/gdcmFile.cxx +++ b/src/gdcmFile.cxx @@ -42,9 +42,7 @@ gdcmFile::gdcmFile(gdcmHeader *header) { * This avoid a double parsing of public part of the header when * one sets an a posteriori shadow dictionary (efficiency can be * seen as a side effect). - * * @param filename file to be opened for parsing - * * @return */ gdcmFile::gdcmFile(std::string & filename) { @@ -65,11 +63,9 @@ gdcmFile::gdcmFile(const char * filename) { /** * \ingroup gdcmFile - * \brief Destructor dedicated to writing a new DICOMV3 part10 compliant - * file (see SetFileName, SetDcmTag and Write) + * \brief canonical destructor * \Note If the gdcmHeader is created by the gdcmFile, it is destroyed * by the gdcmFile - * * */ gdcmFile::~gdcmFile(void) { if(SelfHeader) @@ -93,13 +89,11 @@ gdcmHeader *gdcmFile::GetHeader(void) { /** * \ingroup gdcmFile - * \brief calcule la longueur (in bytes) A ALLOUER pour recevoir les - * pixels de l'image ou DES images dans le cas d'un multiframe - * - * ATTENTION : il ne s'agit PAS de la longueur du groupe des Pixels - * (dans le cas d'images compressees, elle n'a pas de sens). - * - * @return longueur a allouer + * \brief computes the length (in bytes) to ALLOCATE to receive the + * image(s) pixels (multiframes taken into account) + * \warning : it is NOT the group 7FE0 length + * (no interest for compressed images). + * @return length to allocate */ void gdcmFile::SetPixelDataSizeFromHeader(void) { // see PS 3.3-2003 : C.7.6.3.2.1 @@ -166,7 +160,7 @@ size_t gdcmFile::GetImageDataSize(void) { * \ the pixel data represented in this file, when user DOESN'T want * \ to get RGB pixels image when it's stored as a PALETTE COLOR image * \ - the (vtk) user is supposed to know how deal with LUTs - - * \ warning to be used with GetImagePixelsRaw() + * \warning to be used with GetImagePixelsRaw() * @return The size of pixel data in bytes. */ size_t gdcmFile::GetImageDataSizeRaw(void) { @@ -250,19 +244,15 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { // from grey Pixels (?!) // and Gray Lut (!?!) // or Segmented xxx Palette Color Lookup Table Data and so on - - // Well . I'll wait till I find such an image - - // Oops! I get one (gdcm-US-ALOKA-16.dcm) - // No idea how to manage it - // It seems that *no Dicom Viewer* has any idea :-( - // Segmented xxx Palette Color are *more* than 65535 long ?!? + + // Oops! I get one (gdcm-US-ALOKA-16.dcm) + // No idea how to manage such an image + // It seems that *no Dicom Viewer* has any idea :-( + // Segmented xxx Palette Color are *more* than 65535 long ?!? std::string rgb= "MONOCHROME1 "; // Photometric Interpretation - Header->SetPubEntryByNumber(rgb,0x0028,0x0004); - - } - + Header->SetPubEntryByNumber(rgb,0x0028,0x0004); + } // TODO : Drop Palette Color out of the Header? return lgrTotale; } @@ -325,23 +315,21 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { (void)ReadPixelData(destination); - // Nombre de Bits Alloues pour le stockage d'un Pixel + // Number of Bits Allocated for storing a Pixel str_nb = Header->GetPubEntryByNumber(0x0028,0x0100); if (str_nb == GDCM_UNFOUND ) { nb = 16; } else { nb = atoi(str_nb.c_str() ); - } - - // Nombre de Bits Utilises + } + // Number of Bits actually used str_nbu=Header->GetPubEntryByNumber(0x0028,0x0101); if (str_nbu == GDCM_UNFOUND ) { nbu = nb; } else { nbu = atoi(str_nbu.c_str() ); - } - - // Position du Bit de Poids Fort + } + // High Bit Position str_highBit=Header->GetPubEntryByNumber(0x0028,0x0102); if (str_highBit == GDCM_UNFOUND ) { highBit = nb - 1; @@ -358,7 +346,7 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { signe = atoi(str_signe.c_str() ); } - // re arange bytes inside the integer + // re arange bytes inside the integer (processor endianity) if (nb != 8) SwapZone(destination, Header->GetSwapCode(), lgrTotale, nb); @@ -397,9 +385,9 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { return (size_t)0; } } - +// DO NOT remove this code commented out. +// Nobody knows what's expecting you ... // Just to 'see' what was actually read on disk :-( -// Some troubles expected // FILE * f2; // f2 = fopen("SpuriousFile.raw","wb"); // fwrite(destination,lgrTotale,1,f2); @@ -444,11 +432,9 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { // Warning : YBR_FULL_422 acts as RGB // : we need to make RGB Pixels from Planes Y,cB,cR - // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf - // for code optimisation // to see the tricks about YBR_FULL, YBR_FULL_422, - // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : + // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf // and be *very* affraid // @@ -460,11 +446,13 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { unsigned char * a = (unsigned char *)destination; unsigned char * b = a + l; unsigned char * c = b + l; - double R,G,B; // TODO : Replace by the 'well known' // integer computation counterpart + // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + // for code optimisation + for (int i=0;iSetImageDataSize(ExpectedSize); @@ -560,8 +545,9 @@ bool gdcmFile::SetImageData(void * inData, size_t ExpectedSize) { * Ca sera à l'utilisateur d'appeler son Reader correctement * (Equivalent a IdImaWriteRawFile) * - * @param fileName - * @return + * @param fileName name of the file to be created + * (any already existing file is over written) + * @return false if write fails */ bool gdcmFile::WriteRawData (std::string fileName) { @@ -583,8 +569,9 @@ bool gdcmFile::WriteRawData (std::string fileName) { * Ca fonctionnera correctement (?) sur processeur Intel * (Equivalent a IdDcmWrite) * - * @param fileName - * @return int acts as a boolean + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails */ bool gdcmFile::WriteDcmImplVR (std::string fileName) { @@ -594,8 +581,9 @@ bool gdcmFile::WriteDcmImplVR (std::string fileName) { /** * \ingroup gdcmFile * \brief - * @param fileName - * @return int acts as a boolean + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails */ bool gdcmFile::WriteDcmImplVR (const char* fileName) { @@ -605,8 +593,9 @@ bool gdcmFile::WriteDcmImplVR (const char* fileName) { /** * \ingroup gdcmFile * \brief - * @param fileName - * @return int acts as a boolean + * @param fileName name of the file to be created + * (any already existing file is over written) + * @return false if write fails */ bool gdcmFile::WriteDcmExplVR (std::string fileName) { @@ -618,14 +607,15 @@ bool gdcmFile::WriteDcmExplVR (std::string fileName) { * \brief Ecrit au format ACR-NEMA sur disque l'entete et les pixels * (a l'attention des logiciels cliniques * qui ne prennent en entrée QUE des images ACR ... - * \warning si un header DICOM est fourni en entree, - * les groupes < 0x0008 et les groupes impairs sont ignores) - * \warning Aucun test n'est fait sur l'"Endiannerie" du processeur. + * \warning if a DICOM_V3 header is supplied, + * groups < 0x0008 and shadow groups are ignored) + * \warning NO TEST is performed on processor "Endiannerie". * Ca fonctionnera correctement (?) sur processeur Intel * (Equivalent a IdDcmWrite) * - * @param fileName - * @return int acts as a boolean + * @param fileName name of the file to be created + * (any already existing file is over written) + * @return false if write fails */ bool gdcmFile::WriteAcr (std::string fileName) { @@ -637,10 +627,10 @@ bool gdcmFile::WriteAcr (std::string fileName) { /** * \ingroup gdcmFile * - * @param FileName - * @param type - * - * @return int acts as a boolean +* @param fileName name of the file to be created + * (any already existing file is over written) + * @param type file type (ExplicitVR, ImplicitVR, ...) + * @return false if write fails */ bool gdcmFile::WriteBase (std::string FileName, FileType type) { @@ -728,7 +718,7 @@ if(nb == 16) break; default: - printf("valeur de SWAP (16 bits) not allowed : %d\n", swap); + printf("SWAP value (16 bits) not allowed : %d\n", swap); } if( nb == 32 ) @@ -769,7 +759,7 @@ if( nb == 32 ) break; default: - printf(" SWAP value (32 bits) not allowed : %d\n", swap); + printf("SWAP value (32 bits) not allowed : %d\n", swap); } return; } @@ -809,9 +799,9 @@ bool gdcmFile::ReadPixelData(void* destination) { fread(&b2,1,1,fp); //Two steps is necessary to please VC++ *pdestination++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); - /* A */ /* B */ /* D */ + /* A */ /* B */ /* D */ *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); - /* F */ /* C */ /* E */ + /* F */ /* C */ /* E */ // Troubles expected on Big-Endian processors ? } diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 49933b68..581c605f 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -57,6 +57,7 @@ gdcmHeader::gdcmHeader(const char *InFilename, if ( !OpenFile(exception_on_error)) return; ParseHeader(); + wasUpdated = 0; // will be set to 1 if user adds an entry LoadHeaderEntries(); CloseFile(); } @@ -2357,7 +2358,7 @@ gdcmHeaderEntry* gdcmHeader::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) * \note A fake TagKey is generated so the PubDict can keep it's coherence. * @param NewTagName The name to be given to this new tag. * @param VR The Value Representation to be given to this new tag. - * @ return The newly hand crafted Element Value. + * @return The newly hand crafted Element Value. */ gdcmHeaderEntry* gdcmHeader::NewManualHeaderEntryToPubDict(std::string NewTagName, std::string VR) { diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index 58cd9a20..7decd121 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -19,6 +19,8 @@ typedef std::map VRHT; // Value Representation Hash Table //----------------------------------------------------------------------------- /* + * \defgroup gdcmHedaer + * \brief * The purpose of an instance of gdcmHeader is to act as a container of * all the DICOM elements and their corresponding values (and * additionaly the corresponding DICOM dictionary entry) of the header @@ -105,7 +107,7 @@ public: bool SetPubEntryLengthByNumber(guint32 lgr, guint16 group, guint16 element); inline ListTag & GetPubListEntry(void) { return PubEntrySet.GetListEntry();}; - inline TagHeaderEntryHT & GetPubEntry(void) { return PubEntrySet.GetTagHT(); }; + inline TagHeaderEntryHT & GetPubEntry(void) { return PubEntrySet.GetTagHT(); }; void PrintPubEntry(std::ostream & os = std::cout); void PrintPubDict (std::ostream & os = std::cout); @@ -119,7 +121,7 @@ public: bool SetEntryByName(std::string content,std::string tagName); // bool SetEntryByNumber(std::string content,guint16 group, guint16 element); -// inline ListTag & GetListEntry(void) { return PubHeaderEntrySet.GetListElem();}; +// inline ListTag & GetListEntry(void) { return PubHeaderEntrySet.GetListElem();}; // inline TagHeaderEntryHT & GetListEntry(void) { return PubHeaderEntrySet.GetTagHt(); }; // Read (used in gdcmFile) @@ -220,6 +222,7 @@ private: std::string filename; int enableSequences; + int wasUpdated; // true if a gdcmHeaderEntry was added post parsing // FIXME sw should be an enum e.g. //enum EndianType { diff --git a/src/gdcmHeaderEntry.cxx b/src/gdcmHeaderEntry.cxx index aed66bd8..4f53956d 100644 --- a/src/gdcmHeaderEntry.cxx +++ b/src/gdcmHeaderEntry.cxx @@ -1,8 +1,5 @@ // gdcmHeaderEntry.cxx //----------------------------------------------------------------------------- -// TODO -// A 'gdcmHeaderEntry' is actually a 'Dicom Element'. -// WHY such a confusing name??? // #include "gdcmHeaderEntry.h" diff --git a/src/gdcmHeaderEntrySet.cxx b/src/gdcmHeaderEntrySet.cxx index 49139942..5b8408a7 100644 --- a/src/gdcmHeaderEntrySet.cxx +++ b/src/gdcmHeaderEntrySet.cxx @@ -10,7 +10,7 @@ # include #endif -#include //la bibli qui va bien +#include // for std::ios::left, ... //----------------------------------------------------------------------------- // Constructor / Destructor @@ -25,7 +25,6 @@ gdcmHeaderEntrySet::~gdcmHeaderEntrySet() { delete EntryToDelete; tag->second=NULL; } - tagHT.clear(); } @@ -46,6 +45,8 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { gdcmTS * ts = gdcmGlobal::GetTS(); std::ostringstream s; +/* +// DO NOT remove this code right now. // Tag HT s << "------------- using tagHT ---------------------" << std::endl; @@ -78,7 +79,7 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { } s << std::endl; } - +*/ // List element guint32 lgth; char greltag[10]; //group element tag @@ -96,13 +97,23 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { sprintf(greltag,"%04x|%04x",g,e); d2 = _CreateCleanString(v); // replace non printable characters by '.' s << greltag << " lg : "; - lgth = (*i)->GetReadLength(); - sprintf(st,"x(%x)",lgth); - s.setf(std::ios::left); - s << std::setw(10-strlen(st)) << " "; - s << st << " "; - s.setf(std::ios::left); - s << std::setw(8) << lgth; + //lgth = (*i)->GetLength(); + lgth = (*i)->GetReadLength(); + if (lgth == 0xffffffff) { + sprintf(st,"x(%ff)"); + s.setf(std::ios::left); + s << std::setw(10-strlen(st)) << " "; + s << st << " "; + s.setf(std::ios::left); + s << std::setw(8) << "-1"; + } else { + sprintf(st,"x(%x)",lgth); + s.setf(std::ios::left); + s << std::setw(10-strlen(st)) << " "; + s << st << " "; + s.setf(std::ios::left); + s << std::setw(8) << lgth; + } s << " Off.: "; sprintf(st,"x(%x)",o); s << std::setw(10-strlen(st)) << " "; @@ -122,10 +133,16 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { if ( (e == 0x0016) || (e == 0x1150) ) s << " ==>\t[" << ts->GetValue(v) << "]"; } - } + } + if (e == 0x0000) { // elem 0x0000 --> group length + if (v == "4294967295") // to avoid troubles in convertion + sprintf (st," x(ffffffff)"); + else + sprintf(st," x(%08x)",atoi(v.c_str())); + s << st; + } s << std::endl; } - os<GetKey()] = newHeaderEntry; - +// tagHT [newHeaderEntry->GetKey()] = newHeaderEntry; tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) ); - -// WARNING : push_bash in listEntries ONLY during ParseHeader -// TODO : something to allow further Elements addition -// position to be taken care of ! listEntries.push_back(newHeaderEntry); } @@ -336,6 +351,7 @@ bool gdcmHeaderEntrySet::Write(FILE * _fp, FileType type) { * \ingroup gdcmHeaderEntrySet * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader * \warning : to be re-written using the chained list instead of the H table. + * \warning : DO NOT use (doesn't work any longer because of the multimap) * \todo : to be re-written using the chained list instead of the H table * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files) * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...) @@ -435,7 +451,6 @@ void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) { * @param type type of the File to be written * (ACR-NEMA, ExplicitVR, ImplicitVR) * @param _fp already open file pointer - * @return */ void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) { guint16 gr, el; @@ -447,24 +462,24 @@ void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) { std::vector tokens; - // TODO : use listEntries to iterate, not TagHt! + // uses now listEntries to iterate, not TagHt! + // // pb : gdcmHeaderEntrySet.Add does NOT update listEntries - // find a trick in STL to do it, at low cost ! + // TODO : find a trick (in STL?) to do it, at low cost ! void *ptr; - // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian - // restent a tester les echecs en ecriture (apres chaque fwrite) + // TODO (?) tester les echecs en ecriture (apres chaque fwrite) - for (TagHeaderEntryHT::iterator tag2=tagHT.begin(); - tag2 != tagHT.end(); + for (ListTag::iterator tag2=listEntries.begin(); + tag2 != listEntries.end(); ++tag2){ - gr = tag2->second->GetGroup(); - el = tag2->second->GetElement(); - lgr = tag2->second->GetLength(); - val = tag2->second->GetValue().c_str(); - vr = tag2->second->GetVR(); + gr = (*tag2)->GetGroup(); + el = (*tag2)->GetElement(); + lgr = (*tag2)->GetLength(); + val = (*tag2)->GetValue().c_str(); + vr = (*tag2)->GetVR(); if ( type == ACR ) { if (gr < 0x0008) continue; // ignore pure DICOM V3 groups @@ -497,7 +512,7 @@ void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) { if (vr == "US" || vr == "SS") { tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (tag2->second->GetValue(), tokens, "\\"); + Tokenize ((*tag2)->GetValue(), tokens, "\\"); for (unsigned int i=0; isecond->GetValue(), tokens, "\\"); + Tokenize ((*tag2)->GetValue(), tokens, "\\"); for (unsigned int i=0; i GroupHT; //----------------------------------------------------------------------------- /* - * Container for a set of successfully parsed HeaderEntrys (i.e. Dicom Elements). + * \defgroup gdcmHeaderEntrySet + * \brief Container for a set of successfully parsed HeaderEntries + * (i.e. Dicom Elements). */ class GDCM_EXPORT gdcmHeaderEntrySet { public: @@ -66,7 +68,7 @@ private: // Variables TagHeaderEntryHT tagHT; // H Table (multimap), to provide fast access - ListTag listEntries; // chained list, to keep the 'spacial' ordering + ListTag listEntries; // chained list, to keep the 'spacial' ordering }; //-----------------------------------------------------------------------------