From: jpr Date: Thu, 11 Mar 2004 11:42:54 +0000 (+0000) Subject: Allow to create ex nihilo DICOMDIR X-Git-Tag: Version0.5.bp~297 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=55d77e0913ff360d639af1841c70d14dc8687584;p=gdcm.git Allow to create ex nihilo DICOMDIR and populate it whith : gdcmDicomDir::NewPatient gdcmDicomDirPatient::NewStudy gdcmDicomDirStudy::NewSerie gdcmDicomDirSerie::NewImage --- diff --git a/src/gdcmDicomDir.cxx b/src/gdcmDicomDir.cxx index 145ce1e8..34ceb7dc 100644 --- a/src/gdcmDicomDir.cxx +++ b/src/gdcmDicomDir.cxx @@ -24,13 +24,20 @@ * \ or uses an already built DICOMDIR, depending on 'parseDir' value * @param Name name of the root directory (parseDir = true) * name of the DICOMDIR (parseDir = false) - * @param parseDir true if user wants to explore the directories - * @param exception_on_error + * @param parseDir - true if user passed an entry point + * and wants to explore recursively the directories + * - false if user passed an already built DICOMDIR file + * and wants to use it + * @param exception_on_error whether we want to throw an exception or not */ gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir, bool exception_on_error): - gdcmParser(Name,exception_on_error,true) + gdcmParser(Name,exception_on_error,true) // true : enable SeQuences { + // que l'on ai passe un root directory ou un DICOMDIR + // et quelle que soit la valeur de parseDir, + // on a lance gdcmParser + startMethod= NULL; progressMethod= NULL; endMethod= NULL; @@ -46,8 +53,11 @@ gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir, metaElems=NULL; +// Si on passe un root directory, on est assuré de n'avoir rien ramené + if( GetListEntry().begin()==GetListEntry().end() ) { + // Si, en plus, parseDir == false, ca devrait etre une erreur dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty"); if(parseDir) @@ -60,6 +70,33 @@ gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir, CreateDicomDir(); } +/* + * \ingroup gdcmDicomDir + * \brief Constructor : creates an empty gdcmDicomDir + * @param exception_on_error whether we want to throw an exception or not + */ +gdcmDicomDir::gdcmDicomDir(bool exception_on_error): + gdcmParser(exception_on_error) +{ + startMethod= NULL; + progressMethod= NULL; + endMethod= NULL; + startMethodArgDelete= NULL; + progressMethodArgDelete=NULL; + endMethodArgDelete= NULL; + startArg= NULL; + progressArg= NULL; + endArg= NULL; + + progress=0.0; + abort=false; + string pathBidon = ""; // Sorry, NULL not allowed ... + SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements + + AddDicomDirMetaToEnd(listEntries.begin(),--listEntries.end()); +} + + /* * \ingroup gdcmDicomDir * \brief Canonical destructor @@ -91,12 +128,11 @@ void gdcmDicomDir::Print(std::ostream &os) { metaElems->SetPrintLevel(printLevel); metaElems->Print(os); - } - + } for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc) { (*cc)->SetPrintLevel(printLevel); - (*cc)->Print(os); + (*cc)->Print(os); } } @@ -129,7 +165,7 @@ bool gdcmDicomDir::IsReadable(void) */ void gdcmDicomDir::ParseDirectory(void) { - NewDicomDir(GetPath()); + CreateDicomDirChainedList(GetPath()); CreateDicomDir(); } @@ -225,9 +261,13 @@ void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method) * \brief writes on disc a DICOMDIR * \ warning does NOT add the missing elements in the header : * it's up to the user doing it ! + * \todo : to be re-written using the DICOMDIR tree-like structure + * *not* the chained list + * (does NOT exist if the DICOMDIR is user-forged !) * @param fileName file to be written to * @return false only when fail to open */ + bool gdcmDicomDir::Write(std::string fileName) { FILE * fp1; @@ -244,26 +284,83 @@ bool gdcmDicomDir::Write(std::string fileName) fwrite(filePreamble,128,1,fp1); fwrite("DICM",4,1,fp1); free(filePreamble); - UpdateDirectoryRecordSequenceLength(); - WriteEntries(fp1,DICOMDIR); + //UpdateDirectoryRecordSequenceLength(); // a reecrire en utilisant + // la structure arborescente JPR + WriteDicomDirEntries(fp1); fclose(fp1); return true; } +/** + * \ingroup gdcmParser + * \brief writes on disc according to the DICOMDIR format + * using the Chained List + * \todo a reecrire en utilisant la structure arborescente + * @param _fp already open file pointer + */ + +void gdcmDicomDir::WriteDicomDirEntries(FILE *_fp) +{ + // TODO (?) tester les echecs en ecriture + // (apres chaque fwrite, dans le WriteEntry) + + gdcmDicomDirMeta *ptrMeta; + ListDicomDirPatient::iterator itPatient; + ListDicomDirStudy::iterator itStudy; + ListDicomDirSerie::iterator itSerie; + ListDicomDirImage::iterator itImage; + ListTag::iterator i; + + ptrMeta= GetDicomDirMeta(); + for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) { + WriteEntry(*i,_fp,DICOMDIR); + } + + itPatient = GetDicomDirPatients().begin(); + while ( itPatient != GetDicomDirPatients().end() ) { + for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) { + WriteEntry(*i,_fp,DICOMDIR); + } + itStudy = ((*itPatient)->GetDicomDirStudies()).begin(); + while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) { + for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) { + WriteEntry(*i,_fp,DICOMDIR); + } + itSerie = ((*itStudy)->GetDicomDirSeries()).begin(); + while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) { + for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) { + WriteEntry(*i,_fp,DICOMDIR); + } + itImage = ((*itSerie)->GetDicomDirImages()).begin(); + while (itImage != (*itSerie)->GetDicomDirImages().end() ) { + for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) { + WriteEntry(*i,_fp,DICOMDIR); + } + ++itImage; + } + ++itSerie; + } + ++itStudy; + } + ++itPatient; + } +} + //----------------------------------------------------------------------------- // Protected + /* * \ingroup gdcmDicomDir - * \brief create a gdcmDicomDir from a root Directory - * @param path entry point of the stree-like structure + * \brief create a gdcmHeader-like chained list from a root Directory + * @param path entry point of the tree-like structure */ -void gdcmDicomDir::NewDicomDir(std::string path) +void gdcmDicomDir::CreateDicomDirChainedList(std::string path) { CallStartMethod(); - gdcmDirList fileList(path,1); + gdcmDirList fileList(path,1); // gets recursively the file list unsigned int count=0; ListHeader list; gdcmHeader *header; @@ -281,25 +378,89 @@ void gdcmDicomDir::NewDicomDir(std::string path) header=new gdcmHeader(it->c_str()); if(header->IsReadable()) - list.push_back(header); + list.push_back(header); // adds the file header to the chained list else delete header; count++; } - + // sorts Patient/Study/Serie/ std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan); std::string tmp=fileList.GetDirName(); + //for each Header of the chained list, add/update the Patient/Study/Serie/Image info SetElements(tmp,list); CallEndMethod(); } +/* + * \ingroup gdcmDicomDir + * \brief adds a new Patient to a partially created DICOMDIR + */ +gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) { + std::list elemList; + std::list::iterator it; + guint16 tmpGr,tmpEl; + gdcmDictEntry *dictEntry; + gdcmHeaderEntry *entry; + + elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements(); + std::list::iterator debInsertion, finInsertion, i,j; + + + debInsertion = metaElems->fin(); + ++debInsertion; + finInsertion=debInsertion; + + // for all the DicomDirPatient Elements + for(it=elemList.begin();it!=elemList.end();++it) + { + tmpGr=it->group; + tmpEl=it->elem; + dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl); + entry=new gdcmHeaderEntry(dictEntry); + entry->SetOffset(0); // just to avoid missprinting + entry->SetValue(it->value); + + if(dictEntry->GetGroup()==0xfffe) + { + entry->SetLength(entry->GetValue().length()); + } + else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) + { + entry->SetLength(4); + } + else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) + { + entry->SetLength(2); + } + else if(dictEntry->GetVR()=="SQ") + { + entry->SetLength(0xffffffff); + } + else + { + entry->SetLength(entry->GetValue().length()); + } + + tagHT.insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table + listEntries.insert(debInsertion ,entry); // en tete de liste des Patients + ++finInsertion; + } + + i=metaElems->fin(); + i++; + + gdcmDicomDirPatient *p = new gdcmDicomDirPatient(i, --debInsertion, + &tagHT, &listEntries); + patients.push_front(p); + return p; +} + /* * \ingroup gdcmDicomDir * \brief Get the DicomDir path - * @param */ std::string gdcmDicomDir::GetPath(void) { @@ -314,7 +475,10 @@ std::string gdcmDicomDir::GetPath(void) return(path); } - +/* + * \ingroup gdcmDicomDir + * \brief CallStartMethod + */ void gdcmDicomDir::CallStartMethod(void) { progress=0.0f; @@ -322,13 +486,19 @@ void gdcmDicomDir::CallStartMethod(void) if(startMethod) startMethod(startArg); } - +/* + * \ingroup gdcmDicomDir + * \brief CallProgressMethod + */ void gdcmDicomDir::CallProgressMethod(void) { if(progressMethod) progressMethod(progressArg); } - +/* + * \ingroup gdcmDicomDir + * \brief CallEndMethod + */ void gdcmDicomDir::CallEndMethod(void) { progress=1.0f; @@ -344,7 +514,8 @@ void gdcmDicomDir::CallEndMethod(void) */ void gdcmDicomDir::CreateDicomDir() { - // The list is parsed. When a tag is found : + // The list is parsed. + // When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found : // 1 - we save the beginning iterator // 2 - we continue to parse // 3 - we find an other tag @@ -353,7 +524,7 @@ void gdcmDicomDir::CreateDicomDir() gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META; ListTag::iterator begin; - ListTag::iterator end; + ListTag::iterator end, end2; begin=listEntries.begin(); end=begin; @@ -362,48 +533,44 @@ void gdcmDicomDir::CreateDicomDir() std::string v=(*i)->GetValue(); if(v=="PATIENT ") { - end=i; - AddObjectToEnd(type,begin,end); - + end=end2=i; + AddObjectToEnd(type,begin,--end2); type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT; begin=end; } if(v=="STUDY ") { - end=i; - AddObjectToEnd(type,begin,end); - + end=end2=i; + AddObjectToEnd(type,begin,--end2); type=gdcmDicomDir::GDCM_DICOMDIR_STUDY; begin=end; } if(v=="SERIES") { - end=i; - AddObjectToEnd(type,begin,end); - + end=end2=i; + AddObjectToEnd(type,begin,--end2); type=gdcmDicomDir::GDCM_DICOMDIR_SERIE; begin=end; } if(v=="IMAGE ") { - end=i; - AddObjectToEnd(type,begin,end); - + end=end2=i; + AddObjectToEnd(type,begin,--end2); type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE; begin=end; } } - end=GetListEntry().end(); + end=end2=listEntries.end(); if(begin!=end) - AddObjectToEnd(type,begin,end); + AddObjectToEnd(type,begin,--end2); } /* * \ingroup gdcmDicomDir - * \brief + * \brief AddObjectToEnd * @param type * @param begin * @param end @@ -443,23 +610,23 @@ void gdcmDicomDir::AddDicomDirMetaToEnd(ListTag::iterator begin,ListTag::iterato { if(metaElems) delete metaElems; - metaElems = new gdcmDicomDirMeta(begin,end); + metaElems = new gdcmDicomDirMeta(begin,end,&tagHT,&listEntries); } /* * \ingroup gdcmDicomDir - * \brief + * \brief AddDicomDirPatientToEnd * @param begin * @param end */ void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end) { - patients.push_back(new gdcmDicomDirPatient(begin,end)); + patients.push_back(new gdcmDicomDirPatient(begin,end,&tagHT, &listEntries)); } /* * \ingroup gdcmDicomDir - * \brief + * \brief AddDicomDirStudyToEnd * @param begin * @param end */ @@ -469,12 +636,12 @@ void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iter { ListDicomDirPatient::iterator itp=patients.end(); itp--; - (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end)); + (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end,&tagHT, &listEntries)); } } /* * \ingroup gdcmDicomDir - * \brief + * \brief AddDicomDirSerieToEnd * @param begin * @param end */ @@ -489,16 +656,16 @@ void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterat { ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end(); itst--; - (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end)); + (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end,&tagHT, &listEntries)); } } } /* * \ingroup gdcmDicomDir + * \brief AddDicomDirImageToEnd * @param begin * @param end - * @param */ void gdcmDicomDir::AddDicomDirImageToEnd(ListTag::iterator begin,ListTag::iterator end) { @@ -516,7 +683,7 @@ void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterat { ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end(); its--; - (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end)); + (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end,&tagHT, &listEntries)); } } } @@ -524,11 +691,11 @@ void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterat /* * \ingroup gdcmDicomDir - * \brief + * \brief for each Header of the chained list, add/update the Patient/Study/Serie/Image info * @param path * @param list */ -void gdcmDicomDir::SetElements(std::string &path,ListHeader &list) +void gdcmDicomDir::SetElements(std::string &path, ListHeader &list) { std::string patPrevName="", patPrevID=""; std::string studPrevInstanceUID="", studPrevID=""; @@ -538,7 +705,7 @@ void gdcmDicomDir::SetElements(std::string &path,ListHeader &list) std::string studCurInstanceUID, studCurID; std::string serCurInstanceUID, serCurID; - SetElement(path,GDCM_DICOMDIR_NONE,NULL); + SetElement(path,GDCM_DICOMDIR_META,NULL); ListTag::iterator debPat=listEntries.begin(); for(ListHeader::iterator it=list.begin();it!=list.end();++it) @@ -576,10 +743,11 @@ void gdcmDicomDir::SetElements(std::string &path,ListHeader &list) /* * \ingroup gdcmDicomDir - * \brief - * @param path - * @param type - * @param header + * \brief adds to the HTable and at the end of the Chained List + * the gdcmEntries (Dicom Elements) corresponding to the given type + * @param path file Path (only used when type = GDCM_DICOMDIR_IMAGE + * @param type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...) + * @param header gdcmHeader of the current file */ void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header) { @@ -604,7 +772,7 @@ void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader case GDCM_DICOMDIR_IMAGE: elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements(); break; - case GDCM_DICOMDIR_NONE: + case GDCM_DICOMDIR_META: elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements(); break; default: @@ -650,7 +818,7 @@ void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader else { if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0) - val=val=it->value; + val=it->value; } entry->SetValue(val); @@ -678,8 +846,10 @@ void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader entry->SetLength(entry->GetValue().length()); } } - //listEntries.push_back(entry); - AddHeaderEntry(entry); + //AddHeaderEntry(entry); // both in H Table and in chained list + tagHT.insert( PairHT( entry->GetKey(),entry) ); + listEntries.push_back(entry); + //wasUpdated = 1; // is private } } diff --git a/src/gdcmDicomDir.h b/src/gdcmDicomDir.h index 5db25bd1..cd700d34 100644 --- a/src/gdcmDicomDir.h +++ b/src/gdcmDicomDir.h @@ -31,7 +31,8 @@ public: gdcmDicomDir(const char *FileName, bool parseDir = false, bool exception_on_error = false); - + gdcmDicomDir(bool exception_on_error = false); + ~gdcmDicomDir(void); void SetPrintLevel(int level) { printLevel = level; }; @@ -39,8 +40,18 @@ public: // Informations contained in the parser virtual bool IsReadable(void); - inline gdcmDicomDirMeta *GetDicomDirMeta() {return metaElems;}; - inline ListDicomDirPatient &GetDicomDirPatients() {return patients;}; +/** + * \ingroup gdcmDicomDir + * \brief returns a pointer to the gdcmDicomDirMeta for this DICOMDIR. + */ + inline gdcmDicomDirMeta *GetDicomDirMeta() + {return metaElems;}; +/** + * \ingroup gdcmDicomDir + * \brief returns the PATIENT chained List for this DICOMDIR. + */ + inline ListDicomDirPatient &GetDicomDirPatients() + {return patients;}; // Parsing void ParseDirectory(void); @@ -53,9 +64,11 @@ public: void SetEndMethodArgDelete(gdcmMethod *); inline float GetProgress(void) {return(progress);}; - - inline void AbortProgress(void) {abort=true;}; - inline bool IsAborted(void) {return(abort);}; + inline void AbortProgress(void){abort=true; }; + inline bool IsAborted(void) {return(abort); }; + +// Adding + gdcmDicomDirPatient * NewPatient(void); // Write bool Write(std::string fileName); @@ -72,7 +85,7 @@ public: } gdcmDicomDirType; protected: - void NewDicomDir(std::string path); + void CreateDicomDirChainedList(std::string path); std::string GetPath(void); void CallStartMethod(void); @@ -82,7 +95,7 @@ protected: private: void CreateDicomDir(void); void AddObjectToEnd(gdcmDicomDirType type, - ListTag::iterator begin,ListTag::iterator end); + ListTag::iterator begin,ListTag::iterator end); void AddDicomDirMetaToEnd (ListTag::iterator begin,ListTag::iterator end); void AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end); void AddDicomDirStudyToEnd (ListTag::iterator begin,ListTag::iterator end); @@ -95,8 +108,16 @@ private: void UpdateDirectoryRecordSequenceLength(void); static bool HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2); - + void WriteDicomDirEntries(FILE *_fp); + +// Variables +/** +* \brief pointer on *the* gdcmObject 'DicomDirMeta Elements' +*/ gdcmDicomDirMeta *metaElems; +/** +* \brief chained list of DicomDirPatient (to be exploited recursively) +*/ ListDicomDirPatient patients; gdcmMethod *startMethod; diff --git a/src/gdcmDicomDirElement.cxx b/src/gdcmDicomDirElement.cxx index d7197ce9..35746ab9 100644 --- a/src/gdcmDicomDirElement.cxx +++ b/src/gdcmDicomDirElement.cxx @@ -24,7 +24,8 @@ /** * \ingroup gdcmDicomDirElement - * \brief constructor + * \brief constructor : populates the chained lists + * from the file 'Dicts/DicomDir.dic' */ gdcmDicomDirElement::gdcmDicomDirElement(void) { std::string filename=gdcmDictSet::BuildDictPath() + std::string(DICT_ELEM); diff --git a/src/gdcmDicomDirElement.h b/src/gdcmDicomDirElement.h index f813bca4..a11f4846 100644 --- a/src/gdcmDicomDirElement.h +++ b/src/gdcmDicomDirElement.h @@ -10,8 +10,11 @@ //----------------------------------------------------------------------------- typedef struct { - unsigned short int group; + /// DicomGroup number + unsigned short int group; + /// DicomElement number unsigned short int elem; + /// value (coded as a std::string) of the Element std::string value; } gdcmElement; @@ -35,14 +38,40 @@ public: void Print(std::ostream &os); + +/** + * \ingroup gdcmDicomDirElement + * \brief returns a reference to the chained List + * related to the META Elements of a DICOMDIR. + */ ListDicomDirMetaElem &GetDicomDirMetaElements(void) {return(DicomDirMetaList);}; +/** + * \ingroup gdcmDicomDirElement + * \brief returns a reference to the chained List + * related to the PATIENT Elements of a DICOMDIR. + */ ListDicomDirPatientElem &GetDicomDirPatientElements(void) {return(DicomDirPatientList);}; +/** + * \ingroup gdcmDicomDirElement + * \brief returns a reference to the chained List + * related to the STUDY Elements of a DICOMDIR. + */ ListDicomDirStudyElem &GetDicomDirStudyElements(void) {return(DicomDirStudyList);}; +/** + * \ingroup gdcmDicomDirElement + * \brief returns a reference to the chained List + * related to the SERIE Elements of a DICOMDIR. + */ ListDicomDirSerieElem &GetDicomDirSerieElements(void) {return(DicomDirSerieList);}; +/** + * \ingroup gdcmDicomDirElement + * \brief returns a reference to the chained List + * related to the IMAGE Elements of a DICOMDIR. + */ ListDicomDirImageElem &GetDicomDirImageElements(void) {return(DicomDirImageList);}; diff --git a/src/gdcmDicomDirImage.cxx b/src/gdcmDicomDirImage.cxx index 00a54a20..1d089869 100644 --- a/src/gdcmDicomDirImage.cxx +++ b/src/gdcmDicomDirImage.cxx @@ -4,19 +4,31 @@ //----------------------------------------------------------------------------- // Constructor / Destructor + /** * \ingroup gdcmDicomDirImage * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object + * @param begin iterator (inside the gdcmParser chained list) + * on the first Header Entry (i.e Dicom Element) + * related to this "IMAGE" part + * @param end iterator (inside the gdcmParser chained list) + * on the last Header Entry (i.e Dicom Element) + * related to this 'IMAGE' part + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) */ -gdcmDicomDirImage::gdcmDicomDirImage(ListTag::iterator begin,ListTag::iterator end): - gdcmObject(begin,end) +gdcmDicomDirImage::gdcmDicomDirImage(ListTag::iterator begin, + ListTag::iterator end, + TagHeaderEntryHT *ptagHT, + ListTag *plistEntries): + gdcmObject(begin,end,ptagHT,plistEntries) { } /** - * \ingroup gdcmImage + * \ingroup gdcmDicomDirImage * \brief Canonical destructor. */ gdcmDicomDirImage::~gdcmDicomDirImage() diff --git a/src/gdcmDicomDirImage.h b/src/gdcmDicomDirImage.h index 4f1173d9..835167e6 100644 --- a/src/gdcmDicomDirImage.h +++ b/src/gdcmDicomDirImage.h @@ -6,13 +6,21 @@ #include "gdcmObject.h" //----------------------------------------------------------------------------- -class GDCM_EXPORT gdcmDicomDirImage : public gdcmObject -{ +class GDCM_EXPORT gdcmDicomDirImage : public gdcmObject { public: - gdcmDicomDirImage(ListTag::iterator begin,ListTag::iterator end); + gdcmDicomDirImage(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); + ~gdcmDicomDirImage(void); virtual void Print(std::ostream &os = std::cout); + +/** + * \ingroup gdcmDicomDirImage + * \brief TODO + */ + gdcmDicomDirImage* NewImage(void); + }; //----------------------------------------------------------------------------- diff --git a/src/gdcmDicomDirMeta.cxx b/src/gdcmDicomDirMeta.cxx index 94584760..3d62dc36 100644 --- a/src/gdcmDicomDirMeta.cxx +++ b/src/gdcmDicomDirMeta.cxx @@ -4,14 +4,26 @@ //----------------------------------------------------------------------------- // Constructor / Destructor + /** - * \ingroup gdcmDicomDirMeta - * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object - */ -gdcmDicomDirMeta::gdcmDicomDirMeta(ListTag::iterator begin,ListTag::iterator end): - gdcmObject(begin,end) + * \ingroup gdcmMeta + * \brief Constructor + * @param begin iterator (inside the gdcmParser chained list) + * on the first Header Entry (i.e Dicom Element) + * related to the "META" part + * @param end iterator (inside the gdcmParser chained list) + * on the last Header Entry (i.e Dicom Element) + * related to the 'META' part + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) + */ +gdcmDicomDirMeta::gdcmDicomDirMeta(ListTag::iterator begin, + ListTag::iterator end, + TagHeaderEntryHT *ptagHT, + ListTag *plistEntries): + gdcmObject(begin,end,ptagHT,plistEntries) { } diff --git a/src/gdcmDicomDirMeta.h b/src/gdcmDicomDirMeta.h index abc5d010..c3437193 100644 --- a/src/gdcmDicomDirMeta.h +++ b/src/gdcmDicomDirMeta.h @@ -9,7 +9,9 @@ class GDCM_EXPORT gdcmDicomDirMeta : public gdcmObject { public: - gdcmDicomDirMeta(ListTag::iterator begin,ListTag::iterator end); + gdcmDicomDirMeta(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); + ~gdcmDicomDirMeta(void); virtual void Print(std::ostream &os = std::cout); diff --git a/src/gdcmDicomDirPatient.cxx b/src/gdcmDicomDirPatient.cxx index 007eeaf0..2859349e 100644 --- a/src/gdcmDicomDirPatient.cxx +++ b/src/gdcmDicomDirPatient.cxx @@ -1,17 +1,29 @@ // gdcmDicomDirPatient.cxx //----------------------------------------------------------------------------- #include "gdcmDicomDirPatient.h" - +#include "gdcmDicomDirElement.h" +#include "gdcmUtil.h" //----------------------------------------------------------------------------- // Constructor / Destructor /** * \ingroup gdcmDicomDirPatient - * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object + * \brief Constructor + * @param begin iterator (inside the gdcmParser chained list) + * on the first Header Entry (i.e Dicom Element) + * related to this "PATIENT" part + * @param end iterator (inside the gdcmParser chained list) + * on the last Header Entry (i.e Dicom Element) + * related to this 'PATIENT' part + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) */ -gdcmDicomDirPatient::gdcmDicomDirPatient(ListTag::iterator begin,ListTag::iterator end): - gdcmObject(begin,end) +gdcmDicomDirPatient::gdcmDicomDirPatient(ListTag::iterator begin, + ListTag::iterator end, + TagHeaderEntryHT *ptagHT, + ListTag *plistEntries): + gdcmObject(begin,end,ptagHT,plistEntries) { } @@ -49,6 +61,23 @@ void gdcmDicomDirPatient::Print(std::ostream &os) //----------------------------------------------------------------------------- // Public +/* + * \ingroup gdcmDicomDir + * \brief adds a new Patient at the begining of the PatientList + * of a partially created DICOMDIR + */ +gdcmDicomDirStudy * gdcmDicomDirPatient::NewStudy(void) { + std::list elemList; + elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements(); + + FillObject(elemList); + gdcmDicomDirStudy *st = new gdcmDicomDirStudy(i, j, ptagHT, plistEntries); + studies.push_front(st); + return st; + + +} + //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmDicomDirPatient.h b/src/gdcmDicomDirPatient.h index 2868f42a..3569e505 100644 --- a/src/gdcmDicomDirPatient.h +++ b/src/gdcmDicomDirPatient.h @@ -13,15 +13,34 @@ typedef std::list ListDicomDirStudy; class GDCM_EXPORT gdcmDicomDirPatient : public gdcmObject { public: - gdcmDicomDirPatient(ListTag::iterator begin,ListTag::iterator end); + gdcmDicomDirPatient(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); ~gdcmDicomDirPatient(void); virtual void Print(std::ostream &os = std::cout); - - inline ListDicomDirStudy &GetDicomDirStudies() {return studies;}; - inline void AddDicomDirStudy(gdcmDicomDirStudy *obj) {studies.push_back(obj);}; - +/** + * \ingroup gdcmDicomDirPatient + * \brief returns the STUDY chained List for this PATIENT. + */ + inline ListDicomDirStudy &GetDicomDirStudies() + {return studies;}; +/** + * \ingroup gdcmDicomDirPatient + * \brief adds the passed STUDY to the STUDY chained List for this PATIENT. + */ + inline void AddDicomDirStudy(gdcmDicomDirStudy *obj) + {studies.push_back(obj);}; +/** + * \ingroup gdcmDicomDirPatient + * \brief TODO + */ + gdcmDicomDirStudy* NewStudy(void); + private: + +/** +* \brief chained list of DicomDirStudy +*/ ListDicomDirStudy studies; }; diff --git a/src/gdcmDicomDirSerie.cxx b/src/gdcmDicomDirSerie.cxx index a9f2d965..1415d6cd 100644 --- a/src/gdcmDicomDirSerie.cxx +++ b/src/gdcmDicomDirSerie.cxx @@ -1,17 +1,29 @@ // gdcmDicomDirSerie.cxx //----------------------------------------------------------------------------- #include "gdcmDicomDirSerie.h" - +#include "gdcmDicomDirElement.h" +#include "gdcmUtil.h" //----------------------------------------------------------------------------- // Constructor / Destructor /** * \ingroup gdcmDicomDirSerie * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object + * @param begin iterator (inside the gdcmParser chained list) + * on the first Header Entry (i.e Dicom Element) + * related to this "SERIE" part + * @param end iterator (inside the gdcmParser chained list) + * on the last Header Entry (i.e Dicom Element) + * related to this 'SERIE' part + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) */ -gdcmDicomDirSerie::gdcmDicomDirSerie(ListTag::iterator begin,ListTag::iterator end): - gdcmObject(begin,end) +gdcmDicomDirSerie::gdcmDicomDirSerie(ListTag::iterator begin, + ListTag::iterator end, + TagHeaderEntryHT *ptagHT, + ListTag *plistEntries ): + gdcmObject(begin,end,ptagHT,plistEntries) { } @@ -48,7 +60,21 @@ void gdcmDicomDirSerie::Print(std::ostream &os) //----------------------------------------------------------------------------- // Public +/* + * \ingroup gdcmDicomSerie + * \brief adds a new Image to a partially created DICOMDIR + */ +gdcmDicomDirImage * gdcmDicomDirSerie::NewImage(void) { + std::list elemList; + elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements(); + + FillObject(elemList); + gdcmDicomDirImage *st = new gdcmDicomDirImage(i, j, ptagHT, plistEntries); + images.push_front(st); + return st; + +} //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmDicomDirSerie.h b/src/gdcmDicomDirSerie.h index 9554d39a..d9df59fd 100644 --- a/src/gdcmDicomDirSerie.h +++ b/src/gdcmDicomDirSerie.h @@ -13,15 +13,34 @@ typedef std::list ListDicomDirImage; class GDCM_EXPORT gdcmDicomDirSerie : public gdcmObject { public: - gdcmDicomDirSerie(ListTag::iterator begin,ListTag::iterator end); + gdcmDicomDirSerie(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); ~gdcmDicomDirSerie(void); virtual void Print(std::ostream &os = std::cout); +/** + * \ingroup gdcmDicomDirSerie + * \brief returns the IMAGE chained List for this SERIE. + */ + inline ListDicomDirImage &GetDicomDirImages() + {return images;}; +/** + * \ingroup gdcmDicomDirSerie + * \brief adds the passed IMAGE to the IMAGE chained List for this SERIE. + */ + inline void AddDicomDirImage(gdcmDicomDirImage *obj) + {images.push_back(obj);}; - inline ListDicomDirImage &GetDicomDirImages() {return images;}; - inline void AddDicomDirImage(gdcmDicomDirImage *obj) {images.push_back(obj);}; - +/** + * \ingroup gdcmDicomDirSerie + * \brief TODO + */ + gdcmDicomDirImage* NewImage(void); + private: +/** +* \brief chained list of DicomDirImages +*/ ListDicomDirImage images; }; diff --git a/src/gdcmDicomDirStudy.cxx b/src/gdcmDicomDirStudy.cxx index fd8e886b..417af762 100644 --- a/src/gdcmDicomDirStudy.cxx +++ b/src/gdcmDicomDirStudy.cxx @@ -1,17 +1,30 @@ // gdcmDicomDirStudy.cxx //----------------------------------------------------------------------------- #include "gdcmDicomDirStudy.h" - +#include "gdcmDicomDirElement.h" +#include "gdcmUtil.h" //----------------------------------------------------------------------------- // Constructor / Destructor + /** * \ingroup gdcmDicomDirStudy - * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object + * \brief constructor + * @param begin iterator (inside the gdcmParser chained list) + * on the first Header Entry (i.e Dicom Element) + * related to this "STUDY" part + * @param end iterator (inside the gdcmParser chained list) + * on the last Header Entry (i.e Dicom Element) + * related to this 'STUDY' part + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) */ -gdcmDicomDirStudy::gdcmDicomDirStudy(ListTag::iterator begin,ListTag::iterator end): - gdcmObject(begin,end) +gdcmDicomDirStudy::gdcmDicomDirStudy(ListTag::iterator begin, + ListTag::iterator end, + TagHeaderEntryHT *ptagHT, + ListTag *plistEntries): + gdcmObject(begin,end,ptagHT,plistEntries) { } @@ -49,6 +62,21 @@ void gdcmDicomDirStudy::Print(std::ostream &os) //----------------------------------------------------------------------------- // Public +/* + * \ingroup gdcmDicomStudy + * \brief adds a new Serie at the begining of the SerieList + * of a partially created DICOMDIR + */ +gdcmDicomDirSerie * gdcmDicomDirStudy::NewSerie(void) { + + std::list elemList; + elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements(); + + FillObject(elemList); + gdcmDicomDirSerie *st = new gdcmDicomDirSerie(i, j, ptagHT, plistEntries); + series.push_front(st); + return st; +} //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmDicomDirStudy.h b/src/gdcmDicomDirStudy.h index 4c69b7b0..91b24d56 100644 --- a/src/gdcmDicomDirStudy.h +++ b/src/gdcmDicomDirStudy.h @@ -12,15 +12,35 @@ typedef std::list ListDicomDirSerie; //----------------------------------------------------------------------------- class GDCM_EXPORT gdcmDicomDirStudy : public gdcmObject { public: - gdcmDicomDirStudy(ListTag::iterator begin,ListTag::iterator end); + gdcmDicomDirStudy(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); + ~gdcmDicomDirStudy(void); virtual void Print(std::ostream &os = std::cout); +/** + * \ingroup gdcmDicomDirStudy + * \brief returns the SERIE chained List for this STUDY. + */ + inline ListDicomDirSerie &GetDicomDirSeries() + {return series;}; +/** + * \ingroup gdcmDicomDirStudy + * \brief adds the passed SERIE to the SERIE chained List for this STUDY. + */ + inline void AddDicomDirSerie(gdcmDicomDirSerie *obj) + {series.push_back(obj);}; - inline ListDicomDirSerie &GetDicomDirSeries() {return series;}; - inline void AddDicomDirSerie(gdcmDicomDirSerie *obj) {series.push_back(obj);}; - +/** + * \ingroup gdcmDicomDirStudy + * \brief TODO + */ + gdcmDicomDirSerie* NewSerie(void); + private: +/** +* \brief chained list of DicomDirSeries (to be exploited recursively) +*/ ListDicomDirSerie series; }; diff --git a/src/gdcmDict.h b/src/gdcmDict.h index b901f57a..10a58569 100644 --- a/src/gdcmDict.h +++ b/src/gdcmDict.h @@ -57,8 +57,8 @@ public: inline TagKeyHT & gdcmDict::GetEntries(void) { return KeyHt; } private: + /// ASCII file holding the Dictionnary std::string filename; - /// Access through TagKey (see alternate access with NameHt) TagKeyHT KeyHt; /// Access through TagName (see alternate access with KeyHt) diff --git a/src/gdcmDictEntry.h b/src/gdcmDictEntry.h index 1fbe25bd..cd329bd1 100644 --- a/src/gdcmDictEntry.h +++ b/src/gdcmDictEntry.h @@ -91,21 +91,34 @@ public: inline std::string GetKey(void) { return key; } private: - // FIXME : were are the group and element used except from building up + // FIXME : where are the group and element used except from building up // a TagKey. If the answer is nowhere then there is no need // to store the group and element independently. + // + // --> EVERYWHERE ! The alternate question would be : + // What's TagKey used for ? + + /// DicomGroup number guint16 group; // e.g. 0x0010 + /// DicomElement number guint16 element; // e.g. 0x0103 - std::string vr; // Value Representation i.e. some clue about the nature - // of the data represented e.g. "FD" short for - // "Floating Point Double" + /// Value Representation i.e. some clue about the nature + /// of the data represented e.g. "FD" short for + /// "Floating Point Double" + std::string vr; + // CLEANME: find the official dicom name for this field ! - std::string fourth; // Fourth field containing some semantics. - //(Group Name abbr.) - std::string name; // e.g. "Patient_Name" - TagKey key; // Redundant with (group, element) but we add it - // on efficiency purposes. - + + ///Fourth field containing some semantics. + ///(Group Name abbr.) + /// DON'T USER ANY LONGER ! + std::string fourth; + /// e.g. "Patient_Name" + std::string name; + /// Redundant with (group, element) but we add it + /// on efficiency purposes. + TagKey key; + // DCMTK has many fields for handling a DictEntry (see below). What are the // relevant ones for gdcmlib ? // struct DBI_SimpleEntry { diff --git a/src/gdcmDirList.cxx b/src/gdcmDirList.cxx index 2bf597f1..64eda53e 100644 --- a/src/gdcmDirList.cxx +++ b/src/gdcmDirList.cxx @@ -30,7 +30,8 @@ const std::string gdcmDirList::SEPARATOR = "/"; /* * \ingroup gdcmDirList * \brief Constructor - * @param + * @param dirName + * @param recursive */ gdcmDirList::gdcmDirList(std::string dirName,bool recursive) { diff --git a/src/gdcmFile.h b/src/gdcmFile.h index 11c046db..29287b24 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -89,19 +89,29 @@ private: bool gdcm_read_RLE_file (FILE *fp,void * image_buffer); // Variables - gdcmHeader *Header; // Header to use to load the file + /// Header to use to load the file + gdcmHeader *Header; bool SelfHeader; void* PixelData; - size_t lgrTotaleRaw; // Area length to receive the pixels - size_t lgrTotale; // Area length to receive the RGB pixels - // from Grey Plane + Palette Color - int PixelRead; // ==1 if GetImageDataRaw was used - // ==0 if GetImageData was used - // ==-1 if ImageData never read. - - int Parsed; // weather already parsed - std::string OrigFileName; // To avoid file overwrite + + /// Area length to receive the pixels + size_t lgrTotaleRaw; + + /// Area length to receive the RGB pixels + /// from Grey Plane + Palette Color + size_t lgrTotale; + + /// ==1 if GetImageDataRaw was used + /// ==0 if GetImageData was used + /// ==-1 if ImageData never read + int PixelRead; + . + /// weather already parsed + int Parsed; + + /// To avoid file overwrite + std::string OrigFileName; }; //----------------------------------------------------------------------------- diff --git a/src/gdcmHeaderEntry.h b/src/gdcmHeaderEntry.h index 0bb7c593..dd228c60 100644 --- a/src/gdcmHeaderEntry.h +++ b/src/gdcmHeaderEntry.h @@ -199,28 +199,34 @@ private: // Variables gdcmDictEntry *entry; - guint32 UsableLength; // Updated from ReadLength, by FixFoungLentgh() - // for fixing a bug in the header - // or helping the parser going on - - guint32 ReadLength; // Length actually read on disk - // (before FixFoundLength) - // ReadLength will be updated only when - // FixFoundLength actually fixes a bug in the header, - // not when it performs a trick to help the Parser - // going on. - // *for internal* use only - - bool ImplicitVR; // Even when reading explicit vr files, some - // elements happen to be implicit. Flag them here - // since we can't use the entry->vr without breaking - // the underlying dictionary. + /// Updated from ReadLength, by FixFoungLentgh() + /// for fixing a bug in the header + /// or helping the parser going on + guint32 UsableLength; + /// Length actually read on disk + /// (before FixFoundLength) + /// ReadLength will be updated only when + /// FixFoundLength actually fixes a bug in the header, + /// not when it performs a trick to help the Parser + /// going on. + /// *for internal* use only + guint32 ReadLength; + /// Even when reading explicit vr files, some + /// elements happen to be implicit. Flag them here + /// since we can't use the entry->vr without breaking + /// the underlying dictionary. + bool ImplicitVR; + std::string value; - void *voidArea; // unsecure memory area to hold 'non string' values - // (ie : Lookup Tables, overlays) - size_t Offset; // Offset from the begining of file for direct user access + + /// unsecure memory area to hold 'non string' values + /// (ie : Lookup Tables, overlays) + void *voidArea; + /// Offset from the begining of file for direct user access + size_t Offset; + int printLevel; }; diff --git a/src/gdcmObject.cxx b/src/gdcmObject.cxx index 82ff5131..66c40a80 100644 --- a/src/gdcmObject.cxx +++ b/src/gdcmObject.cxx @@ -7,16 +7,23 @@ // Constructor / Destructor /** * \ingroup gdcmObject - * \brief - * @param begin iterator of begin for the object - * @param end iterator of end for the object + * \brief Constructor + * @param begin iterator on the first Header Entry (i.e Dicom Element) + * related to this 'Object' + * @param end iterator on the last Header Entry + * (i.e Dicom Element) related to this 'Object' + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + * @param plistEntries pointer to the chained List (gdcmObject needs it + * to build the gdcmHeaderEntries) */ -gdcmObject::gdcmObject(ListTag::iterator begin,ListTag::iterator end) -{ - beginObj=begin; - endObj=end; - - if(beginObj==endObj) +gdcmObject::gdcmObject(ListTag::iterator begin, ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries) { + beginObj = begin; + endObj = end; + this->ptagHT = ptagHT; + this->plistEntries = plistEntries; + if(begin==end) dbg.Verbose(0, "gdcmObject::gdcmObject empty list"); } @@ -24,8 +31,7 @@ gdcmObject::gdcmObject(ListTag::iterator begin,ListTag::iterator end) * \ingroup gdcmObject * \brief Canonical destructor. */ -gdcmObject::~gdcmObject(void) -{ +gdcmObject::~gdcmObject(void) { } //----------------------------------------------------------------------------- @@ -35,14 +41,14 @@ gdcmObject::~gdcmObject(void) * \brief Prints the Object * @return */ -void gdcmObject::Print(std::ostream &os) -{ - if(printLevel>=0) - { - for(ListTag::iterator i=beginObj;i!=endObj;++i) - { +void gdcmObject::Print(std::ostream &os) { + if(printLevel>=0) { + ListTag::iterator i; + //for(ListTag::iterator i=beginObj;i!=endObj;++i) // JPR + for(i=beginObj;;++i) { (*i)->SetPrintLevel(printLevel); (*i)->Print(os); + if (i == endObj) break; } } } @@ -51,28 +57,26 @@ void gdcmObject::Print(std::ostream &os) // Public /** * \ingroup gdcmObject - * \brief Get an entry by number + * \brief Get the value of an Header Entries (i.e Dicom Element) by number * @return */ -std::string gdcmObject::GetEntryByNumber(guint16 group, guint16 element) -{ - for(ListTag::iterator i=beginObj;i!=endObj;++i) - { +std::string gdcmObject::GetEntryByNumber(guint16 group, guint16 element) { + //for(ListTag::iterator i=beginObj;i!=endObj;++i) // JPR + for(ListTag::iterator i=beginObj;;++i) { if ( (*i)->GetGroup()==group && (*i)->GetElement()==element) return (*i)->GetValue(); - } - + if (i == endObj) break; + } return GDCM_UNFOUND; } /** * \ingroup gdcmObject - * \brief Get an entry by name - * @param name name of the searched element. + * \brief Get the value of an Header Entries (i.e Dicom Element) by name + * @param name : name of the searched element. * @return */ -std::string gdcmObject::GetEntryByName(TagName name) -{ +std::string gdcmObject::GetEntryByName(TagName name) { gdcmDict *PubDict=gdcmGlobal::GetDicts()->GetDefaultPubDict(); gdcmDictEntry *dictEntry = (*PubDict).GetDictEntryByName(name); @@ -81,43 +85,121 @@ std::string gdcmObject::GetEntryByName(TagName name) return GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()); } +/** + * \ingroup gdcmParser + * \brief Sets Entry (Dicom Element) value of an element, + * specified by it's tag (Group, Number) + * and the length, too ... + * @param val string value to set + * @param group Group of the searched tag. + * @param element Element of the searched tag. + * @return true if element was found, else false + */ + bool gdcmObject::SetEntryByNumber(std::string val,guint16 group, + guint16 element) { + + //for(ListTag::iterator i=beginObj;i!=endObj;++i) // JPR + for(ListTag::iterator i=beginObj;;++i) { + if ( (*i)->GetGroup()==group && (*i)->GetElement()==element) { + (*i)->SetValue(val); + (*i)->SetLength(val.length()+1); + return true; + } + if (i == endObj) break; + } + return false; +} /** * \ingroup gdcmObject - * \brief Get all entries in a hash table + * \brief Builds a hash table (multimap) containing + * pointers to all Header Entries (i.e Dicom Element) + * related to this 'object' * @return */ -TagHeaderEntryHT gdcmObject::GetEntry(void) -{ +TagHeaderEntryHT gdcmObject::GetEntry(void) { TagHeaderEntryHT HT; - - for(ListTag::iterator it=beginObj;it!=endObj;++it) - { - HT.insert( PairHT( (*it)->GetKey(),(*it)) ); + //for(ListTag::iterator i=beginObj;i!=endObj;++i) // JPR + for(ListTag::iterator i=beginObj;;++i) { + HT.insert( PairHT( (*i)->GetKey(),(*i)) ); + if (i == endObj) break; } - return(HT); } /** * \ingroup gdcmObject - * \brief Get all entries in a list + * \brief Builds a Chained List containing + * pointers to all Header Entries (i.e Dicom Element) + * related to this 'object' * @return */ -ListTag gdcmObject::GetListEntry(void) -{ +ListTag gdcmObject::GetListEntry(void) { ListTag list; - - for(ListTag::iterator it=beginObj;it!=endObj;++it) - { - list.push_back(*it); + //for(ListTag::iterator i=beginObj;i!=endObj;++i) // JPR + for(ListTag::iterator i=beginObj;;++i) { + list.push_back(*i); + if (i == endObj) break; } - return(list); } + //----------------------------------------------------------------------------- // Protected - +/* + * \ingroup gdcmObject + * \brief add the 'Object' related Dicom Elements to the listEntries + * of a partially created DICOMDIR + */ +void gdcmObject::FillObject(std::list elemList) { + std::list::iterator it; + guint16 tmpGr,tmpEl; + gdcmDictEntry *dictEntry; + gdcmHeaderEntry *entry; + + debInsertion = this->fin(); + ++debInsertion; + finInsertion=debInsertion; + + for(it=elemList.begin();it!=elemList.end();++it) + { + tmpGr=it->group; + tmpEl=it->elem; + dictEntry=gdcmGlobal::GetDicts()->GetDefaultPubDict()->GetDictEntryByNumber(tmpGr,tmpEl); + entry=new gdcmHeaderEntry(dictEntry); + entry->SetOffset(0); // just to avoid missprinting //JPR + entry->SetValue(it->value); + + if(dictEntry->GetGroup()==0xfffe) + { + entry->SetLength(entry->GetValue().length()); + } + else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) + { + entry->SetLength(4); + } + else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) + { + entry->SetLength(2); + } + else if(dictEntry->GetVR()=="SQ") + { + entry->SetLength(0xffffffff); + } + else + { + entry->SetLength(entry->GetValue().length()); + } + ptagHT->insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table + plistEntries->insert(debInsertion ,entry); // en tete de liste des Patients + ++finInsertion; + } + + i=fin(); + i++; + j=debInsertion; + j--; +} //----------------------------------------------------------------------------- // Private diff --git a/src/gdcmObject.h b/src/gdcmObject.h index 0c745e0a..f236d591 100644 --- a/src/gdcmObject.h +++ b/src/gdcmObject.h @@ -8,7 +8,7 @@ #include "gdcmCommon.h" #include "gdcmHeaderEntry.h" #include "gdcmParser.h" - +#include "gdcmDicomDirElement.h" //----------------------------------------------------------------------------- class gdcmObject; typedef std::list ListContent; @@ -17,7 +17,8 @@ typedef std::list ListContent; class GDCM_EXPORT gdcmObject { public: - gdcmObject(ListTag::iterator begin,ListTag::iterator end); + gdcmObject(ListTag::iterator begin,ListTag::iterator end, + TagHeaderEntryHT *ptagHT, ListTag *plistEntries); ~gdcmObject(void); void SetPrintLevel(int level) { printLevel = level; }; @@ -25,19 +26,66 @@ public: std::string GetEntryByNumber(guint16 group, guint16 element); std::string GetEntryByName(TagName name); - + bool SetEntryByNumber(std::string val,guint16 group,guint16 element); + TagHeaderEntryHT GetEntry(void); ListTag GetListEntry(void); - ListTag::iterator debut(void) { return(beginObj);} - ListTag::iterator fin (void) { return(endObj); } +/** + * \ingroup gdcmObject + * \brief returns an iterator on the first Header Entry (i.e Dicom Element), + * inside the DICOMDIR chained list, + * related to this 'Object' + * @return + */ + ListTag::iterator debut(void) + { return(beginObj);} +/** + * \ingroup gdcmObject + * \brief returns an iterator on the last Header Entry (i.e Dicom Element), + * inside the DICOMDIR chained list, + * related to this 'Object' + * @return + */ + ListTag::iterator fin (void) + { return(endObj); } protected: - + +void FillObject(std::list elemList); + +/** +* \brief iterator on the first Header Entry (i.e Dicom Element), +* inside the DICOMDIR chained list, +* related to this 'Object' +*/ ListTag::iterator beginObj; +/** +* \brief iterator on the last Header Entry (i.e Dicom Element), +* inside the DICOMDIR chained list, +* related to this 'Object' +*/ ListTag::iterator endObj; +/** +* \brief pointer to the HTable of the gdcmParser, +* (because we don't know it within any gdcmObject) +*/ + TagHeaderEntryHT *ptagHT; +/** +* \brief pointer to the Chained List of the gdcmParser, +* (because we don't know it within any gdcmObject) +*/ + ListTag *plistEntries; +/** +* \brief +*/ int printLevel; + +/// used to pass variables to FillObject function +/// Work as 'global' variables + std::list::iterator debInsertion, finInsertion, i,j; private: + }; //----------------------------------------------------------------------------- diff --git a/src/gdcmParser.cxx b/src/gdcmParser.cxx index 42db7b9f..60dd01ba 100644 --- a/src/gdcmParser.cxx +++ b/src/gdcmParser.cxx @@ -65,8 +65,8 @@ // // Other usefull abreviations : - //Radiographic view associated with Patient Position (0018,5100). - // Defined Terms: + // Radiographic view associated with Patient Position (0018,5100). + // Defined Terms: // // AP = Anterior/Posterior // PA = Posterior/Anterior @@ -95,7 +95,7 @@ const unsigned int gdcmParser::MAX_SIZE_PRINT_ELEMENT_VALUE = 64; * \ingroup gdcmParser * \brief constructor * @param inFilename - * @param exception_on_error + * @param exception_on_error whether we 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 @@ -1021,19 +1021,14 @@ void gdcmParser::UpdateGroupLength(bool SkipSequence, FileType type) { /** * \ingroup gdcmParser * \brief writes on disc according to the requested format - * (ACR-NEMA, ExplicitVR, ImplicitVR) the image - * using the Chained List - * \warning does NOT add the missing elements in the header : - * it's up to the user doing it ! - * (function CheckHeaderCoherence to be written) - * \warning DON'T try, right now, to write a DICOM image - * from an ACR Header (meta elements will be missing!) - * \sa WriteEntriesDeprecated (Special temporay method for Theralys) + * (ACR-NEMA, ExplicitVR, ImplicitVR) ONE + * gdcmHeaderEntry + * @param tag pointer on the gdcmHeaderEntry to be written * @param type type of the File to be written * (ACR-NEMA, ExplicitVR, ImplicitVR) * @param _fp already open file pointer */ -void gdcmParser::WriteEntries(FILE *_fp,FileType type) +void gdcmParser::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type) { guint16 gr, el; guint32 lgr; @@ -1045,46 +1040,36 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) guint16 valZero =0; void *voidArea; std::vector tokens; - - // TODO : function CheckHeaderCoherence to be written - - // uses now listEntries to iterate, not TagHt! - // - // pb : gdcmParser.Add does NOT update listEntries - // TODO : find a trick (in STL?) to do it, at low cost ! void *ptr; int ff=0xffffffff; // TODO (?) tester les echecs en ecriture (apres chaque fwrite) int compte =0; - - for (ListTag::iterator tag2=listEntries.begin(); - tag2 != listEntries.end(); - ++tag2) - { + itsTimeToWritePixels = false; + // === Deal with the length // -------------------- - if(((*tag2)->GetLength())%2==1) + if((tag->GetLength())%2==1) { - (*tag2)->SetValue((*tag2)->GetValue()+"\0"); - (*tag2)->SetLength((*tag2)->GetReadLength()+1); + tag->SetValue(tag->GetValue()+"\0"); + tag->SetLength(tag->GetReadLength()+1); } - gr = (*tag2)->GetGroup(); - el = (*tag2)->GetElement(); - lgr = (*tag2)->GetReadLength(); - val = (*tag2)->GetValue().c_str(); - vr = (*tag2)->GetVR(); - voidArea = (*tag2)->GetVoidArea(); + gr = tag->GetGroup(); + el = tag->GetElement(); + lgr = tag->GetReadLength(); + val = tag->GetValue().c_str(); + vr = tag->GetVR(); + voidArea = tag->GetVoidArea(); if ( type == ACR ) { - if (gr < 0x0008) continue; // ignore pure DICOM V3 groups - if (gr %2) continue; // ignore shadow groups - if (vr == "SQ" ) continue; // ignore Sequences + if (gr < 0x0008) return; // ignore pure DICOM V3 groups + if (gr %2) return; // ignore shadow groups + if (vr == "SQ" ) return; // ignore Sequences // TODO : find a trick to *skip* the SeQuences ! // Not only ignore the SQ element - if (gr == 0xfffe ) continue; // ignore delimiters + if (gr == 0xfffe ) return; // ignore delimiters } fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group @@ -1097,7 +1082,7 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) if (gr == 0xfffe) { // NO Value Representation for 'delimiters' // no length : write ffffffff fwrite (&ff,(size_t)4 ,(size_t)1 ,_fp); - continue; // NO value for 'delimiters' + return; // NO value for 'delimiters' } shortLgr=lgr; @@ -1122,19 +1107,19 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) // === Deal with the value // ------------------- - if (vr == "SQ") continue; // no "value" to write for the SEQuences - if (gr == 0xfffe)continue; // no "value" to write for the delimiters + if (vr == "SQ") return; // no "value" to write for the SEQuences + if (gr == 0xfffe)return; // no "value" to write for the delimiters if (voidArea != NULL) { // there is a 'non string' LUT, overlay, etc fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value - continue; + return; } if (vr == "US" || vr == "SS") { tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize ((*tag2)->GetValue(), tokens, "\\"); + Tokenize (tag->GetValue(), tokens, "\\"); for (unsigned int i=0; iGetValue(), tokens, "\\"); + Tokenize (tag->GetValue(), tokens, "\\"); for (unsigned int i=0; i tokens; - 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) for (TagHeaderEntryHT::iterator tag2=tagHT.begin(); tag2 != tagHT.end(); ++tag2){ - - gr = tag2->second->GetGroup(); - el = tag2->second->GetElement(); - lgr = tag2->second->GetLength(); - val = tag2->second->GetValue().c_str(); - vr = tag2->second->GetVR(); - - // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl; - - if ( type == ACR ) { - if (gr < 0x0008) continue; // ignore pure DICOM V3 groups - if (gr %2) continue; // ignore shadow groups - if (vr == "SQ" ) continue; // ignore Sequences - if (gr == 0xfffe ) continue; // ignore delimiters - } - - fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group - fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element - - if ( (type == ExplicitVR) && (gr <= 0x0002) ) { - // EXPLICIT VR - guint16 z=0, shortLgr; - fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp); - - if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) { - fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp); - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp); - - } else { - shortLgr=lgr; - fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp); - } - } else { // IMPLICIT VR - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp); - } - - if (vr == "US" || vr == "SS") { - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (tag2->second->GetValue(), tokens, "\\"); - for (unsigned int i=0; isecond->GetValue(), tokens, "\\"); - for (unsigned int i=0; isecond,_fp,type); + if (itsTimeToWritePixels) + break; } } - - - - - /** * \ingroup gdcmParser * \brief Swaps back the bytes of 4-byte long integer accordingly to @@ -1524,7 +1464,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry) { /** * \ingroup gdcmParser * \brief add a new Dicom Element pointer to - * the H Table and to the chained List + * the H Table and at the end of the chained List * \warning push_bash in listEntries ONLY during ParseHeader * \todo something to allow further Elements addition, * (at their right place in the chained list) @@ -1965,7 +1905,7 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 Found /** * \ingroup gdcmParser - * \brief Apply some heuristics to predict wether the considered + * \brief Apply some heuristics to predict whether the considered * element value contains/represents an integer or not. * @param Entry The element value on which to apply the predicate. * @return The result of the heuristical predicate. @@ -2104,7 +2044,7 @@ guint32 gdcmParser::ReadInt32(void) { /** * \ingroup gdcmParser - * \brief + * \brief skips bytes inside the source file * \warning NOT end user intended method ! * @return */ @@ -2115,7 +2055,8 @@ void gdcmParser::SkipBytes(guint32 NBytes) { /** * \ingroup gdcmParser - * \brief + * \brief Loads all the needed Dictionaries + * \warning NOT end user intended method ! */ void gdcmParser::Initialise(void) { @@ -2310,7 +2251,8 @@ bool gdcmParser::CheckSwap() { /** * \ingroup gdcmParser - * \brief + * \brief Restore the unproperly loaded values i.e. the group, the element + * and the dictionary entry depending on them. */ void gdcmParser::SwitchSwapToBigEndian(void) { diff --git a/src/gdcmParser.h b/src/gdcmParser.h index 8c976a63..8767a1d4 100644 --- a/src/gdcmParser.h +++ b/src/gdcmParser.h @@ -48,13 +48,15 @@ public: * \brief Sets the print level for the Dicom Header * \note 0 for Light Print; 1 for 'medium' Print, 2 for Heavy */ - void SetPrintLevel(int level) { printLevel = level; }; + void SetPrintLevel(int level) + { printLevel = level; }; /** * \ingroup gdcmParser * \brief canonical Printer * \sa SetPrintLevel */ - virtual void Print (std::ostream &os = std::cout) {PrintEntry(os);}; + virtual void Print (std::ostream &os = std::cout) + {PrintEntry(os);}; virtual void PrintEntry (std::ostream &os = std::cout); virtual void PrintPubDict (std::ostream &os = std::cout); virtual void PrintShaDict (std::ostream &os = std::cout); @@ -64,7 +66,8 @@ public: * \ingroup gdcmParser * \brief Gets the external File Name */ - inline std::string GetFileName(void) {return filename;} + inline std::string GetFileName(void) + {return filename;} // Dictionnaries gdcmDict *GetPubDict(void); @@ -132,7 +135,7 @@ protected: virtual int GetEntryLengthByNumber(guint16 group, guint16 element); virtual bool SetEntryByName (std::string content, std::string tagName); - virtual bool SetEntryByNumber(std::string content, guint16 group, guint16 element); + virtual bool SetEntryByNumber(std::string content, guint16 group, guint16 element); virtual bool SetEntryLengthByNumber(guint32 length, guint16 group, guint16 element); virtual size_t GetEntryOffsetByNumber (guint16 Group, guint16 Elem); @@ -151,6 +154,7 @@ protected: void LoadHeaderEntrySafe(gdcmHeaderEntry *); void UpdateGroupLength(bool SkipSequence = false, FileType type = ImplicitVR); + void WriteEntry(gdcmHeaderEntry *tag,FILE *_fp,FileType type); void WriteEntries(FILE *_fp,FileType type); void WriteEntriesDeprecated(FILE *_fp,FileType type); // JPR @@ -203,6 +207,10 @@ protected: * Let's remember how many times! */ int countGrPixel; + /** + * \brief = true when the 'pixel Element' is reached during writting process + */ + bool itsTimeToWritePixels; private: // Read @@ -241,9 +249,10 @@ private: std::string vr = "unkn", std::string fourth = "unkn", std::string name = "unkn"); - gdcmDictEntry *NewVirtualDictEntry(gdcmHeaderEntry *); + //gdcmDictEntry *NewVirtualDictEntry(gdcmHeaderEntry *); // never defined // HeaderEntry related utilities + gdcmHeaderEntry *ReadNextHeaderEntry (void); gdcmHeaderEntry *NewHeaderEntryByNumber(guint16 group, guint16 element); @@ -252,35 +261,53 @@ private: // Deprecated (Not used) --> commented out //gdcmHeaderEntry *NewManualHeaderEntryToPubDict(std::string NewTagName, - // std::string VR); + // std::string VR); + guint32 GenerateFreeTagKeyInGroup(guint16 group); - // Refering underlying filename. + /** + * \brief Refering underlying filename. + */ std::string filename; - // Public dictionary used to parse this header + /** + * \brief Public dictionary used to parse this header + */ gdcmDict *RefPubDict; - // Optional "shadow dictionary" (private elements) used to parse this header + + /** + * \brief Optional "shadow dictionary" (private elements) used to parse this header + */ gdcmDict *RefShaDict; - // = 1 if a gdcmHeaderEntry was added post parsing + /** + * \brief = 1 if a gdcmHeaderEntry was added post parsing + */ int wasUpdated; - // =1 if user wants to skip shadow groups while parsing (to save space) + /** + * \brief =1 if user wants to skip shadow groups while parsing (to save space) + */ int ignoreShadow; - - // Swap code e.g. little, big, bad-big, bad-little endian). Warning: - // this code is not fixed during header parsing. + + /** + * \brief Swap code e.g. little, big, bad-big, bad-little endian). + * \warning : this code is not fixed during header parsing. + */ int sw; - - // Size treshold above which an element value will NOT be loaded in - // memory (to avoid loading the image/volume itself). By default, - // this upper bound is fixed to 1024 bytes (which might look reasonable - // when one considers the definition of the various VR contents). + /** + * \brief Size treshold above which an element value will NOT be loaded in + * memory (to avoid loading the image/volume itself). By default, + * this upper bound is fixed to 1024 bytes (which might look reasonable + * when one considers the definition of the various VR contents). + */ guint32 MaxSizeLoadEntry; - // Size treshold above which an element value will NOT be *printed* in - // order no to polute the screen output. By default, - // this upper bound is fixed to 64 bytes. + + /** + * \brief Size treshold above which an element value will NOT be *printed* in + * order no to polute the screen output. + * By default, this upper bound is fixed to 64 bytes. + */ guint32 MaxSizePrintEntry; };