From d1cf86f331e421ff841ac1bb7323369751a648b9 Mon Sep 17 00:00:00 2001 From: jpr Date: Fri, 16 Jan 2004 08:46:11 +0000 Subject: [PATCH] * removal of class gdcmHeaderEntrySet * removal of files gdcmHeaderEntrySet.cxx, gdcmHeaderEntrySet.h * add file gdcmHeader2.cxx * add method gdcmHeader::SetPrintLevel (for PrintHeader) --- src/CMakeLists.txt | 2 +- src/Makefile.am | 59 ++-- src/gdcm.h | 1 - src/gdcmFile.cxx | 22 +- src/gdcmHeader.cxx | 249 ++++++++++++----- src/gdcmHeader.h | 78 +++++- ...gdcmHeaderEntrySet.cxx => gdcmHeader2.cxx} | 256 ++++-------------- src/gdcmHeaderEntrySet.h | 75 ----- 8 files changed, 336 insertions(+), 406 deletions(-) rename src/{gdcmHeaderEntrySet.cxx => gdcmHeader2.cxx} (61%) delete mode 100644 src/gdcmHeaderEntrySet.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5000f8c6..7fdd268e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,9 +13,9 @@ SET(libgdcm_la_SOURCES gdcmException.cxx gdcmUtil.cxx gdcmHeader.cxx + gdcmHeader2.cxx gdcmHeaderHelper.cxx gdcmHeaderEntry.cxx - gdcmHeaderEntrySet.cxx gdcmDictEntry.cxx gdcmDict.cxx gdcmDictSet.cxx diff --git a/src/Makefile.am b/src/Makefile.am index 3aa620c9..263adbb8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,39 +12,38 @@ libgdcm_la_LIBADD = \ $(top_builddir)/src/jpeg/libijg8/libgdcmijpeg8.la \ $(top_builddir)/src/jpeg/ljpg/libgdcmjpg.la -libgdcm_la_SOURCES= \ - gdcmException.cxx \ - gdcmUtil.cxx \ - gdcmHeader.cxx \ - gdcmHeaderHelper.cxx \ - gdcmHeaderEntry.cxx \ - gdcmHeaderEntrySet.cxx \ - gdcmDictEntry.cxx \ - gdcmDict.cxx \ - gdcmDictSet.cxx \ - gdcmFile.cxx \ - gdcmVR.cxx \ - gdcmTS.cxx \ - gdcmJpeg.cxx \ - gdcmJpeg12.cxx \ - gdcmJpeg2000.cxx \ - gdcmRLE.cxx \ +libgdcm_la_SOURCES= \ + gdcmException.cxx \ + gdcmUtil.cxx \ + gdcmHeader.cxx \ + gdcmHeader2.cxx \ + gdcmHeaderHelper.cxx \ + gdcmHeaderEntry.cxx \ + gdcmDictEntry.cxx \ + gdcmDict.cxx \ + gdcmDictSet.cxx \ + gdcmFile.cxx \ + gdcmVR.cxx \ + gdcmTS.cxx \ + gdcmJpeg.cxx \ + gdcmJpeg12.cxx \ + gdcmJpeg2000.cxx \ + gdcmRLE.cxx \ gdcmParse.cxx libgdcmincludedir = $(includedir) -libgdcminclude_HEADERS = \ - gdcmException.h \ - gdcmHeader.h \ - gdcmHeaderHelper.h \ - gdcmCommon.h \ - gdcm.h \ - gdcmDictSet.h \ - gdcmDict.h \ - gdcmDictEntry.h \ - gdcmHeaderEntry.h \ - gdcmHeaderEntrySet.h \ - gdcmVR.h \ - gdcmTS.h \ +libgdcminclude_HEADERS = \ + gdcmException.h \ + gdcmHeader.h \ + gdcmHeaderHelper.h \ + gdcmCommon.h \ + gdcm.h \ + gdcmDictSet.h \ + gdcmDict.h \ + gdcmDictEntry.h \ + gdcmHeaderEntry.h \ + gdcmVR.h \ + gdcmTS.h \ gdcmFile.h EXTRA_DIST = \ diff --git a/src/gdcm.h b/src/gdcm.h index e1fd77c8..7aa9fc3a 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -21,7 +21,6 @@ #include "gdcmDictSet.h" #include "gdcmHeaderEntry.h" -#include "gdcmHeaderEntrySet.h" #include "gdcmHeader.h" #include "gdcmHeaderHelper.h" diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index e94c9c4f..888c5758 100644 --- a/src/gdcmFile.cxx +++ b/src/gdcmFile.cxx @@ -172,8 +172,8 @@ size_t gdcmFile::GetImageDataSizeRaw(void) { * \brief Allocates necessary memory, copies the pixel data * (image[s]/volume[s]) to newly allocated zone. * Transforms YBR pixels into RGB pixels if any - Transforms 3 planes R, G, B into a single RGB Plane - Transforms single Grey plane + 3 Palettes into a RGB Plane + * Transforms 3 planes R, G, B into a single RGB Plane + * Transforms single Grey plane + 3 Palettes into a RGB Plane * @return Pointer to newly allocated pixel data. * \ NULL if alloc fails */ @@ -262,8 +262,8 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { * \brief Allocates necessary memory, copies the pixel data * (image[s]/volume[s]) to newly allocated zone. * Transforms YBR pixels into RGB pixels if any - Transforms 3 planes R, G, B into a single RGB Plane - DOES NOT transform Grey plane + 3 Palettes into a RGB Plane + * Transforms 3 planes R, G, B into a single RGB Plane + * DOES NOT transform Grey plane + 3 Palettes into a RGB Plane * @return Pointer to newly allocated pixel data. * \ NULL if alloc fails */ @@ -594,7 +594,7 @@ bool gdcmFile::WriteDcmImplVR (const char* fileName) { * \ingroup gdcmFile * \brief * @param fileName name of the file to be created - * (any already existing file is over written) + * (any already existing file is overwritten) * @return false if write fails */ @@ -609,12 +609,12 @@ bool gdcmFile::WriteDcmExplVR (std::string fileName) { * qui ne prennent en entrée QUE des images ACR ... * \warning if a DICOM_V3 header is supplied, * groups < 0x0008 and shadow groups are ignored) - * \warning NO TEST is performed on processor "Endiannerie". + * \warning NO TEST is performed on processor "Endiannity". * Ca fonctionnera correctement (?) sur processeur Intel * (Equivalent a IdDcmWrite) * * @param fileName name of the file to be created - * (any already existing file is over written) + * (any already existing file is overwritten) * @return false if write fails */ @@ -628,16 +628,16 @@ bool gdcmFile::WriteAcr (std::string fileName) { * \ingroup gdcmFile * * @param fileName name of the file to be created - * (any already existing file is over written) + * (any already existing file is overwritten) * @param type file type (ExplicitVR, ImplicitVR, ...) * @return false if write fails */ -bool gdcmFile::WriteBase (std::string FileName, FileType type) { +bool gdcmFile::WriteBase (std::string fileName, FileType type) { FILE * fp1; - fp1 = fopen(FileName.c_str(),"wb"); + fp1 = fopen(fileName.c_str(),"wb"); if (fp1 == NULL) { - printf("Echec ouverture (ecriture) Fichier [%s] \n",FileName.c_str()); + printf("Echec ouverture (ecriture) Fichier [%s] \n",fileName.c_str()); return (false); } diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index e6177650..fc306970 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -57,9 +57,10 @@ 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(); + wasUpdated = 0; // will be set to 1 if user adds an entry + printLevel = 1; // 'Heavy' header print by default } /** @@ -94,7 +95,7 @@ gdcmHeader::~gdcmHeader (void) { * @return */ void gdcmHeader::PrintPubEntry(std::ostream & os) { - PubEntrySet.Print(os); + Print(os); } /** @@ -695,7 +696,7 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables // if Photometric Interpretation # PALETTE COLOR, no LUT to be done - if (gdcmHeader::GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") { + if (GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") { return NULL; } int lengthR, debR, nbitsR; @@ -865,18 +866,6 @@ std::string gdcmHeader::GetPubEntryVRByName(std::string tagName) { return elem->GetVR(); } -/** - * \ingroup gdcmHeader - * \brief Searches within the public dictionary for element value of - * a given tag. - * @param group Group of the researched tag. - * @param element Element of the researched tag. - * @return Corresponding element value when it exists, and the string - * GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmHeader::GetPubEntryByNumber(guint16 group, guint16 element) { - return PubEntrySet.GetEntryByNumber(group, element); -} /** * \ingroup gdcmHeader @@ -912,31 +901,77 @@ bool gdcmHeader::SetPubEntryByName(std::string content, std::string tagName) { gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); if( dictEntry == NULL) return false; - return(PubEntrySet.SetEntryByNumber(content, - dictEntry->GetGroup(), - dictEntry->GetElement())); + return(SetEntryByNumber(content, + dictEntry->GetGroup(), + dictEntry->GetElement())); } /** * \ingroup gdcmHeader * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) - * in the PubHeaderEntrySet of this instance * through it's (group, element) and modifies it's content with * the given value. * @param content new value to substitute with * @param group group of the Dicom Element to modify * @param element element of the Dicom Element to modify */ -bool gdcmHeader::SetPubEntryByNumber(std::string content, guint16 group, - guint16 element) - -//TODO : homogeneiser les noms : SetPubElValByNumber -// qui appelle PubHeaderEntrySet.SetHeaderEntryByNumber -// pourquoi pas SetPubHeaderEntryByNumber ?? -{ - return ( PubEntrySet.SetEntryByNumber (content, group, element) ); +bool gdcmHeader::SetPubEntryByNumber(std::string content, + guint16 group, + guint16 element) { + TagKey key = gdcmDictEntry::TranslateToKey(group, element); + if ( ! tagHT.count(key)) + return false; + int l = content.length(); + if(l%2) { // Odd length are padded with a space (020H). + l++; + content = content + '\0'; + } + + //tagHT[key]->SetValue(content); + gdcmHeaderEntry * a; + IterHT p; + TagHeaderEntryHT::iterator p2; + // DO NOT remove the following lines : they explain the stuff + //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym + //p2=p.first; // iterator on the first synonym + //a=p2->second; // H Table target column (2-nd col) + + // or, easier : + a = ((tagHT.equal_range(key)).first)->second; + + a-> SetValue(content); + + //std::string vr = tagHT[key]->GetVR(); + std::string vr = a->GetVR(); + + guint32 lgr; + if( (vr == "US") || (vr == "SS") ) + lgr = 2; + else if( (vr == "UL") || (vr == "SL") ) + lgr = 4; + else + lgr = l; + //tagHT[key]->SetLength(lgr); + a->SetLength(lgr); + return true; } +/** + * \ingroup gdcmHeader + * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * \warning Don't use any longer : use SetPubEntryByNumber + * @param content new value to substitute with + * @param group group of the Dicom Element to modify + * @param element element of the Dicom Element to modify + */ +bool gdcmHeader::SetEntryByNumber(std::string content, + guint16 group, + guint16 element) { + return SetPubEntryByNumber(content, group, element); +} + /** * \ingroup gdcmHeader * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) @@ -950,16 +985,41 @@ bool gdcmHeader::SetPubEntryByNumber(std::string content, guint16 group, * @return 1 on success, 0 otherwise. */ -bool gdcmHeader::SetPubEntryLengthByNumber(guint32 length, guint16 group, - guint16 element) { - return ( PubEntrySet.SetEntryLengthByNumber (length, group, element) ); +bool gdcmHeader::SetPubEntryLengthByNumber(guint32 length, + guint16 group, guint16 element) { + TagKey key = gdcmDictEntry::TranslateToKey(group, element); + if ( ! tagHT.count(key)) + return false; + if (length%2) length++; // length must be even + //tagHT[key]->SetLength(length); + ( ((tagHT.equal_range(key)).first)->second )->SetLength(length); + + return true ; } +/** + * \ingroup gdcmHeader + * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) + * in the PubHeaderEntrySet of this instance + * through it's (group, element) and modifies it's length with + * the given value. + * \warning Don't use any longer : use SetPubEntryLengthByNumber + * @param length new length to substitute with + * @param group group of the ElVal to modify + * @param element element of the ElVal to modify + * @return 1 on success, 0 otherwise. + */ + +bool gdcmHeader::SetEntryLengthByNumber(guint32 length, + guint16 group, guint16 element) { + return SetPubEntryLengthByNumber( length, group,element); +} /** * \ingroup gdcmHeader * \brief Searches within Header Entries (Dicom Elements) parsed with * the public and private dictionaries * for the element value of a given tag. + * \warning Don't use any longer : use GetPubEntryByName * @param tagName name of the searched element. * @return Corresponding element value when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. @@ -997,9 +1057,26 @@ std::string gdcmHeader::GetEntryVRByName(std::string tagName) { * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ std::string gdcmHeader::GetEntryByNumber(guint16 group, guint16 element) { - return GetPubEntryByNumber(group, element); + TagKey key = gdcmDictEntry::TranslateToKey(group, element); + if ( ! tagHT.count(key)) + return GDCM_UNFOUND; + return tagHT.find(key)->second->GetValue(); } +/** + * \ingroup gdcmHeader + * \brief Searches within the public dictionary for element value of + * a given tag. + * @param group Group of the researched tag. + * @param element Element of the researched tag. + * @return Corresponding element value when it exists, and the string + * GDCM_UNFOUND ("gdcm::Unfound") otherwise. + */ +std::string gdcmHeader::GetPubEntryByNumber(guint16 group, guint16 element) { + return GetEntryByNumber(group, element); +} + + /** * \ingroup gdcmHeader * \brief Searches within Header Entries (Dicom Elements) parsed with @@ -1034,7 +1111,7 @@ bool gdcmHeader::SetEntryByName(std::string content,std::string tagName) { TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), dictEntry->GetElement()); - if ( PubEntrySet.GetTagHT().count(key) == 0 ) + if ( GetPubEntry().count(key) == 0 ) return false; int l = content.length(); if(l%2) { // Odd length are padded with a space (020H). @@ -1051,7 +1128,7 @@ bool gdcmHeader::SetEntryByName(std::string content,std::string tagName) { //p2=p.first; // iterator on the first synonym //a=p2->second; // H Table target column (2-nd col) // or, easier : - a = ((PubEntrySet.GetTagHT().equal_range(key)).first)->second; + a = ((GetPubEntry().equal_range(key)).first)->second; a-> SetValue(content); std::string vr = a->GetVR(); @@ -1128,21 +1205,40 @@ void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { CheckSwap(); while ( (newHeaderEntry = ReadNextHeaderEntry()) ) { SkipHeaderEntry(newHeaderEntry); - PubEntrySet.Add(newHeaderEntry); + Add(newHeaderEntry); } } + + /** * \ingroup gdcmHeader * \brief * @param fp file pointer on an already open file - * @param type file type ( ImplicitVR, ExplicitVR, ...) - * @return Boolean - */ + * @param type type of the File to be written + * (ACR-NEMA, ExplicitVR, ImplicitVR) + * @return always "True" ?! + */ bool gdcmHeader::Write(FILE * fp, FileType type) { +// ============== +// TODO The stuff has been rewritten using the chained list instead +// of the H table +// so we could remove the GroupHT from the gdcmHeader +// To be checked +// ============= + // TODO : move the following lines (and a lot of others, to be written) // to a future function CheckAndCorrectHeader + + // Question : + // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non + // (FileType est un champ de gdcmHeader ...) + // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA + // no way + // a moins de se livrer a un tres complique ajout des champs manquants. + // faire un CheckAndCorrectHeader (?) + if (type == ImplicitVR) { std::string implicitVRTransfertSyntax = "1.2.840.10008.1.2"; @@ -1152,7 +1248,7 @@ bool gdcmHeader::Write(FILE * fp, FileType type) { // values with a VR of UI shall be padded with a single trailing null // Dans le cas suivant on doit pader manuellement avec un 0 - PubEntrySet.SetEntryLengthByNumber(18, 0x0002, 0x0010); + SetEntryLengthByNumber(18, 0x0002, 0x0010); } if (type == ExplicitVR) { @@ -1163,11 +1259,18 @@ bool gdcmHeader::Write(FILE * fp, FileType type) { // values with a VR of UI shall be padded with a single trailing null // Dans le cas suivant on doit pader manuellement avec un 0 - PubEntrySet.SetEntryLengthByNumber(20, 0x0002, 0x0010); + SetEntryLengthByNumber(20, 0x0002, 0x0010); } - return PubEntrySet.Write(fp, type); -} + + if ( (type == ImplicitVR) || (type == ExplicitVR) ) + UpdateGroupLength(false,type); + if ( type == ACR) + UpdateGroupLength(true,ACR); + + WriteEntries(type, fp); + return(true); + } /** * \ingroup gdcmFile @@ -1211,9 +1314,9 @@ bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, gdcmHeaderEntry* a =NewHeaderEntryByNumber(Group, Elem); if (a == NULL) return false; - PubEntrySet.Add(a); + Add(a); } - PubEntrySet.SetEntryByNumber(Value, Group, Elem); + SetPubEntryByNumber(Value, Group, Elem); return(true); } @@ -1231,9 +1334,9 @@ bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Ele gdcmHeaderEntry* nvHeaderEntry=NewHeaderEntryByNumber(Group, Elem); // TODO : check if fails - PubEntrySet.Add(nvHeaderEntry); + Add(nvHeaderEntry); std::string v = Value; - PubEntrySet.SetEntryByNumber(v, Group, Elem); + SetEntryByNumber(v, Group, Elem); return(true); } @@ -1244,12 +1347,12 @@ bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Ele * @param Value * @param Group * @param Elem - * \return integer acts as a boolean + * \return boolean */ bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) { std::string v = Value; - PubEntrySet.SetEntryByNumber(v, Group, Elem); + SetEntryByNumber(v, Group, Elem); return true; } @@ -1295,22 +1398,26 @@ guint16 gdcmHeader::SwapShort(guint16 a) { //----------------------------------------------------------------------------- // Protected + /** * \ingroup gdcmHeader - * \brief - * - * @return + * \brief retrieves a Dicom Element (the first one) using (group, element) + * \ warning (group, element) IS NOT an identifier inside the Dicom Header + * if you think it's NOT UNIQUE, check the count number + * and use iterators to retrieve ALL the Dicoms Elements within + * a given couple (group, element) + * @param group Group number of the searched Dicom Element + * @param element Element number of the searched Dicom Element + * @return */ -gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByNumber(guint16 Group, guint16 Elem) { - gdcmHeaderEntry *HeaderEntry = PubEntrySet.GetHeaderEntryByNumber(Group, Elem); - if (!HeaderEntry) { - dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber", - "failed to Locate gdcmHeaderEntry"); +gdcmHeaderEntry* gdcmHeader::GetHeaderEntryByNumber(guint16 group, guint16 element) { + TagKey key = gdcmDictEntry::TranslateToKey(group, element); + if ( ! tagHT.count(key)) return NULL; - } - return HeaderEntry; + return tagHT.find(key)->second; } + /** * \ingroup gdcmHeader * \brief Searches within the Header Entries for a Dicom Element of @@ -1329,14 +1436,15 @@ gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByNumber(guint16 Group, guint16 Elem) /** * \ingroup gdcmHeader - * \brief Checks if a given HeaderEntry (group,number) - * \ exists in the Public HeaderEntrySet - * @param Group - * @param Elem - * @return boolean + * \brief Checks if a given Dicom Element exists + * \ within the H table + * @param group Group number of the searched Dicom Element + * @param element Element number of the searched Dicom Element + * @return number of occurences */ -bool gdcmHeader::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { - return (PubEntrySet.CheckIfExistByNumber(Group, Elem)>0); +int gdcmHeader::CheckIfExistByNumber(guint16 group, guint16 element ) { + std::string key = gdcmDictEntry::TranslateToKey(group, element ); + return (tagHT.count(key)); } /** @@ -1392,7 +1500,7 @@ void * gdcmHeader::LoadEntryVoidArea(guint16 Group, guint16 Elem) { return NULL; } - PubEntrySet.SetVoidAreaByNumber(a, Group, Elem); + SetVoidAreaByNumber(a, Group, Elem); // TODO check the result size_t l2 = fread(a, 1, l ,fp); if(l != l2) { @@ -1583,7 +1691,7 @@ void gdcmHeader::LoadHeaderEntrySafe(gdcmHeaderEntry * entry) { /** * \ingroup gdcmHeader * \brief - * @param entry Header Entry whose value shall be loaded. + * @param ElVal Header Entry whose length of the value shall be loaded. * @return */ @@ -1781,8 +1889,9 @@ void gdcmHeader::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) { /** * \ingroup gdcmHeader - * \brief - * @param ElVal + * \brief Skip a given Header Entry + * \warning NOT end user intended method ! + * @param entry * @return */ void gdcmHeader::SkipHeaderEntry(gdcmHeaderEntry * entry) { @@ -2367,7 +2476,7 @@ gdcmHeaderEntry* gdcmHeader::NewManualHeaderEntryToPubDict(std::string NewTagNam guint32 FreeElem = 0; gdcmDictEntry* NewEntry = (gdcmDictEntry*)0; - FreeElem = PubEntrySet.GenerateFreeTagKeyInGroup(StuffGroup); + FreeElem = GenerateFreeTagKeyInGroup(StuffGroup); if (FreeElem == UINT32_MAX) { dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict", "Group 0xffff in Public Dict is full"); @@ -2376,7 +2485,7 @@ gdcmHeaderEntry* gdcmHeader::NewManualHeaderEntryToPubDict(std::string NewTagNam NewEntry = Dicts->NewVirtualDictEntry(StuffGroup, FreeElem, VR, "GDCM", NewTagName); NewElVal = new gdcmHeaderEntry(NewEntry); - PubEntrySet.Add(NewElVal); + Add(NewElVal); return NewElVal; } diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index 7decd121..ba4b347b 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -9,17 +9,30 @@ #include "gdcmException.h" #include "gdcmDictSet.h" #include "gdcmHeaderEntry.h" -#include "gdcmHeaderEntrySet.h" + +#include #include +#include // for linking together *all* the Dicom Elements //----------------------------------------------------------------------------- typedef std::string VRKey; typedef std::string VRAtr; typedef std::map VRHT; // Value Representation Hash Table +typedef std::multimap TagHeaderEntryHT; +typedef std::pair PairHT; +typedef std::pair IterHT; + +typedef std::list ListTag; // for linking together the Elements + +// TODO : to be removed after re-writting gdcmHeaderEntrySet::UpdateGroupLength +// using the chained list instead of the H table +typedef std::string GroupKey; +typedef std::map GroupHT; + //----------------------------------------------------------------------------- /* - * \defgroup gdcmHedaer + * \defgroup gdcmHeader * \brief * The purpose of an instance of gdcmHeader is to act as a container of * all the DICOM elements and their corresponding values (and @@ -29,7 +42,7 @@ typedef std::map VRHT; // Value Representation Hash Table * The typical usage of instances of class gdcmHeader is to classify a set of * dicom files according to header information e.g. to create a file hierarchy * reflecting the Patient/Study/Serie informations, or extracting a given - * SerieId. Accesing the content (image[s] or volume[s]) is beyond the + * SerieId. Accessing the content (image[s] or volume[s]) is beyond the * functionality of this class and belongs to gdmcFile. * \note The various entries of the explicit value representation (VR) shall * be managed within a dictionary which is shared by all gdcmHeader @@ -104,11 +117,29 @@ public: bool SetPubEntryByName (std::string content, std::string tagName); bool SetPubEntryByNumber(std::string content, guint16 group, guint16 element); - bool SetPubEntryLengthByNumber(guint32 lgr, guint16 group, guint16 element); - - inline ListTag & GetPubListEntry(void) { return PubEntrySet.GetListEntry();}; - inline TagHeaderEntryHT & GetPubEntry(void) { return PubEntrySet.GetTagHT(); }; - + bool SetPubEntryLengthByNumber(guint32 lgr, guint16 group, guint16 element); + + /** + * \ingroup gdcmHeader + * \brief returns a ref to the Dicom Header H table (multimap) + * return the Dicom Header H table + */ + inline TagHeaderEntryHT & GetPubEntry(void) { return tagHT; }; + + /** + * \ingroup gdcmHeader + * \brief returns a ref to the Dicom Header chained list + * return the Dicom Header chained list + */ + inline ListTag & GetPubListEntry(void) { return listEntries; }; + + /** + * \ingroup gdcmHeader + * \brief Sets the print level for the Dicom Header + * \note 0 for Light Print; 1 for 'heavy' Print + */ + void SetPrintLevel(int level) { printLevel = level; }; + void PrintPubEntry(std::ostream & os = std::cout); void PrintPubDict (std::ostream & os = std::cout); @@ -121,8 +152,6 @@ 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 TagHeaderEntryHT & GetListEntry(void) { return PubHeaderEntrySet.GetTagHt(); }; // Read (used in gdcmFile) FILE *OpenFile(bool exception_on_error = false) throw(gdcmFileError); @@ -141,9 +170,21 @@ public: inline int GetSwapCode(void) { return sw; } guint16 SwapShort(guint16); // needed by gdcmFile guint32 SwapLong(guint32); // for JPEG Files + + + +// ================= Was in EntrySet ================= + void Print(std::ostream &); + void Add(gdcmHeaderEntry*); + bool SetEntryByNumber(std::string content, guint16 group, guint16 element); + bool SetEntryLengthByNumber(guint32 l, guint16 group, guint16 element); + bool SetVoidAreaByNumber(void *a, guint16 Group, guint16 Elem ); + guint32 GenerateFreeTagKeyInGroup(guint16 group); +// =================================================== + protected: - bool CheckIfExistByNumber(guint16 Group, guint16 Elem ); + int CheckIfExistByNumber(guint16 Group, guint16 Elem ); // int ! gdcmHeaderEntry *GetHeaderEntryByName (std::string Name); gdcmHeaderEntry *GetHeaderEntryByNumber(guint16 group, guint16 element); @@ -156,6 +197,11 @@ protected: void * LoadEntryVoidArea (guint16 Group, guint16 Element); +// ================= Was in EntrySet ================= + void UpdateGroupLength(bool SkipSequence = false, FileType type = ImplicitVR); + void WriteEntries(FileType type, FILE *); +// =================================================== + // Variables FILE * fp; FileType filetype; // ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown @@ -215,14 +261,18 @@ private: // header gdcmDict *RefShaDict; - /// ELement VALueS parsed with the PUBlic dictionary. - gdcmHeaderEntrySet PubEntrySet; + // ================ Was in gdcmHeaderEntrySet ========= + TagHeaderEntryHT tagHT; // H Table (multimap), to provide fast access + ListTag listEntries; // chained list, to keep the 'spacial' ordering + int wasUpdated; // true if a gdcmHeaderEntry was added post parsing + int printLevel; // for PrintHeader + // ==================================================== + // Refering underlying filename. 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/gdcmHeaderEntrySet.cxx b/src/gdcmHeader2.cxx similarity index 61% rename from src/gdcmHeaderEntrySet.cxx rename to src/gdcmHeader2.cxx index b83a4e87..ded3d1be 100644 --- a/src/gdcmHeaderEntrySet.cxx +++ b/src/gdcmHeader2.cxx @@ -1,7 +1,7 @@ -// gdcmHeaderEntrySet.cxx +// gdcmHeader2.cxx //----------------------------------------------------------------------------- #include "gdcmUtil.h" -#include "gdcmHeaderEntrySet.h" +#include "gdcmHeader.h" #include "gdcmTS.h" #ifdef GDCM_NO_ANSI_STRING_STREAM # include @@ -12,38 +12,21 @@ #include // for std::ios::left, ... -//----------------------------------------------------------------------------- -// Constructor / Destructor -/** - * \ingroup gdcmHeaderEntrySet - * \brief Destructor - */ -gdcmHeaderEntrySet::~gdcmHeaderEntrySet() { - for (TagHeaderEntryHT::iterator tag = tagHT.begin(); tag != tagHT.end(); ++tag) { - gdcmHeaderEntry* EntryToDelete = tag->second; - if ( EntryToDelete ) - delete EntryToDelete; - tag->second=NULL; - } - tagHT.clear(); -} - //----------------------------------------------------------------------------- // Print /** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \brief prints the Dicom Elements of the gdcmHeader * using both H table and Chained List * @param os The output stream to be written to. */ -void gdcmHeaderEntrySet::Print(std::ostream & os) { +void gdcmHeader::Print(std::ostream & os) { size_t o; unsigned short int g, e; TSKey v; std::string d2; gdcmTS * ts = gdcmGlobal::GetTS(); - std::ostringstream s; /* // DO NOT remove this code right now. @@ -79,7 +62,8 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { } s << std::endl; } -*/ +*/ + // List element guint32 lgth; char greltag[10]; //group element tag @@ -94,36 +78,42 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { e = (*i)->GetElement(); v = (*i)->GetValue(); o = (*i)->GetOffset(); - sprintf(greltag,"%04x|%04x",g,e); + sprintf(greltag,"%04x|%04x ",g,e); d2 = _CreateCleanString(v); // replace non printable characters by '.' - s << greltag << " lg : "; - //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 << greltag ; + + if (printLevel>=2) { + s << "lg : "; + 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)) << " "; s << st << " "; - s.setf(std::ios::left); - s << std::setw(8) << lgth; + s << std::setw(8) << o; } - s << " Off.: "; - sprintf(st,"x(%x)",o); - s << std::setw(10-strlen(st)) << " "; - s << st << " "; - s << std::setw(8) << o; - s << "[" << (*i)->GetVR() << "] "; - s.setf(std::ios::left); - s << std::setw(66-(*i)->GetName().length()) << " "; - s << "[" << (*i)->GetName()<< "] "; - s << "[" << d2 << "]"; + if (printLevel>=1) { + s << "[" << (*i)->GetVR() << "] "; + s.setf(std::ios::left); + s << std::setw(66-(*i)->GetName().length()) << " "; + } + + s << "[" << (*i)->GetName()<< "]"; + s << " [" << d2 << "]"; // Display the UID value (instead of displaying the rough code) if (g == 0x0002) { // Any more to be displayed ? if ( (e == 0x0010) || (e == 0x0002) ) @@ -149,7 +139,7 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { //----------------------------------------------------------------------------- // Public /** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \brief add a new Dicom Element pointer to * the H Table and to the chained List * \warning push_bash in listEntries ONLY during ParseHeader @@ -157,122 +147,24 @@ void gdcmHeaderEntrySet::Print(std::ostream & os) { * \ when position to be taken care of * @param newHeaderEntry */ -void gdcmHeaderEntrySet::Add(gdcmHeaderEntry * newHeaderEntry) { +void gdcmHeader::Add(gdcmHeaderEntry * newHeaderEntry) { // tagHT [newHeaderEntry->GetKey()] = newHeaderEntry; tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) ); listEntries.push_back(newHeaderEntry); + wasUpdated = 1; } -/** - * \ingroup gdcmHeaderEntrySet - * \brief retrieves a Dicom Element (the first one) using (group, element) - * \ warning (group, element) IS NOT an identifier inside the Dicom Header - * if you think it's NOT UNIQUE, check the count number - * and use iterators to retrieve ALL the Dicoms Elements within - * a given couple (group, element) - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return - */ -gdcmHeaderEntry* gdcmHeaderEntrySet::GetHeaderEntryByNumber(guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return NULL; - return tagHT.find(key)->second; -} - -/** - * \ingroup gdcmHeaderEntrySet - * \brief Gets the value (string) of the target Dicom Element - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return - */ -std::string gdcmHeaderEntrySet::GetEntryByNumber(guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return GDCM_UNFOUND; - return tagHT.find(key)->second->GetValue(); -} /** - * \ingroup gdcmHeaderEntrySet - * \brief Sets the value (string) of the target Dicom Element - * @param content string value of the Dicom Element - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return - */ -bool gdcmHeaderEntrySet::SetEntryByNumber(std::string content, - guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return false; - int l = content.length(); - if(l%2) { // Odd length are padded with a space (020H). - l++; - content = content + '\0'; - } - - //tagHT[key]->SetValue(content); - gdcmHeaderEntry * a; - IterHT p; - TagHeaderEntryHT::iterator p2; - // DO NOT remove the following lines : they explain the stuff - //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym - //p2=p.first; // iterator on the first synonym - //a=p2->second; // H Table target column (2-nd col) - - // or, easier : - a = ((tagHT.equal_range(key)).first)->second; - - a-> SetValue(content); - - //std::string vr = tagHT[key]->GetVR(); - std::string vr = a->GetVR(); - - guint32 lgr; - if( (vr == "US") || (vr == "SS") ) - lgr = 2; - else if( (vr == "UL") || (vr == "SL") ) - lgr = 4; - else - lgr = l; - //tagHT[key]->SetLength(lgr); - a->SetLength(lgr); - return true; -} - -/** - * \ingroup gdcmHeaderEntrySet - * \brief Sets the value length of the Dicom Element - * \warning : use with caution ! - * @param length - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return boolean - */ -bool gdcmHeaderEntrySet::SetEntryLengthByNumber(guint32 length, - guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return false; - if (length%2) length++; // length must be even - //tagHT[key]->SetLength(length); - ( ((tagHT.equal_range(key)).first)->second )->SetLength(length); - - return true ; -} -/** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \brief Sets a 'non string' value to a given Dicom Element * @param area * @param group Group number of the searched Dicom Element * @param element Element number of the searched Dicom Element * @return */ -bool gdcmHeaderEntrySet::SetVoidAreaByNumber(void * area, +bool gdcmHeader::SetVoidAreaByNumber(void * area, guint16 group, guint16 element) { TagKey key = gdcmDictEntry::TranslateToKey(group, element); if ( ! tagHT.count(key)) @@ -283,13 +175,13 @@ bool gdcmHeaderEntrySet::SetVoidAreaByNumber(void * area, } /** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \brief Generate a free TagKey i.e. a TagKey that is not present * in the TagHt dictionary. * @param group The generated tag must belong to this group. * @return The element of tag with given group which is fee. */ -guint32 gdcmHeaderEntrySet::GenerateFreeTagKeyInGroup(guint16 group) { +guint32 gdcmHeader::GenerateFreeTagKeyInGroup(guint16 group) { for (guint32 elem = 0; elem < UINT32_MAX; elem++) { TagKey key = gdcmDictEntry::TranslateToKey(group, elem); if (tagHT.count(key) == 0) @@ -298,57 +190,13 @@ guint32 gdcmHeaderEntrySet::GenerateFreeTagKeyInGroup(guint16 group) { return UINT32_MAX; } -/** - * \ingroup gdcmHeaderEntrySet - * \brief Checks if a given Dicom Element exists - * \ within the H table - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return number of occurences - */ -int gdcmHeaderEntrySet::CheckIfExistByNumber(guint16 group, guint16 element ) { - std::string key = gdcmDictEntry::TranslateToKey(group, element ); - return (tagHT.count(key)); -} - -// ============== -// TODO to be re-written using the chained list instead of the H table -// so we can remove the GroupHT from the gdcmHeader -// ============= -/** - * \ingroup gdcmHeaderEntrySet - * \brief - * @param _fp already open file pointer - * @param type type of the File to be written - * (ACR-NEMA, ExplicitVR, ImplicitVR) - * @return always "True" ?! - */ -bool gdcmHeaderEntrySet::Write(FILE * _fp, FileType type) { - - // Question : - // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non - // (FileType est un champ de gdcmHeader ...) - // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA - // no way - // a moins de se livrer a un tres complique ajout des champs manquants. - // faire un CheckAndCorrectHeader (?) - - if ( (type == ImplicitVR) || (type == ExplicitVR) ) - UpdateGroupLength(false,type); - if ( type == ACR) - UpdateGroupLength(true,ACR); - - WriteEntries(type, _fp); - return(true); -} - //----------------------------------------------------------------------------- // Protected //----------------------------------------------------------------------------- // Private /** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \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) @@ -356,7 +204,7 @@ bool gdcmHeaderEntrySet::Write(FILE * _fp, FileType type) { * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files) * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...) */ -void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) { +void gdcmHeader::UpdateGroupLength(bool SkipSequence, FileType type) { guint16 gr, el; std::string vr; @@ -428,7 +276,7 @@ void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) { tk = g->first + "|0000"; // generate the element full tag if ( tagHT.count(tk) == 0) { // if element 0x0000 not found - gdcmDictEntry * tagZ = gdcmGlobal::GetDicts()->NewVirtualDictEntry(gr_bid, 0x0000, "UL"); + gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL"); elemZ = new gdcmHeaderEntry(tagZ); elemZ->SetLength(4); Add(elemZ); // create it @@ -442,7 +290,7 @@ void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) { } /** - * \ingroup gdcmHeaderEntrySet + * \ingroup gdcmHeader * \brief writes on disc according to the requested format * \ (ACR-NEMA, ExplicitVR, ImplicitVR) the image * \ warning does NOT add the missing elements in the header : @@ -452,7 +300,7 @@ void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) { * (ACR-NEMA, ExplicitVR, ImplicitVR) * @param _fp already open file pointer */ -void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) { +void gdcmHeader::WriteEntries(FileType type, FILE * _fp) { guint16 gr, el; guint32 lgr; const char * val; @@ -464,7 +312,7 @@ void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) { // uses now listEntries to iterate, not TagHt! // - // pb : gdcmHeaderEntrySet.Add does NOT update listEntries + // pb : gdcmHeader.Add does NOT update listEntries // TODO : find a trick (in STL?) to do it, at low cost ! void *ptr; diff --git a/src/gdcmHeaderEntrySet.h b/src/gdcmHeaderEntrySet.h deleted file mode 100644 index 320e0722..00000000 --- a/src/gdcmHeaderEntrySet.h +++ /dev/null @@ -1,75 +0,0 @@ -// gdcmHeaderEntrySet.h -//----------------------------------------------------------------------------- -#ifndef GDCMHeaderEntrySet_H -#define GDCMHeaderEntrySet_H - -#include "gdcmCommon.h" -#include "gdcmHeaderEntry.h" - -#include -#include -#include // for linking together *all* the Dicom Elements - -//----------------------------------------------------------------------------- -typedef std::multimap TagHeaderEntryHT; -typedef std::pair PairHT; -typedef std::pair IterHT; - -typedef std::list ListTag; // for linking together the Elements - -// TODO : to be removed after re-writting gdcmHeaderEntrySet::UpdateGroupLength -// using the chained list instead of the H table -typedef std::string GroupKey; -typedef std::map GroupHT; - -//----------------------------------------------------------------------------- -/* - * \defgroup gdcmHeaderEntrySet - * \brief Container for a set of successfully parsed HeaderEntries - * (i.e. Dicom Elements). - */ -class GDCM_EXPORT gdcmHeaderEntrySet { -public: - ~gdcmHeaderEntrySet(); - - void Print(std::ostream &); - - void Add(gdcmHeaderEntry*); - - gdcmHeaderEntry* GetHeaderEntryByNumber(guint16 group, guint16 element); - std::string GetEntryByNumber(guint16 group, guint16 element); - - bool SetEntryByNumber(std::string content, guint16 group, guint16 element); - bool SetEntryLengthByNumber(guint32 l, guint16 group, guint16 element); - bool SetVoidAreaByNumber(void *a, guint16 Group, guint16 Elem ); - - guint32 GenerateFreeTagKeyInGroup(guint16 group); - int CheckIfExistByNumber(guint16 Group, guint16 Elem ); // int ! - - /** - * \ingroup gdcmHeaderEntrySet - * \brief returns a ref to the Dicom Header H table (multimap) - * return the Dicom Header H table - */ - inline TagHeaderEntryHT & gdcmHeaderEntrySet::GetTagHT(void) { return tagHT; }; - - /** - * \ingroup gdcmHeaderEntrySet - * \brief returns a ref to the Dicom Header chained list - * return the Dicom Header chained list - */ - inline ListTag & gdcmHeaderEntrySet::GetListEntry(void) { return listEntries; }; - - bool Write(FILE *fp, FileType type); - -private: - void UpdateGroupLength(bool SkipSequence = false, FileType type = ImplicitVR); - void WriteEntries(FileType type, FILE *); - -// Variables - TagHeaderEntryHT tagHT; // H Table (multimap), to provide fast access - ListTag listEntries; // chained list, to keep the 'spacial' ordering -}; - -//----------------------------------------------------------------------------- -#endif -- 2.48.1