From 06c1c583239fdf5196260e6ef83a78669c1bd17f Mon Sep 17 00:00:00 2001 From: regrain Date: Tue, 13 Jan 2004 15:27:03 +0000 Subject: [PATCH] * src/*.[h|cxx] : coding style -- BeNours --- ChangeLog | 3 + src/gdcm.h | 7 +- src/gdcmCommon.h | 4 +- src/gdcmDict.cxx | 101 +- src/gdcmDict.h | 46 +- src/gdcmDictEntry.cxx | 24 +- src/gdcmDictEntry.h | 196 +- src/gdcmDictSet.cxx | 147 +- src/gdcmDictSet.h | 35 +- src/gdcmElValSet.cxx | 197 +- src/gdcmElValSet.h | 66 +- src/gdcmElValue.cxx | 19 +- src/gdcmElValue.h | 171 +- src/gdcmException.cxx | 12 +- src/gdcmException.h | 142 +- src/gdcmFile.cxx | 692 ++++--- src/gdcmFile.h | 70 +- src/gdcmHeader.cxx | 3781 +++++++++++++++++++------------------- src/gdcmHeader.h | 299 +-- src/gdcmHeaderHelper.cxx | 438 ++--- src/gdcmHeaderHelper.h | 119 +- src/gdcmJpeg.cxx | 228 ++- src/gdcmJpeg12.cxx | 350 ++-- src/gdcmJpeg2000.cxx | 11 +- src/gdcmParse.cxx | 8 +- src/gdcmRLE.cxx | 44 +- src/gdcmTS.cxx | 17 +- src/gdcmTS.h | 11 +- src/gdcmUtil.cxx | 59 +- src/gdcmUtil.h | 31 +- src/gdcmVR.cxx | 17 +- src/gdcmVR.h | 10 +- 32 files changed, 3664 insertions(+), 3691 deletions(-) diff --git a/ChangeLog b/ChangeLog index cdfae207..64caba12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2004-01-13 Benoit Regrain + * src/*.[h|cxx] : coding style + 2004-01-13 Benoit Regrain * gdcmPython/testSuite.py : test the readable flag of file for tests * src/gdcmDict.cxx, gdcmElValSet.cxx : bug fix under windows for prints. diff --git a/src/gdcm.h b/src/gdcm.h index cd173d27..250b76e5 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -1,5 +1,5 @@ // gdcm.h - +//----------------------------------------------------------------------------- #ifndef GDCM_H #define GDCM_H @@ -27,8 +27,5 @@ #include "gdcmHeaderHelper.h" #include "gdcmFile.h" -//#include "gdcmTS.h" -//#include "gdcmVR.h" -//#include "gdcmUtil.h" - +//----------------------------------------------------------------------------- #endif // #ifndef GDCM_H diff --git a/src/gdcmCommon.h b/src/gdcmCommon.h index 07d0eec6..3775c317 100644 --- a/src/gdcmCommon.h +++ b/src/gdcmCommon.h @@ -1,5 +1,5 @@ //gdcmCommon.h - +//----------------------------------------------------------------------------- #ifndef GDCMCOMMON_H #define GDCMCOMMON_H @@ -26,6 +26,7 @@ // Mmmmmm ! // It reminds me the formerly well known LibIDO's idproto.h +//----------------------------------------------------------------------------- #ifdef __GNUC__ #ifndef HAVE_NO_STDINT_H #include @@ -74,4 +75,5 @@ enum FileType { //For now gdcm is not willing cmake, try to be more quiet //#cmakedefine GDCM_NO_ANSI_STRING_STREAM +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmDict.cxx b/src/gdcmDict.cxx index e362675d..725d2d6c 100644 --- a/src/gdcmDict.cxx +++ b/src/gdcmDict.cxx @@ -1,5 +1,5 @@ // gdcmDict.cxx - +//----------------------------------------------------------------------------- #include "gdcmDict.h" #include "gdcmUtil.h" #include @@ -10,6 +10,8 @@ # include #endif +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmDict * \brief Construtor @@ -63,6 +65,8 @@ gdcmDict::~gdcmDict() { NameHt.clear(); } +//----------------------------------------------------------------------------- +// Print /** * \brief Print all the dictionary entries contained in this dictionary. * Entries will be sorted by tag i.e. the couple (group, element). @@ -114,49 +118,8 @@ void gdcmDict::PrintByName(std::ostream& os) { os << s.str(); } -/** - * \ingroup gdcmDict - * \brief Get the dictionnary entry identified by a given tag (group,element) - * @param group group of the entry to be found - * @param element element of the entry to be found - * @return the corresponding dictionnary entry when existing, NULL otherwise - */ -gdcmDictEntry * gdcmDict::GetTagByNumber(guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! KeyHt.count(key)) - return (gdcmDictEntry*)0; - return KeyHt.find(key)->second; -} - -/** - * \ingroup gdcmDict - * \brief Get the dictionnary entry identified by it's name. - * @param name element of the ElVal to modify - * \warning : NEVER use it ! - * the 'name' IS NOT an identifier within the Dicom Dicom Dictionary - * the name MAY CHANGE between two versions ! - * @return the corresponding dictionnary entry when existing, NULL otherwise - */ -gdcmDictEntry * gdcmDict::GetTagByName(TagName name) { - if ( ! NameHt.count(name)) - return (gdcmDictEntry*)0; - return NameHt.find(name)->second; -} - -/** - * \ingroup gdcmDict - * \brief replaces an already existing Dicom Element by a new one - * @param NewEntry - * @return false if Dicom Element doesn't exist - */ -bool gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) { - if ( RemoveEntry(NewEntry->gdcmDictEntry::GetKey()) ) { - KeyHt[ NewEntry->GetKey()] = NewEntry; - return (true); - } - return (false); -} - +//----------------------------------------------------------------------------- +// Public /** * \ingroup gdcmDict * \brief adds a new Dicom Dictionary Entry @@ -176,6 +139,20 @@ bool gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) { } } +/** + * \ingroup gdcmDict + * \brief replaces an already existing Dicom Element by a new one + * @param NewEntry + * @return false if Dicom Element doesn't exist + */ +bool gdcmDict::ReplaceEntry(gdcmDictEntry* NewEntry) { + if ( RemoveEntry(NewEntry->gdcmDictEntry::GetKey()) ) { + KeyHt[ NewEntry->GetKey()] = NewEntry; + return (true); + } + return (false); +} + /** * \ingroup gdcmDict * \brief removes an already existing Dicom Dictionary Entry, @@ -209,3 +186,39 @@ bool gdcmDict::RemoveEntry (guint16 group, guint16 element) { return( RemoveEntry(gdcmDictEntry::TranslateToKey(group, element)) ); } +/** + * \ingroup gdcmDict + * \brief Get the dictionnary entry identified by a given tag (group,element) + * @param group group of the entry to be found + * @param element element of the entry to be found + * @return the corresponding dictionnary entry when existing, NULL otherwise + */ +gdcmDictEntry * gdcmDict::GetTagByNumber(guint16 group, guint16 element) { + TagKey key = gdcmDictEntry::TranslateToKey(group, element); + if ( ! KeyHt.count(key)) + return (gdcmDictEntry*)0; + return KeyHt.find(key)->second; +} + +/** + * \ingroup gdcmDict + * \brief Get the dictionnary entry identified by it's name. + * @param name element of the ElVal to modify + * \warning : NEVER use it ! + * the 'name' IS NOT an identifier within the Dicom Dicom Dictionary + * the name MAY CHANGE between two versions ! + * @return the corresponding dictionnary entry when existing, NULL otherwise + */ +gdcmDictEntry * gdcmDict::GetTagByName(TagName name) { + if ( ! NameHt.count(name)) + return (gdcmDictEntry*)0; + return NameHt.find(name)->second; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- diff --git a/src/gdcmDict.h b/src/gdcmDict.h index e91d6823..cf340244 100644 --- a/src/gdcmDict.h +++ b/src/gdcmDict.h @@ -1,5 +1,5 @@ // gdcmDict.h - +//----------------------------------------------------------------------------- #ifndef GDCMDICT_H #define GDCMDICT_H @@ -7,9 +7,11 @@ #include "gdcmDictEntry.h" #include +//----------------------------------------------------------------------------- typedef std::map TagKeyHT; typedef std::map TagNameHT; +//----------------------------------------------------------------------------- /* * \defgroup gdcmDict * \brief gdcmDict acts a memory representation of a dicom dictionary i.e. @@ -21,34 +23,40 @@ typedef std::map TagNameHT; * \see gdcmDictSet */ class GDCM_EXPORT gdcmDict { - std::string name; - std::string filename; - /// Access through TagKey (see alternate access with NameHt) - TagKeyHT KeyHt; - /// Access through TagName (see alternate access with KeyHt) - TagNameHT NameHt; public: - gdcmDict(std::string & FileName); + gdcmDict(std::string & FileName); ~gdcmDict(); - bool AddNewEntry (gdcmDictEntry* NewEntry); + + void Print(std::ostream&); + void PrintByKey(std::ostream&); + void PrintByName(std::ostream&); + + bool AddNewEntry (gdcmDictEntry* NewEntry); bool ReplaceEntry(gdcmDictEntry* NewEntry); bool RemoveEntry (TagKey key); bool RemoveEntry (guint16 group, guint16 element); + gdcmDictEntry * GetTagByNumber(guint16 group, guint16 element); gdcmDictEntry * GetTagByName(TagName name); - void Print(std::ostream&); - void PrintByKey(std::ostream&); - void PrintByName(std::ostream&); - /** - * \ingroup gdcmDict - * \brief returns a ref to the Dicom Dictionary H table (map) - * return the Dicom Dictionary H table - */ - inline TagKeyHT & gdcmDict::GetEntries(void) { + /** + * \ingroup gdcmDict + * \brief returns a ref to the Dicom Dictionary H table (map) + * return the Dicom Dictionary H table + */ + inline TagKeyHT & gdcmDict::GetEntries(void) { return KeyHt; - } + } +private: + std::string name; + std::string filename; + /// Access through TagKey (see alternate access with NameHt) + TagKeyHT KeyHt; + /// Access through TagName (see alternate access with KeyHt) + TagNameHT NameHt; + }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmDictEntry.cxx b/src/gdcmDictEntry.cxx index ddef6533..7ad40bee 100644 --- a/src/gdcmDictEntry.cxx +++ b/src/gdcmDictEntry.cxx @@ -1,10 +1,12 @@ // gdcmDictEntry.cxx - +//----------------------------------------------------------------------------- #include "gdcmDictEntry.h" #include // FIXME For sprintf #include "gdcmUtil.h" +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmDictEntry * \brief Construtor @@ -19,14 +21,19 @@ gdcmDictEntry::gdcmDictEntry(guint16 InGroup, guint16 InElement, std::string InVr, std::string InFourth, std::string InName) { - group = InGroup; + group = InGroup; element = InElement; vr = InVr; - fourth = InFourth; + fourth = InFourth; name = InName; key = TranslateToKey(group, element); } +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public /** * \ingroup gdcmDictEntry * \brief concatenates 2 guint16 (supposed to be a Dicom group number @@ -54,10 +61,19 @@ TagKey gdcmDictEntry::TranslateToKey(guint16 group, guint16 element) { * @param NewVr New V(alue) R(epresentation) to be set. */ void gdcmDictEntry::SetVR(std::string NewVr) { - if ( IsVrUnknown() ) + if ( IsVRUnknown() ) vr = NewVr; else { dbg.Error(true, "gdcmDictEntry::SetVR", "Overwriting vr might compromise a dictionary"); } } + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- + diff --git a/src/gdcmDictEntry.h b/src/gdcmDictEntry.h index 6b212099..5c6abff3 100644 --- a/src/gdcmDictEntry.h +++ b/src/gdcmDictEntry.h @@ -1,10 +1,11 @@ // gdcmDictEntry.h - +//----------------------------------------------------------------------------- #ifndef GDCMDICTENTRY_H #define GDCMDICTENTRY_H #include "gdcmCommon.h" +//----------------------------------------------------------------------------- /* * the gdcmDictEntry in an element contained by the gdcmDict. * It contains : @@ -14,6 +15,95 @@ * - etc. */ class GDCM_EXPORT gdcmDictEntry { +public: + gdcmDictEntry(guint16 group, + guint16 element, + std::string vr = "Unknown", + std::string fourth = "Unknown", + std::string name = "Unknown"); + + static TagKey TranslateToKey(guint16 group, guint16 element); + void SetVR(std::string); + + /** + * \ingroup gdcmDictEntry + * \brief tells if the V(alue) R(epresentation) is known (?!) + * + * @return + */ + inline bool gdcmDictEntry::IsVRUnknown() { + if ( vr == "Unknown" ) + return true; + return false; + } + + /** + * \ingroup gdcmDictEntry + * \brief returns the Dicom Group Number of the current gdcmDictEntry + * return the Dicom Group Number + */ + inline guint16 gdcmDictEntry::GetGroup(void) { + return group; + } + + /** + * \ingroup gdcmDictEntry + * \brief returns the Dicom Element Number of the current gdcmDictEntry + * return the Dicom Element Number + */ + inline guint16 gdcmDictEntry::GetElement(void) { + return element; + } + + /** + * \ingroup gdcmDictEntry + * \brief returns the Dicom Value Representation of the current gdcmDictEntry + * return the Dicom Value Representation + */ + inline std::string gdcmDictEntry::GetVR(void) { + return vr; + } + + /** + * \ingroup gdcmDictEntry + * \brief sets the key of the current gdcmDictEntry + * @param k New key to be set. + */ + inline void gdcmDictEntry::SetKey(std::string k) { + key = k; + } + + /** + * \ingroup gdcmDictEntry + * \brief returns the Fourth field of the current gdcmDictEntry + * \warning NOT part of the Dicom Standard + * \ May be REMOVED an any time + * \ NEVER use it + * return the Fourth field + */ + inline std::string gdcmDictEntry::GetFourth(void) { + return fourth; + } + + /** + * \ingroup gdcmDictEntry + * \brief returns the Dicom Name of the current gdcmDictEntry + * \ e.g. "Patient Name" for Dicom Tag (0x0010, 0x0010) + * return the Dicom Name + */ + inline std::string gdcmDictEntry::GetName(void) { + return name; + } + + /** + * \ingroup gdcmDictEntry + * \brief Gets the key of the current gdcmDictEntry + * @return the key . + */ + inline std::string gdcmDictEntry::GetKey(void) { + return key; + } + private: // FIXME : were are the group and element used except from building up // a TagKey. If the answer is nowhere then there is no need @@ -43,109 +133,7 @@ private: // DcmDictRangeRestriction groupRestriction; // DcmDictRangeRestriction elementRestriction; // }; -public: - gdcmDictEntry(guint16 group, - guint16 element, - std::string vr = "Unknown", - std::string fourth = "Unknown", - std::string name = "Unknown"); - - static TagKey TranslateToKey(guint16 group, guint16 element); - -// bool IsVrUnknown(void); - -// inline guint16 GetGroup(void); -// inline guint16 GetElement(void); -// inline std::string GetVR(void); - void SetVR(std::string); -// inline void SetKey(std::string k); -// inline std::string GetFourth(void); -// inline std::string GetName(void); -// inline std::string GetKey(void); - - - -/** - * \ingroup gdcmDictEntry - * \brief tells if the V(alue) R(epresentation) is known (?!) - * - * @return - */ -inline bool gdcmDictEntry::IsVrUnknown() { - if ( vr == "Unknown" ) - return true; - return false; -} - - -/** - * \ingroup gdcmDictEntry - * \brief returns the Dicom Group Number of the current gdcmDictEntry - * return the Dicom Group Number - */ - inline guint16 gdcmDictEntry::GetGroup(void) { - return group; - } - -/** - * \ingroup gdcmDictEntry - * \brief returns the Dicom Element Number of the current gdcmDictEntry - * return the Dicom Element Number - */ - inline guint16 gdcmDictEntry::GetElement(void) { - return element; - } - - /** - * \ingroup gdcmDictEntry - * \brief returns the Dicom Value Representation of the current gdcmDictEntry - * return the Dicom Value Representation - */ - inline std::string gdcmDictEntry::GetVR(void) { - return vr; - } - -/** - * \ingroup gdcmDictEntry - * \brief sets the key of the current gdcmDictEntry - * @param k New key to be set. - */ - inline void gdcmDictEntry::SetKey(std::string k) { - key = k; - } - - /** - * \ingroup gdcmDictEntry - * \brief returns the Fourth field of the current gdcmDictEntry - * \warning NOT part of the Dicom Standard - * \ May be REMOVED an any time - * \ NEVER use it - * return the Fourth field - */ - inline std::string gdcmDictEntry::GetFourth(void) { - return fourth; - } - - /** - * \ingroup gdcmDictEntry - * \brief returns the Dicom Name of the current gdcmDictEntry - * \ e.g. "Patient Name" for Dicom Tag (0x0010, 0x0010) - * return the Dicom Name - */ - inline std::string gdcmDictEntry::GetName(void) { - return name; - } - - /** - * \ingroup gdcmDictEntry - * \brief Gets the key of the current gdcmDictEntry - * @return the key . - */ - inline std::string gdcmDictEntry::GetKey(void) { - return key; - } - - }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmDictSet.cxx b/src/gdcmDictSet.cxx index 0db5964a..ce08aa50 100644 --- a/src/gdcmDictSet.cxx +++ b/src/gdcmDictSet.cxx @@ -1,5 +1,5 @@ // gdcmDictEntry - +//----------------------------------------------------------------------------- #include "gdcmDictSet.h" #include "gdcmUtil.h" #include @@ -11,6 +11,49 @@ #endif #define PUB_DICT_FILENAME "dicomV3.dic" +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \ingroup gdcmDictSet + * \brief The Dictionnary Set obtained with this constructor simply + * contains the Default Public dictionnary. + */ +gdcmDictSet::gdcmDictSet(void) { + DictPath = BuildDictPath(); + std::string PubDictFile = DictPath + PUB_DICT_FILENAME; + Dicts[PUB_DICT_NAME] = new gdcmDict(PubDictFile); +} + +/** + * \ingroup gdcmDictSet + * \brief Destructor + */ +gdcmDictSet::~gdcmDictSet() { + for (DictSetHT::iterator tag = Dicts.begin(); tag != Dicts.end(); ++tag) { + gdcmDict* EntryToDelete = tag->second; + if ( EntryToDelete ) + delete EntryToDelete; + } + Dicts.clear(); +} + +//----------------------------------------------------------------------------- +// Print +/** + * \ingroup gdcmDictSet + * \brief Print, in an informal fashion, the list of all the dictionaries + * contained is this gdcmDictSet, along with their respective content. + * @param os Output stream used for printing. + */ +void gdcmDictSet::Print(std::ostream& os) { + for (DictSetHT::iterator dict = Dicts.begin(); dict != Dicts.end(); ++dict){ + os << "Printing dictionary " << dict->first << std::endl; + dict->second->Print(os); + } +} + +//----------------------------------------------------------------------------- +// Public /** * \ingroup gdcmDictSet * \brief Consider all the entries of the public dicom dictionnary. @@ -39,7 +82,6 @@ std::list * gdcmDictSet::GetPubDictTagNames(void) { * A typical usage of this method would be to enable a dynamic * configuration of a Dicom file browser: the admin/user can * select in the interface which Dicom tags should be displayed. - * \warning Dicom *doesn't* define any name for any 'categorie' * (the dictionnary fourth field was formerly NIH defined * - and no longer he is- @@ -63,54 +105,6 @@ std::map > * gdcmDictSet::GetPubDictTagNames return Result; } -/** - * \ingroup gdcmDictSet - * \brief Obtain from the GDCM_DICT_PATH environnement variable the - * path to directory containing the dictionnaries. When - * the environnement variable is absent the path is defaulted - * to "../Dicts/". - * @return path to directory containing the dictionnaries - */ -std::string gdcmDictSet::BuildDictPath(void) { - std::string ResultPath; - const char* EnvPath = (char*)0; - EnvPath = getenv("GDCM_DICT_PATH"); - if (EnvPath && (strlen(EnvPath) != 0)) { - ResultPath = EnvPath; - if (ResultPath[ResultPath.length() -1] != '/' ) - ResultPath += '/'; - dbg.Verbose(1, "gdcmDictSet::BuildDictPath:", - "Dictionary path set from environnement"); - } else - ResultPath = PUB_DICT_PATH; - return ResultPath; -} - -/** - * \ingroup gdcmDictSet - * \brief The Dictionnary Set obtained with this constructor simply - * contains the Default Public dictionnary. - */ -gdcmDictSet::gdcmDictSet(void) { - DictPath = BuildDictPath(); - std::string PubDictFile = DictPath + PUB_DICT_FILENAME; - Dicts[PUB_DICT_NAME] = new gdcmDict(PubDictFile); -} - - -/** - * \ingroup gdcmDictSet - * \brief Destructor - */ -gdcmDictSet::~gdcmDictSet() { - for (DictSetHT::iterator tag = Dicts.begin(); tag != Dicts.end(); ++tag) { - gdcmDict* EntryToDelete = tag->second; - if ( EntryToDelete ) - delete EntryToDelete; - } - Dicts.clear(); -} - /** * \ingroup gdcmDictSet * \brief Loads a dictionary from a specified file, and add it @@ -122,20 +116,7 @@ gdcmDictSet::~gdcmDictSet() { */ void gdcmDictSet::LoadDictFromFile(std::string FileName, DictKey Name) { gdcmDict *NewDict = new gdcmDict(FileName); - Dicts[Name] = NewDict; -} - -/** - * \ingroup gdcmDictSet - * \brief Print, in an informal fashion, the list of all the dictionaries - * contained is this gdcmDictSet, along with their respective content. - * @param os Output stream used for printing. - */ -void gdcmDictSet::Print(std::ostream& os) { - for (DictSetHT::iterator dict = Dicts.begin(); dict != Dicts.end(); ++dict){ - os << "Printing dictionary " << dict->first << std::endl; - dict->second->Print(os); - } + AppendDict(NewDict,Name); } /** @@ -158,3 +139,41 @@ gdcmDict * gdcmDictSet::GetDict(DictKey DictName) { gdcmDict * gdcmDictSet::GetDefaultPubDict() { return GetDict(PUB_DICT_NAME); } + +/** + * \ingroup gdcmDictSet + * \brief Obtain from the GDCM_DICT_PATH environnement variable the + * path to directory containing the dictionnaries. When + * the environnement variable is absent the path is defaulted + * to "../Dicts/". + * @return path to directory containing the dictionnaries + */ +std::string gdcmDictSet::BuildDictPath(void) { + std::string ResultPath; + const char* EnvPath = (char*)0; + EnvPath = getenv("GDCM_DICT_PATH"); + if (EnvPath && (strlen(EnvPath) != 0)) { + ResultPath = EnvPath; + if (ResultPath[ResultPath.length() -1] != '/' ) + ResultPath += '/'; + dbg.Verbose(1, "gdcmDictSet::BuildDictPath:", + "Dictionary path set from environnement"); + } else + ResultPath = PUB_DICT_PATH; + return ResultPath; +} + +//----------------------------------------------------------------------------- +// Protected +bool gdcmDictSet::AppendDict(gdcmDict* NewDict,DictKey Name) +{ + Dicts[Name] = NewDict; + return(true); +} + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- + + diff --git a/src/gdcmDictSet.h b/src/gdcmDictSet.h index 578f7205..1fee82f9 100644 --- a/src/gdcmDictSet.h +++ b/src/gdcmDictSet.h @@ -1,5 +1,5 @@ // gdcmDictSet.h - +//----------------------------------------------------------------------------- #ifndef GDCMDICTSET_H #define GDCMDICTSET_H @@ -10,6 +10,7 @@ typedef std::string DictKey; typedef std::map DictSetHT; +//----------------------------------------------------------------------------- /* * \defgroup gdcmDictSet * \brief Container for managing a set of loaded dictionaries. @@ -19,20 +20,7 @@ typedef std::map DictSetHT; * (saving memory). */ class GDCM_EXPORT gdcmDictSet { -private: - /// Hash table of all dictionaries contained in this gdcmDictSet - DictSetHT Dicts; - /// Directory path to dictionaries - std::string DictPath; - - int AppendDict(gdcmDict* NewDict); - void LoadDictFromFile(std::string FileName, DictKey Name); - public: - std::list * GetPubDictTagNames(void); - std::map >* - GetPubDictTagNamesByCategory(void); - // TODO Swig int LoadDictFromFile(std::string filename); // QUESTION: the following function might not be thread safe !? Maybe // we need some mutex here, to avoid concurent creation of @@ -42,12 +30,29 @@ public: // TODO Swig std::string* GetAllDictNames(); gdcmDictSet(void); ~gdcmDictSet(void); + void Print(std::ostream& os); - gdcmDict* GetDict(DictKey DictName); + std::list * GetPubDictTagNames(void); + std::map >* + GetPubDictTagNamesByCategory(void); + + void LoadDictFromFile(std::string FileName, DictKey Name); + + gdcmDict* GetDict(DictKey DictName); gdcmDict* GetDefaultPubDict(void); static std::string BuildDictPath(void); + +protected: + bool AppendDict(gdcmDict* NewDict,DictKey Name); + +private: + /// Hash table of all dictionaries contained in this gdcmDictSet + DictSetHT Dicts; + /// Directory path to dictionaries + std::string DictPath; }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmElValSet.cxx b/src/gdcmElValSet.cxx index 21c63c33..fb99ba16 100644 --- a/src/gdcmElValSet.cxx +++ b/src/gdcmElValSet.cxx @@ -1,5 +1,5 @@ // gdcmElValSet.cxx - +//----------------------------------------------------------------------------- #include "gdcmUtil.h" #include "gdcmElValSet.h" #include "gdcmTS.h" @@ -10,6 +10,8 @@ # include #endif +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmElValSet * \brief Destructor @@ -25,42 +27,13 @@ gdcmElValSet::~gdcmElValSet() { tagHt.clear(); } -/** - * \ingroup gdcmElValSet - * \brief add a new Dicom Element pointer to - * the H Table and to the chained List - * @param newElValue - */ -void gdcmElValSet::Add(gdcmElValue * newElValue) { - -// tagHt [newElValue->GetKey()] = newElValue; - - tagHt.insert( PairHT( newElValue->GetKey(),newElValue) ); - -// WARNING : push_bash in listElem ONLY during ParseHeader -// TODO : something to allow further Elements addition -// position to be taken care of ! - listElem.push_back(newElValue); -} - -/** - * \ingroup gdcmElValSet - * \brief Checks if a given Dicom Element exists - * \ within the H table - * @param Group Group number of the searched Dicom Element - * @param Elem Element number of the searched Dicom Element - * @return number of occurences - */ -int gdcmElValSet::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { - std::string key = TranslateToKey(Group, Elem ); - return (tagHt.count(key)); -} - +//----------------------------------------------------------------------------- +// Print /** * \ingroup gdcmElValSet * \brief prints the Dicom Elements of the gdcmHeader * using both H table and Chained List - * @param os The output stream to be written to. + * @param os The output stream to be written to. */ void gdcmElValSet::Print(std::ostream & os) { @@ -69,11 +42,10 @@ void gdcmElValSet::Print(std::ostream & os) { TSKey v; std::string d2; gdcmTS * ts = gdcmGlobal::GetTS(); - - std::cout << "------------- using tagHt ---------------------" << std::endl; - // Do not remove cout std::ostringstream s; + // Tag HT + s << "------------- using tagHt ---------------------" << std::endl; for (TagElValueHT::iterator tag = tagHt.begin(); tag != tagHt.end(); ++tag){ @@ -104,13 +76,11 @@ void gdcmElValSet::Print(std::ostream & os) { s << std::endl; } - + // List element guint32 lgth; char greltag[10]; //group element tag - std::cout << "------------ using listElem -------------------" << std::endl; - // Do not remove cout - + s << "------------ using listElem -------------------" << std::endl; for (ListTag::iterator i = listElem.begin(); i != listElem.end(); ++i){ @@ -147,6 +117,26 @@ void gdcmElValSet::Print(std::ostream & os) { os<GetKey()] = newElValue; + + tagHt.insert( PairHT( newElValue->GetKey(),newElValue) ); + +// WARNING : push_bash in listElem ONLY during ParseHeader +// TODO : something to allow further Elements addition +// position to be taken care of ! + listElem.push_back(newElValue); +} + /** * \ingroup gdcmElValSet * \brief retrieves a Dicom Element (the first one) using (group, element) @@ -179,7 +169,6 @@ std::string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) { return tagHt.find(key)->second->GetValue(); } - /** * \ingroup gdcmElValSet * \brief Sets the value (string) of the target Dicom Element @@ -228,21 +217,25 @@ bool gdcmElValSet::SetElValueByNumber(std::string content, return true; } - /** * \ingroup gdcmElValSet - * \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. + * \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 elem Element number of the searched Dicom Element + * @return boolean */ -guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) { - for (guint32 elem = 0; elem < UINT32_MAX; elem++) { - TagKey key = gdcmDictEntry::TranslateToKey(group, elem); - if (tagHt.count(key) == 0) - return elem; - } - return UINT32_MAX; +bool gdcmElValSet::SetElValueLengthByNumber(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 ; } /** @@ -265,31 +258,69 @@ bool gdcmElValSet::SetVoidAreaByNumber(void * area, /** * \ingroup gdcmElValSet - * \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 elem Element number of the searched Dicom Element - * @return boolean + * \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. */ -bool gdcmElValSet::SetElValueLengthByNumber(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 ; +guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) { + for (guint32 elem = 0; elem < UINT32_MAX; elem++) { + TagKey key = gdcmDictEntry::TranslateToKey(group, elem); + if (tagHt.count(key) == 0) + return elem; + } + return UINT32_MAX; } +/** + * \ingroup gdcmElValSet + * \brief Checks if a given Dicom Element exists + * \ within the H table + * @param Group Group number of the searched Dicom Element + * @param Elem Element number of the searched Dicom Element + * @return number of occurences + */ +int gdcmElValSet::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { + std::string key = gdcmDictEntry::TranslateToKey(Group, Elem ); + 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 gdcmElValSet + * \brief + * @param _fp already open file pointer + * @param type type of the File to be written + * (ACR-NEMA, ExplicitVR, ImplicitVR) + * @return always "True" ?! + */ +bool gdcmElValSet::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); + WriteElements(type, _fp); + return(true); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private /** * \ingroup gdcmElValSet * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader @@ -482,30 +513,4 @@ void gdcmElValSet::WriteElements(FileType type, FILE * _fp) { } } -/** - * \ingroup gdcmElValSet - * \brief - * @param _fp already open file pointer - * @param type type of the File to be written - * (ACR-NEMA, ExplicitVR, ImplicitVR) - * @return always "True" ?! - */ -bool gdcmElValSet::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); - - WriteElements(type, _fp); - return(true); -} - +//----------------------------------------------------------------------------- diff --git a/src/gdcmElValSet.h b/src/gdcmElValSet.h index 5dd8736c..07bea3ca 100644 --- a/src/gdcmElValSet.h +++ b/src/gdcmElValSet.h @@ -1,5 +1,5 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmElValSet.h,v 1.21 2004/01/13 11:32:30 jpr Exp $ - +// gdcmElValSet.h +//----------------------------------------------------------------------------- #ifndef GDCMELVALSET_H #define GDCMELVALSET_H @@ -10,10 +10,7 @@ #include #include // for linking together *all* the Dicom Elements -/* - * Container for a set of successfully parsed ElValues (i.e. Dicom Elements). - */ - +//----------------------------------------------------------------------------- typedef std::multimap TagElValueHT; typedef std::pair PairHT; typedef std::pair IterHT; @@ -25,57 +22,52 @@ typedef std::list ListTag; // for linking together the Elements typedef std::string GroupKey; typedef std::map GroupHT; - +//----------------------------------------------------------------------------- +/* + * Container for a set of successfully parsed ElValues (i.e. Dicom Elements). + */ class GDCM_EXPORT gdcmElValSet { - TagElValueHT tagHt; // H Table (multimap), to provide fast access - ListTag listElem; // chained list, to keep the 'spacial' ordering - public: ~gdcmElValSet(); - void Add(gdcmElValue*); - + void Print(std::ostream &); - bool Write(FILE *fp, FileType type); + void Add(gdcmElValue*); + gdcmElValue* GetElementByNumber(guint16 group, guint16 element); - //gdcmElValue* GetElementByName (std::string); - // moved to gdcmHeader std::string GetElValueByNumber(guint16 group, guint16 element); bool SetElValueByNumber(std::string content, guint16 group, guint16 element); - // bool SetElValueByName (std::string content, std::string TagName); - // moved to gdcmHeader - bool SetElValueLengthByNumber(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 gdcmElValSet - * \brief returns a ref to the Dicom Header H table (multimap) - * return the Dicom Header H table - */ -inline TagElValueHT & gdcmElValSet::GetTagHt(void) { - return tagHt; - }; + /** + * \ingroup gdcmElValSet + * \brief returns a ref to the Dicom Header H table (multimap) + * return the Dicom Header H table + */ + inline TagElValueHT & gdcmElValSet::GetTagHt(void) { return tagHt; }; + + /** + * \ingroup gdcmElValSet + * \brief returns a ref to the Dicom Header chained list + * return the Dicom Header chained list + */ + inline ListTag & gdcmElValSet::GetListElem(void) { return listElem; }; + + bool Write(FILE *fp, FileType type); - /** - * \ingroup gdcmElValSet - * \brief returns a ref to the Dicom Header chained list - * return the Dicom Header chained list - */ - inline ListTag & gdcmElValSet::GetListElem(void) { - return listElem; - }; - private: void UpdateGroupLength(bool SkipSequence = false, FileType type = ImplicitVR); void WriteElements(FileType type, FILE *); - +// Variables + TagElValueHT tagHt; // H Table (multimap), to provide fast access + ListTag listElem; // chained list, to keep the 'spacial' ordering }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmElValue.cxx b/src/gdcmElValue.cxx index ef00cd18..64e3e247 100644 --- a/src/gdcmElValue.cxx +++ b/src/gdcmElValue.cxx @@ -1,20 +1,33 @@ // gdcmElValue.cxx - - +//----------------------------------------------------------------------------- // TODO // A 'gdcmElValue' is actually a 'Dicom Element'. // WHY such a confusing name??? // #include "gdcmElValue.h" +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmElValue * \brief Constructor from a given gdcmDictEntry * @param in Pointer to existing dictionary entry */ - gdcmElValue::gdcmElValue(gdcmDictEntry* in) { ImplicitVr = false; entry = in; } +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- diff --git a/src/gdcmElValue.h b/src/gdcmElValue.h index ed14eb2f..7b4600a4 100644 --- a/src/gdcmElValue.h +++ b/src/gdcmElValue.h @@ -1,5 +1,5 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmElValue.h,v 1.11 2004/01/13 11:32:30 jpr Exp $ - +// gdcmElValue.h +//----------------------------------------------------------------------------- #ifndef GDCMELVALUE_H #define GDCMELVALUE_H @@ -8,49 +8,15 @@ class gdcmHeader; #include +//----------------------------------------------------------------------------- /* * The dicom header of a Dicom file contains a set of such ELement VALUES * (when successfuly parsed against a given Dicom dictionary) */ class GDCM_EXPORT gdcmElValue { -private: - 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. - - // FIXME: In fact we should be more specific and use : - // friend gdcmElValue * gdcmHeader::ReadNextElement(void); - friend class gdcmHeader; - public: - 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 - gdcmElValue(gdcmDictEntry*); - // inline void SetDictEntry(gdcmDictEntry *NewEntry); - // inline bool IsVrUnknown(void); - // inline void SetImplicitVr(void); - // inline bool IsImplicitVr(void); - // inline void SetOffset(size_t of); - // inline gdcmDictEntry * GetDictEntry(void); - inline guint16 GetGroup(void) { return entry->GetGroup(); }; inline guint16 GetElement(void) { return entry->GetElement();}; inline std::string GetKey(void) { return entry->GetKey(); }; @@ -71,67 +37,88 @@ public: inline void SetValue(std::string val) { value = val; }; inline void SetVoidArea(void * area) { voidArea = area; }; - - -/** - * \ingroup gdcmElValue - * \brief Sets the offset of the Dicom Element - * \warning : use with caution ! - * @param of offset to be set - */ - -inline void gdcmElValue::SetOffset(size_t of){ - Offset = of; -}; + /** + * \ingroup gdcmElValue + * \brief Sets the offset of the Dicom Element + * \warning : use with caution ! + * @param of offset to be set + */ + inline void gdcmElValue::SetOffset(size_t of) { Offset = of; }; -/** - * \ingroup gdcmElValue - * \brief Sets the DicEntry of the current Dicom Element - * @param NewEntry pointer to the DictEntry - */ + /** + * \ingroup gdcmElValue + * \brief Sets the DicEntry of the current Dicom Element + * @param NewEntry pointer to the DictEntry + */ + inline void gdcmElValue::SetDictEntry(gdcmDictEntry *NewEntry) { + entry = NewEntry; + }; -inline void gdcmElValue::SetDictEntry(gdcmDictEntry *NewEntry) { - entry = NewEntry; -}; + /** + * \ingroup gdcmElValue + * \brief Sets to TRUE the ImplicitVr flag of the current Dicom Element + */ + inline void gdcmElValue::SetImplicitVr(void) { + ImplicitVr = true; + }; + + /** + * \ingroup gdcmElValue + * \brief tells us if the current Dicom Element was checked as ImplicitVr + * @return true if the current Dicom Element was checked as ImplicitVr + */ + inline bool gdcmElValue::IsImplicitVr(void) { + return ImplicitVr; + }; -/** - * \ingroup gdcmElValue - * \brief tells us if the VR of the current Dicom Element is Unkonwn - * @return true if the VR is unkonwn - */ + /** + * \ingroup gdcmElValue + * \brief Gets the DicEntry of the current Dicom Element + * @return the DicEntry of the current Dicom Element + */ + gdcmDictEntry * gdcmElValue::GetDictEntry(void) { + return entry; + }; -inline bool gdcmElValue::IsVrUnknown(void) { - return entry->IsVrUnknown(); -}; + /** + * \ingroup gdcmElValue + * \brief tells us if the VR of the current Dicom Element is Unkonwn + * @return true if the VR is unkonwn + */ + inline bool gdcmElValue::IsVRUnknown(void) { + return entry->IsVRUnknown(); + }; -/** - * \ingroup gdcmElValue - * \brief Sets to TRUE the ImplicitVr flag of the current Dicom Element - */ - -inline void gdcmElValue::SetImplicitVr(void) { - ImplicitVr = true; -}; - -/** - * \ingroup gdcmElValue - * \brief tells us if the current Dicom Element was checked as ImplicitVr - * @return true if the current Dicom Element was checked as ImplicitVr - */ -inline bool gdcmElValue::IsImplicitVr(void) { - return ImplicitVr; - }; +private: + // FIXME: In fact we should be more specific and use : + // friend gdcmElValue * gdcmHeader::ReadNextElement(void); + friend class gdcmHeader; -/** - * \ingroup gdcmElValue - * \brief Gets the DicEntry of the current Dicom Element - * @return the DicEntry of the current Dicom Element - */ -gdcmDictEntry * gdcmElValue::GetDictEntry(void) { - return entry; -}; - - +// 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. + + + 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 }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmException.cxx b/src/gdcmException.cxx index d2d3d7cd..aeb15c0b 100644 --- a/src/gdcmException.cxx +++ b/src/gdcmException.cxx @@ -1,9 +1,12 @@ - +// gdcmException.cxx +//----------------------------------------------------------------------------- #include "gdcmException.h" #include #include +//----------------------------------------------------------------------------- +// gdcmException gdcmException::gdcmException(const std::string &f, const std::string& msg) throw() #ifdef __GNUC__ try @@ -17,7 +20,6 @@ catch(...) { #endif - void gdcmException::fatal(const char *from) throw() { try { std::cerr << "Fatal: exception received in " << from @@ -36,7 +38,6 @@ void gdcmException::fatal(const char *from) throw() { } } - std::string gdcmException::getName() const throw() { try { #ifdef __GNUC__ // GNU C++ compiler class name demangling @@ -68,12 +69,11 @@ std::string gdcmException::getName() const throw() { } } - gdcmException::operator const char *() const throw() { return getName().c_str(); } - +//----------------------------------------------------------------------------- std::ostream& operator<<(std::ostream &os, const gdcmException &e) { try { os << "Exception " << e.getName() << " thrown: " << e.getError() << std::endl; @@ -84,4 +84,4 @@ std::ostream& operator<<(std::ostream &os, const gdcmException &e) { return os; } - +//----------------------------------------------------------------------------- diff --git a/src/gdcmException.h b/src/gdcmException.h index 094cd568..436d664a 100644 --- a/src/gdcmException.h +++ b/src/gdcmException.h @@ -1,3 +1,5 @@ +// gdcmException.h +//----------------------------------------------------------------------------- #ifndef GDCM_EXCEPTION_H #define GDCM_EXCEPTION_H @@ -6,103 +8,103 @@ #include #include +//----------------------------------------------------------------------------- /* * Any exception thrown in the gdcm library */ class GDCM_EXPORT gdcmException : public std::exception { - protected: - /// error message - std::string from; - /// error message - std::string error; - - public: - /* - * Builds an exception with minimal information: name of the thrower - * method and error message - * - * @param from name of the thrower - * @param error error description string - */ - explicit gdcmException(const std::string &from, const std::string &error = "") +public: + /* + * Builds an exception with minimal information: name of the thrower + * method and error message + * + * @param from name of the thrower + * @param error error description string + */ + explicit gdcmException(const std::string &from, const std::string &error = "") throw(); - - - /* - * virtual destructor makes this class dynamic - */ - virtual ~gdcmException() throw() { - } - - /// returns error message - const std::string &getError(void) const throw() { - return error; - } - /// returns exception name string - operator const char *() const throw(); + /* + * virtual destructor makes this class dynamic + */ + virtual ~gdcmException() throw() { + } - /// returns exception name string (overloads std::exception::what) - virtual const char *what() const throw() { - return (const char *) *this; - } + // exception caught within exception class: print error message and die + static void fatal(const char *from) throw(); + // returns error message + const std::string &getError(void) const throw() { + return error; + } - /// exception caught within exception class: print error message and die - static void fatal(const char *from) throw(); + // try to discover this (dynamic) class name + virtual std::string getName() const throw(); - /// try to discover this (dynamic) class name - virtual std::string getName() const throw(); + // returns exception name string (overloads std::exception::what) + virtual const char *what() const throw() { + return (const char *) *this; + } - friend std::ostream& operator<<(std::ostream &os, const gdcmException &e); - -}; + // returns exception name string + operator const char *() const throw(); + friend std::ostream& operator<<(std::ostream &os, const gdcmException &e); -/* prints exception stack on output stream - * @param os output stream - * @param e exception to print - * @returns output stream os - */ -std::ostream& operator<<(std::ostream &os, const gdcmException &e); +protected: + // error message + std::string from; + // error message + std::string error; +}; +//----------------------------------------------------------------------------- /* * File error exception thrown in the gdcm library */ class GDCM_EXPORT gdcmFileError : public gdcmException { - public: - /* - * Builds an file-related exception with minimal information: name of - * the thrower method and error message - * - * @param from name of the thrower - * @param error error description string - */ - explicit gdcmFileError(const std::string &from, - const std::string &error = "File error") - throw() : gdcmException(from, error) { - } +public: + /* + * Builds an file-related exception with minimal information: name of + * the thrower method and error message + * + * @param from name of the thrower + * @param error error description string + */ + explicit gdcmFileError(const std::string &from, + const std::string &error = "File error") + throw() : gdcmException(from, error) { + } }; +//----------------------------------------------------------------------------- /* * Invalid file format exception */ class GDCM_EXPORT gdcmFormatError : public gdcmException { - public: - /* - * Builds an file-related exception with minimal information: name of - * the thrower method and error message - * - * @param from name of the thrower - * @param error error description string - */ - explicit gdcmFormatError(const std::string &from, - const std::string &error = "Invalid file format error") - throw() : gdcmException(from, error) { - } +public: + /* + * Builds an file-related exception with minimal information: name of + * the thrower method and error message + * + * @param from name of the thrower + * @param error error description string + */ + explicit gdcmFormatError(const std::string &from, + const std::string &error = "Invalid file format error") + throw() : gdcmException(from, error) { + } }; +//----------------------------------------------------------------------------- +/* prints exception stack on output stream + * @param os output stream + * @param e exception to print + * @returns output stream os + */ +std::ostream& operator<<(std::ostream &os, const gdcmException &e); +//----------------------------------------------------------------------------- #endif // GDCM_EXCEPTION_H diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index eb34b461..fb042163 100644 --- a/src/gdcmFile.cxx +++ b/src/gdcmFile.cxx @@ -1,10 +1,11 @@ // gdcmFile.cxx - +//----------------------------------------------------------------------------- #include "gdcmFile.h" #include "gdcmUtil.h" #include "jpeg/ljpg/jpegless.h" -///////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmFile * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant @@ -31,7 +32,6 @@ gdcmFile::gdcmFile(gdcmHeader *header) SetPixelDataSizeFromHeader(); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant @@ -66,7 +66,6 @@ gdcmFile::gdcmFile(const char * filename) SetPixelDataSizeFromHeader(); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Destructor dedicated to writing a new DICOMV3 part10 compliant @@ -84,7 +83,11 @@ gdcmFile::~gdcmFile(void) Header=NULL; } +//----------------------------------------------------------------------------- +// Print +//----------------------------------------------------------------------------- +// Public /** * \ingroup gdcmFile * \brief @@ -106,6 +109,32 @@ gdcmHeader *gdcmFile::GetHeader(void) * @return longueur a allouer */ void gdcmFile::SetPixelDataSizeFromHeader(void) { + // see PS 3.3-2003 : C.7.6.3.2.1 + // + // MONOCHROME1 + // MONOCHROME2 + // PALETTE COLOR + // RGB + // HSV (Retired) + // ARGB (Retired) + // CMYK (Retired) + // YBR_FULL + // YBR_FULL_422 (no LUT, no Palette) + // YBR_PARTIAL_422 + // YBR_ICT + // YBR_RCT + + // LUT's + // ex : gdcm-US-ALOKA-16.dcm + // 0028|1221 [OW] [Segmented Red Palette Color Lookup Table Data] + // 0028|1222 [OW] [Segmented Green Palette Color Lookup Table Data] + // 0028|1223 [OW] [Segmented Blue Palette Color Lookup Table Data] + + // ex : OT-PAL-8-face.dcm + // 0028|1201 [US] [Red Palette Color Lookup Table Data] + // 0028|1202 [US] [Green Palette Color Lookup Table Data] + // 0028|1203 [US] [Blue Palette Color Lookup Table Data] + int nb; std::string str_nb; str_nb=Header->GetPubElValByNumber(0x0028,0x0100); @@ -128,240 +157,27 @@ void gdcmFile::SetPixelDataSizeFromHeader(void) { } } - // see PS 3.3-2003 : C.7.6.3.2.1 - // - // MONOCHROME1 - // MONOCHROME2 - // PALETTE COLOR - // RGB - // HSV (Retired) - // ARGB (Retired) - // CMYK (Retired) - // YBR_FULL - // YBR_FULL_422 (no LUT, no Palette) - // YBR_PARTIAL_422 - // YBR_ICT - // YBR_RCT - - // LUT's - // ex : gdcm-US-ALOKA-16.dcm - // 0028|1221 [OW] [Segmented Red Palette Color Lookup Table Data] - // 0028|1222 [OW] [Segmented Green Palette Color Lookup Table Data] - // 0028|1223 [OW] [Segmented Blue Palette Color Lookup Table Data] - - // ex : OT-PAL-8-face.dcm - // 0028|1201 [US] [Red Palette Color Lookup Table Data] - // 0028|1202 [US] [Green Palette Color Lookup Table Data] - // 0028|1203 [US] [Blue Palette Color Lookup Table Data] - - -///////////////////////////////////////////////////////////////// -/** - * \ingroup gdcmFile - * \brief Returns the size (in bytes) of required memory to hold - * \ the pixel data represented in this file, when user DOESN'T want - * \ to get RGB pixels image when it's stored as a PALETTE COLOR image - * \ - the (vtk) user is supposed to know how deal with LUTs - - * \ warning to be used with GetImagePixelsRaw() - * @return The size of pixel data in bytes. - */ - -size_t gdcmFile::GetImageDataSizeRaw(void) { - return (lgrTotaleRaw); -} - -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Returns the size (in bytes) of required memory to hold * the pixel data represented in this file. * @return The size of pixel data in bytes. */ - size_t gdcmFile::GetImageDataSize(void) { return (lgrTotale); } - -///////////////////////////////////////////////////////////////// /** - * \ingroup gdcmFile - * \brief Read pixel data from disk (optionaly decompressing) into the - * caller specified memory location. - * @param destination where the pixel data should be stored. - * + * \ingroup gdcmFile + * \brief Returns the size (in bytes) of required memory to hold + * \ the pixel data represented in this file, when user DOESN'T want + * \ to get RGB pixels image when it's stored as a PALETTE COLOR image + * \ - the (vtk) user is supposed to know how deal with LUTs - + * \ warning to be used with GetImagePixelsRaw() + * @return The size of pixel data in bytes. */ -bool gdcmFile::ReadPixelData(void* destination) { - - FILE *fp; - - if ( !(fp=Header->OpenFile())) - return false; - - if ( fseek(fp, Header->GetPixelOffset(), SEEK_SET) == -1 ) { - Header->CloseFile(); - return false; - } - - - // ---------------------- Compacted File (12 Bits Per Pixel) - - /* unpack 12 Bits pixels into 16 Bits pixels */ - /* 2 pixels 12bit = [0xABCDEF] */ - /* 2 pixels 16bit = [0x0ABD] + [0x0FCE] */ - - if (Header->GetBitsAllocated()==12) { - int nbPixels = Header->GetXSize() * Header->GetYSize(); - unsigned char b0, b1, b2; - - unsigned short int* pdestination = (unsigned short int*)destination; - for(int p=0;p> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); - /* A */ /* B */ /* D */ - *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); - /* F */ /* C */ /* E */ - - // Troubles expected on Big-Endian processors ? - } - return(true); - } - - // ---------------------- Uncompressed File - - if ( !Header->IsDicomV3() || - Header->IsImplicitVRLittleEndianTransferSyntax() || - Header->IsExplicitVRLittleEndianTransferSyntax() || - Header->IsExplicitVRBigEndianTransferSyntax() || - Header->IsDeflatedExplicitVRLittleEndianTransferSyntax() ) { - - size_t ItemRead = fread(destination, Header->GetPixelAreaLength(), 1, fp); - - if ( ItemRead != 1 ) { - Header->CloseFile(); - return false; - } else { - Header->CloseFile(); - return true; - } - } - - // ---------------------- Run Length Encoding - - if (Header->IsRLELossLessTransferSyntax()) { - bool res = (bool)gdcm_read_RLE_file (fp,destination); - return res; - } - - // --------------- SingleFrame/Multiframe JPEG Lossless/Lossy/2000 - - int nb; - std::string str_nb=Header->GetPubElValByNumber(0x0028,0x0100); - if (str_nb == GDCM_UNFOUND ) { - nb = 16; - } else { - nb = atoi(str_nb.c_str() ); - if (nb == 12) nb =16; // ?? 12 should be ACR-NEMA only ? - } - - int nBytes= nb/8; - - int taille = Header->GetXSize() * Header->GetYSize() - * Header->GetSamplesPerPixel(); - long fragmentBegining; // for ftell, fseek - - bool jpg2000 = Header->IsJPEG2000(); - bool jpgLossless = Header->IsJPEGLossless(); - - bool res = true; - guint16 ItemTagGr,ItemTagEl; - int ln; - - // Position on begining of Jpeg Pixels - - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if(Header->GetSwapCode()) { - ItemTagGr=Header->SwapShort(ItemTagGr); - ItemTagEl=Header->SwapShort(ItemTagEl); - } - fread(&ln,4,1,fp); - if(Header->GetSwapCode()) - ln=Header->SwapLong(ln); // Basic Offset Table Item length - - if (ln != 0) { - // What is it used for ?!? - char *BasicOffsetTableItemValue = (char *)malloc(ln+1); - fread(BasicOffsetTableItemValue,ln,1,fp); - } - - // first Fragment initialisation - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if(Header->GetSwapCode()) { - ItemTagGr=Header->SwapShort(ItemTagGr); - ItemTagEl=Header->SwapShort(ItemTagEl); - } - - // parsing fragments until Sequence Delim. Tag found - - while ( ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) { - // --- for each Fragment - - fread(&ln,4,1,fp); - if(Header->GetSwapCode()) - ln=Header->SwapLong(ln); // Fragment Item length - - fragmentBegining=ftell(fp); - - if (jpg2000) { // JPEG 2000 : call to ??? - - res = (bool)gdcm_read_JPEG2000_file (fp,destination); // Not Yet written - - } // ------------------------------------- endif (JPEG2000) - - else if (jpgLossless) { // JPEG LossLess : call to xmedcom JPEG - - JPEGLosslessDecodeImage (fp, // Reading Fragment pixels - (unsigned short *)destination, - Header->GetPixelSize()*8* Header->GetSamplesPerPixel(), - ln); - res=1; // in order not to break the loop - - } // ------------------------------------- endif (JPEGLossless) - - else { // JPEG Lossy : call to IJG 6b - - if (Header->GetBitsStored() == 8) { - res = (bool)gdcm_read_JPEG_file (fp,destination); // Reading Fragment pixels - } else { - res = (bool)gdcm_read_JPEG_file12 (fp,destination);// Reading Fragment pixels - } - } // ------------------------------------- endif (JPEGLossy) - - if (!res) break; - - destination = (char *)destination + taille * nBytes; // location in user's memory - // for next fragment (if any) - - fseek(fp,fragmentBegining,SEEK_SET); // To be sure we start - fseek(fp,ln,SEEK_CUR); // at the begining of next fragment - - ItemTagGr = ItemTagEl =0; - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if(Header->GetSwapCode()) { - ItemTagGr=Header->SwapShort(ItemTagGr); - ItemTagEl=Header->SwapShort(ItemTagEl); - } - - } // endWhile parsing fragments until Sequence Delim. Tag found - - Header->CloseFile(); - return res; +size_t gdcmFile::GetImageDataSizeRaw(void) { + return (lgrTotaleRaw); } /** @@ -381,27 +197,6 @@ void * gdcmFile::GetImageData (void) { return(PixelData); } -/** - * \ingroup gdcmFile - * \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 - * @return Pointer to newly allocated pixel data. - * \ NULL if alloc fails - */ -void * gdcmFile::GetImageDataRaw (void) { - if (Header->HasLUT()) - lgrTotale /= 3; // TODO Let gdcmHeadar user a chance - // to get the right value - // Create a member lgrTotaleRaw ??? - PixelData = (void *) malloc(lgrTotale); - if (PixelData) - GetImageDataIntoVectorRaw(PixelData, lgrTotale); - return(PixelData); -} - /** * \ingroup gdcmFile * \brief Copies at most MaxSize bytes of pixel data to caller's @@ -423,16 +218,13 @@ void * gdcmFile::GetImageDataRaw (void) { * @return On success, the number of bytes actually copied. Zero on * failure e.g. MaxSize is lower than necessary. */ - size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { - size_t l = GetImageDataIntoVectorRaw (destination, MaxSize); if (!Header->HasLUT()) return lgrTotale; - // from Lut R + Lut G + Lut B - + // from Lut R + Lut G + Lut B unsigned char * newDest = (unsigned char *)malloc(lgrTotale); unsigned char * a = (unsigned char *)destination; unsigned char * lutRGBA = Header->GetLUTRGBA(); @@ -459,8 +251,7 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { Header->SetPubElValByNumber(rgb,0x0028,0x0004); std::string planConfig = "0"; // Planar Configuration Header->SetPubElValByNumber(planConfig,0x0028,0x0006); - - + } else { // need to make RGB Pixels (?) // from grey Pixels (?!) @@ -483,7 +274,26 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { return lgrTotale; } - +/** + * \ingroup gdcmFile + * \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 + * @return Pointer to newly allocated pixel data. + * \ NULL if alloc fails + */ +void * gdcmFile::GetImageDataRaw (void) { + if (Header->HasLUT()) + lgrTotale /= 3; // TODO Let gdcmHeadar user a chance + // to get the right value + // Create a member lgrTotaleRaw ??? + PixelData = (void *) malloc(lgrTotale); + if (PixelData) + GetImageDataIntoVectorRaw(PixelData, lgrTotale); + return(PixelData); +} /** * \ingroup gdcmFile @@ -497,7 +307,7 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { * (for some axis related reasons?). Hence he will have * to load the image line by line, starting from the end. * VTK users hace to call GetImageData - * \warning DOES NOT transform the Grey Plane + Palette Color (if any) + * \warning DOES NOT transform the Grey Plane + Palette Color (if any) * into a single RGB Pixels Plane * the (VTK) user will manage the palettes * @@ -509,7 +319,6 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) { * @return On success, the number of bytes actually copied. Zero on * failure e.g. MaxSize is lower than necessary. */ - size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { int nb, nbu, highBit, signe; @@ -640,13 +449,13 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { { if (str_PhotometricInterpretation == "YBR_FULL") { - // Warning : YBR_FULL_422 acts as RGB - // : we need to make RGB Pixels from Planes Y,cB,cR - // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf - // for code optimisation + // Warning : YBR_FULL_422 acts as RGB + // : we need to make RGB Pixels from Planes Y,cB,cR + // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + // for code optimisation // to see the tricks about YBR_FULL, YBR_FULL_422, - // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : + // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf // and be *very* affraid // @@ -688,7 +497,7 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { } else { // need to make RGB Pixels from R,G,B Planes - // (all the Frames at a time) + // (all the Frames at a time) int l = Header->GetXSize()*Header->GetYSize()*Header->GetZSize(); @@ -713,15 +522,13 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { case 2: // Palettes were found - // Let the user deal with them ! - return lgrTotale; + // Let the user deal with them ! + return lgrTotale; } - // now, it's an RGB image - // Lets's write it in the Header - - // CreateOrReplaceIfExist ? - + // now, it's an RGB image + // Lets's write it in the Header + // CreateOrReplaceIfExist ? std::string spp = "3"; // Samples Per Pixel Header->SetPubElValByNumber(spp,0x0028,0x0002); @@ -732,92 +539,9 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) { Header->SetPubElValByNumber(planConfig,0x0028,0x0006); // TODO : Drop Palette Color out of the Header? - return lgrTotale; } - - -/** - * \ingroup gdcmFile - * \brief Swap the bytes, according to swap code. - * \warning not end user intended - * @param im area to deal with - * @param swap swap code - * @param lgr Area Length - * @param nb Pixels Bit number - */ - -void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) { -guint32 s32; -guint16 fort,faible; -int i; - -if(nb == 16) - switch(swap) { - case 0: - case 12: - case 1234: - break; - - case 21: - case 3412: - case 2143: - case 4321: - - for(i=0;i>8) - | ((((unsigned short int*)im)[i])<<8); - break; - - default: - printf("valeur de SWAP (16 bits) not allowed : %d\n", swap); - } - -if( nb == 32 ) - switch (swap) { - case 0: - case 1234: - break; - - case 4321: - for(i=0;i>16; - fort= (fort>>8) | (fort<<8); - faible=(faible>>8) | (faible<<8); - s32=faible; - ((unsigned long int*)im)[i]=(s32<<16)|fort; - } - break; - - case 2143: - for(i=0;i>16; - fort= (fort>>8) | (fort<<8); - faible=(faible>>8) | (faible<<8); - s32=fort; - ((unsigned long int*)im)[i]=(s32<<16)|faible; - } - break; - - case 3412: - for(i=0;i>16; - s32=faible; - ((unsigned long int*)im)[i]=(s32<<16)|fort; - } - break; - - default: - printf(" SWAP value (32 bits) not allowed : %d\n", swap); - } -return; -} - -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief TODO JPR @@ -836,8 +560,6 @@ bool gdcmFile::SetImageData(void * inData, size_t ExpectedSize) { return(true); } - -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Ecrit sur disque les pixels d'UNE image @@ -861,7 +583,6 @@ bool gdcmFile::WriteRawData (std::string fileName) { return(true); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Ecrit sur disque UNE image Dicom @@ -877,7 +598,6 @@ bool gdcmFile::WriteDcmImplVR (std::string fileName) { return WriteBase(fileName, ImplicitVR); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief @@ -889,7 +609,6 @@ bool gdcmFile::WriteDcmImplVR (const char* fileName) { return WriteDcmImplVR (std::string (fileName)); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief @@ -901,7 +620,6 @@ bool gdcmFile::WriteDcmExplVR (std::string fileName) { return WriteBase(fileName, ExplicitVR); } -///////////////////////////////////////////////////////////////// /** * \ingroup gdcmFile * \brief Ecrit au format ACR-NEMA sur disque l'entete et les pixels @@ -921,7 +639,8 @@ bool gdcmFile::WriteAcr (std::string fileName) { return WriteBase(fileName, ACR); } -///////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// Protected /** * \ingroup gdcmFile * @@ -981,3 +700,258 @@ bool gdcmFile::WriteBase (std::string FileName, FileType type) { fclose (fp1); return(true); } + +//----------------------------------------------------------------------------- +// Private +/** + * \ingroup gdcmFile + * \brief Swap the bytes, according to swap code. + * \warning not end user intended + * @param im area to deal with + * @param swap swap code + * @param lgr Area Length + * @param nb Pixels Bit number + */ +void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) { +guint32 s32; +guint16 fort,faible; +int i; + +if(nb == 16) + switch(swap) { + case 0: + case 12: + case 1234: + break; + + case 21: + case 3412: + case 2143: + case 4321: + + for(i=0;i>8) + | ((((unsigned short int*)im)[i])<<8); + break; + + default: + printf("valeur de SWAP (16 bits) not allowed : %d\n", swap); + } + +if( nb == 32 ) + switch (swap) { + case 0: + case 1234: + break; + + case 4321: + for(i=0;i>16; + fort= (fort>>8) | (fort<<8); + faible=(faible>>8) | (faible<<8); + s32=faible; + ((unsigned long int*)im)[i]=(s32<<16)|fort; + } + break; + + case 2143: + for(i=0;i>16; + fort= (fort>>8) | (fort<<8); + faible=(faible>>8) | (faible<<8); + s32=fort; + ((unsigned long int*)im)[i]=(s32<<16)|faible; + } + break; + + case 3412: + for(i=0;i>16; + s32=faible; + ((unsigned long int*)im)[i]=(s32<<16)|fort; + } + break; + + default: + printf(" SWAP value (32 bits) not allowed : %d\n", swap); + } +return; +} + +/** + * \ingroup gdcmFile + * \brief Read pixel data from disk (optionaly decompressing) into the + * caller specified memory location. + * @param destination where the pixel data should be stored. + * + */ +bool gdcmFile::ReadPixelData(void* destination) { + + FILE *fp; + + if ( !(fp=Header->OpenFile())) + return false; + + if ( fseek(fp, Header->GetPixelOffset(), SEEK_SET) == -1 ) { + Header->CloseFile(); + return false; + } + + + // ---------------------- Compacted File (12 Bits Per Pixel) + /* unpack 12 Bits pixels into 16 Bits pixels */ + /* 2 pixels 12bit = [0xABCDEF] */ + /* 2 pixels 16bit = [0x0ABD] + [0x0FCE] */ + if (Header->GetBitsAllocated()==12) { + int nbPixels = Header->GetXSize() * Header->GetYSize(); + unsigned char b0, b1, b2; + + unsigned short int* pdestination = (unsigned short int*)destination; + for(int p=0;p> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); + /* A */ /* B */ /* D */ + *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); + /* F */ /* C */ /* E */ + + // Troubles expected on Big-Endian processors ? + } + return(true); + } + + // ---------------------- Uncompressed File + if ( !Header->IsDicomV3() || + Header->IsImplicitVRLittleEndianTransferSyntax() || + Header->IsExplicitVRLittleEndianTransferSyntax() || + Header->IsExplicitVRBigEndianTransferSyntax() || + Header->IsDeflatedExplicitVRLittleEndianTransferSyntax() ) { + + size_t ItemRead = fread(destination, Header->GetPixelAreaLength(), 1, fp); + + if ( ItemRead != 1 ) { + Header->CloseFile(); + return false; + } else { + Header->CloseFile(); + return true; + } + } + + // ---------------------- Run Length Encoding + if (Header->IsRLELossLessTransferSyntax()) { + bool res = (bool)gdcm_read_RLE_file (fp,destination); + return res; + } + + // --------------- SingleFrame/Multiframe JPEG Lossless/Lossy/2000 + int nb; + std::string str_nb=Header->GetPubElValByNumber(0x0028,0x0100); + if (str_nb == GDCM_UNFOUND ) { + nb = 16; + } else { + nb = atoi(str_nb.c_str() ); + if (nb == 12) nb =16; // ?? 12 should be ACR-NEMA only ? + } + + int nBytes= nb/8; + + int taille = Header->GetXSize() * Header->GetYSize() + * Header->GetSamplesPerPixel(); + long fragmentBegining; // for ftell, fseek + + bool jpg2000 = Header->IsJPEG2000(); + bool jpgLossless = Header->IsJPEGLossless(); + + bool res = true; + guint16 ItemTagGr,ItemTagEl; + int ln; + + // Position on begining of Jpeg Pixels + + fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr + fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El + if(Header->GetSwapCode()) { + ItemTagGr=Header->SwapShort(ItemTagGr); + ItemTagEl=Header->SwapShort(ItemTagEl); + } + fread(&ln,4,1,fp); + if(Header->GetSwapCode()) + ln=Header->SwapLong(ln); // Basic Offset Table Item length + + if (ln != 0) { + // What is it used for ?!? + char *BasicOffsetTableItemValue = (char *)malloc(ln+1); + fread(BasicOffsetTableItemValue,ln,1,fp); + } + + // first Fragment initialisation + fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr + fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El + if(Header->GetSwapCode()) { + ItemTagGr=Header->SwapShort(ItemTagGr); + ItemTagEl=Header->SwapShort(ItemTagEl); + } + + // parsing fragments until Sequence Delim. Tag found + while ( ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) { + // --- for each Fragment + + fread(&ln,4,1,fp); + if(Header->GetSwapCode()) + ln=Header->SwapLong(ln); // Fragment Item length + + fragmentBegining=ftell(fp); + + if (jpg2000) { // JPEG 2000 : call to ??? + + res = (bool)gdcm_read_JPEG2000_file (fp,destination); // Not Yet written + + } // ------------------------------------- endif (JPEG2000) + + else if (jpgLossless) { // JPEG LossLess : call to xmedcom JPEG + + JPEGLosslessDecodeImage (fp, // Reading Fragment pixels + (unsigned short *)destination, + Header->GetPixelSize()*8* Header->GetSamplesPerPixel(), + ln); + res=1; // in order not to break the loop + + } // ------------------------------------- endif (JPEGLossless) + + else { // JPEG Lossy : call to IJG 6b + + if (Header->GetBitsStored() == 8) { + res = (bool)gdcm_read_JPEG_file (fp,destination); // Reading Fragment pixels + } else { + res = (bool)gdcm_read_JPEG_file12 (fp,destination);// Reading Fragment pixels + } + } // ------------------------------------- endif (JPEGLossy) + + if (!res) break; + + destination = (char *)destination + taille * nBytes; // location in user's memory + // for next fragment (if any) + + fseek(fp,fragmentBegining,SEEK_SET); // To be sure we start + fseek(fp,ln,SEEK_CUR); // at the begining of next fragment + + ItemTagGr = ItemTagEl =0; + fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr + fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El + if(Header->GetSwapCode()) { + ItemTagGr=Header->SwapShort(ItemTagGr); + ItemTagEl=Header->SwapShort(ItemTagEl); + } + + } // endWhile parsing fragments until Sequence Delim. Tag found + + Header->CloseFile(); + return res; +} +//----------------------------------------------------------------------------- diff --git a/src/gdcmFile.h b/src/gdcmFile.h index fb2cbc41..6773662c 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -1,11 +1,12 @@ // gdcmFile.h - +//----------------------------------------------------------------------------- #ifndef GDCMFILE_H #define GDCMFILE_H #include "gdcmCommon.h" #include "gdcmHeader.h" +//----------------------------------------------------------------------------- /* * In addition to Dicom header exploration, this class is designed * for accessing the image/volume content. One can also use it to @@ -13,31 +14,6 @@ */ class GDCM_EXPORT gdcmFile { -private: - gdcmHeader *Header; // Header to use to load the file - 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 Parsed; // weather already parsed - std::string OrigFileName; // To avoid file overwrite - void SwapZone(void* im, int swap, int lgr, int nb); - - bool ReadPixelData(void * destination); - - bool gdcm_read_JPEG_file (FILE *fp,void * image_buffer); // For JPEG 8 Bits - bool gdcm_read_JPEG_file12 (FILE *fp,void * image_buffer); // For JPEG 12 Bits - bool gdcm_read_JPEG2000_file (FILE *fp,void * image_buffer); // For JPEG 2000 (TODO) - -// For Run Length Encoding (TOCHECK) - bool gdcm_read_RLE_file (FILE *fp,void * image_buffer); - -protected: - bool WriteBase(std::string FileName, FileType type); - public: gdcmFile(gdcmHeader *header); gdcmFile(std::string & filename); @@ -58,6 +34,7 @@ public: void SetPixelDataSizeFromHeader(void); size_t GetImageDataSize(); size_t GetImageDataSizeRaw(); + void * GetImageData(); size_t GetImageDataIntoVector(void* destination, size_t MaxSize); void * GetImageDataRaw(); @@ -79,17 +56,50 @@ public: // incohérente avec l'ordre des octets en mémoire ? // TODO Swig int Write(); - // Ecrit sur disque les pixels d'UNE image - // Aucun test n'est fait sur l'"Endiannerie" du processeur. - // Ca sera à l'utilisateur d'appeler son Reader correctement - + // Write pixels of ONE image on hard drive + // No test is made on processor "stupidity" + // The user must call his reader correctly bool WriteRawData (std::string fileName); bool WriteDcmImplVR(std::string fileName); bool WriteDcmImplVR(const char * fileName); bool WriteDcmExplVR(std::string fileName); bool WriteAcr (std::string fileName); +protected: + bool WriteBase(std::string FileName, FileType type); + + // Body in file gdcmParse.cxx bool ParsePixelData(void); + +private: + void SwapZone(void* im, int swap, int lgr, int nb); + + bool ReadPixelData(void * destination); + + // For JPEG 8 Bits, body in file gdcmJpeg.cxx + bool gdcm_read_JPEG_file (FILE *fp,void * image_buffer); + static int gdcm_read_RLE_fragment(char **areaToRead, long lengthToDecode, + long uncompressedSegmentSize,FILE *fp); + // For JPEG 12 Bits, body in file gdcmJpeg12.cxx + bool gdcm_read_JPEG_file12 (FILE *fp,void * image_buffer); + // For JPEG 2000, body in file gdcmJpeg2000.cxx + bool gdcm_read_JPEG2000_file (FILE *fp,void * image_buffer); + + // For Run Length Encoding (TOCHECK) + bool gdcm_read_RLE_file (FILE *fp,void * image_buffer); + +// Variables + gdcmHeader *Header; // Header to use to load the file + 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 Parsed; // weather already parsed + std::string OrigFileName; // To avoid file overwrite }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index a6f4c58e..cbe330c0 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -1,5 +1,5 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmHeader.cxx,v 1.123 2004/01/13 11:32:30 jpr Exp $ - +// gdcmHeader.cxx +//----------------------------------------------------------------------------- #include "gdcmHeader.h" #include @@ -22,22 +22,15 @@ #include "gdcmUtil.h" #include "gdcmTS.h" +//----------------------------------------------------------------------------- // Refer to gdcmHeader::CheckSwap() -#define HEADER_LENGTH_TO_READ 256 +const unsigned int gdcmHeader::HEADER_LENGTH_TO_READ = 256; + // Refer to gdcmHeader::SetMaxSizeLoadElementValue() -#define _MaxSizeLoadElementValue_ 4096 -/** - * \ingroup gdcmHeader - * \brief - */ -void gdcmHeader::Initialise(void) { - dicom_vr = gdcmGlobal::GetVR(); - dicom_ts = gdcmGlobal::GetTS(); - Dicts = gdcmGlobal::GetDicts(); - RefPubDict = Dicts->GetDefaultPubDict(); - RefShaDict = (gdcmDict*)0; -} +const unsigned int gdcmHeader::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096; +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmHeader * \brief @@ -45,8 +38,7 @@ void gdcmHeader::Initialise(void) { * @param exception_on_error * @param enable_sequences = true to allow the header * to be parsed *inside* the SeQuences, - * when they have an actual length - the + * when they have an actual length */ gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error, @@ -56,7 +48,7 @@ gdcmHeader::gdcmHeader(const char *InFilename, else enableSequences = 0; - SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_); + SetMaxSizeLoadElementValue(MAX_SIZE_LOAD_ELEMENT_VALUE); filename = InFilename; Initialise(); if ( !OpenFile(exception_on_error)) @@ -72,373 +64,192 @@ gdcmHeader::gdcmHeader(const char *InFilename, * @param exception_on_error */ gdcmHeader::gdcmHeader(bool exception_on_error) { - SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_); + SetMaxSizeLoadElementValue(MAX_SIZE_LOAD_ELEMENT_VALUE); Initialise(); } /** * \ingroup gdcmHeader - * \brief - * @param exception_on_error - * @return + * \brief Canonical destructor. */ -FILE *gdcmHeader::OpenFile(bool exception_on_error) - throw(gdcmFileError) { - fp=fopen(filename.c_str(),"rb"); - if(exception_on_error) { - if(!fp) - throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)"); - } +gdcmHeader::~gdcmHeader (void) { + dicom_vr = (gdcmVR*)0; + Dicts = (gdcmDictSet*)0; + RefPubDict = (gdcmDict*)0; + RefShaDict = (gdcmDict*)0; + return; +} - if ( fp ) { - guint16 zero; - fread(&zero, (size_t)2, (size_t)1, fp); +//----------------------------------------------------------------------------- +// Print +/** + * \ingroup gdcmHeader + * \brief + * @return + */ +void gdcmHeader::PrintPubElVal(std::ostream & os) { + PubElValSet.Print(os); +} - //ACR -- or DICOM with no Preamble - if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200) - return(fp); +/** + * \ingroup gdcmHeader + * \brief + * @return + */ +void gdcmHeader::PrintPubDict(std::ostream & os) { + RefPubDict->Print(os); +} - //DICOM - fseek(fp, 126L, SEEK_CUR); - char dicm[4]; - fread(dicm, (size_t)4, (size_t)1, fp); - if( memcmp(dicm, "DICM", 4) == 0 ) - return(fp); +//----------------------------------------------------------------------------- +// Public +/** + * \ingroup gdcmHeader + * \brief This predicate, based on hopefully reasonable heuristics, + * decides whether or not the current gdcmHeader was properly parsed + * and contains the mandatory information for being considered as + * a well formed and usable image. + * @return true when gdcmHeader is the one of a reasonable Dicom file, + * false otherwise. + */ +bool gdcmHeader::IsReadable(void) { + std::string res = GetPubElValByNumber(0x0028, 0x0005); + if ( res != GDCM_UNFOUND + && atoi(res.c_str()) > 4 ) { + return false; // Image Dimensions + } + if ( GetPubElValByNumber(0x0028, 0x0100) == GDCM_UNFOUND ) + return false; // "Bits Allocated" + if ( GetPubElValByNumber(0x0028, 0x0101) == GDCM_UNFOUND ) + return false; // "Bits Stored" + if ( GetPubElValByNumber(0x0028, 0x0102) == GDCM_UNFOUND ) + return false; // "High Bit" + if ( GetPubElValByNumber(0x0028, 0x0103) == GDCM_UNFOUND ) + return false; // "Pixel Representation" + return true; +} - fclose(fp); - dbg.Verbose(0, "gdcmHeader::gdcmHeader not DICOM/ACR", filename.c_str()); - } - else { - dbg.Verbose(0, "gdcmHeader::gdcmHeader cannot open file", filename.c_str()); - } - return(NULL); +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a ImplicitVRLittleEndian one. + * + * @return True when ImplicitVRLittleEndian found. False in all other cases. + */ +bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2" ) + return true; + return false; } /** * \ingroup gdcmHeader - * \brief - * @return TRUE if the close was successfull + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a ExplicitVRLittleEndian one. + * + * @return True when ExplicitVRLittleEndian found. False in all other cases. */ -bool gdcmHeader::CloseFile(void) { - int closed = fclose(fp); - fp = (FILE *)0; - if (! closed) - return false; - return true; +bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.1" ) + return true; + return false; } /** * \ingroup gdcmHeader - * \brief Canonical destructor. + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a DeflatedExplicitVRLittleEndian one. + * + * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases. */ -gdcmHeader::~gdcmHeader (void) { - dicom_vr = (gdcmVR*)0; - Dicts = (gdcmDictSet*)0; - RefPubDict = (gdcmDict*)0; - RefShaDict = (gdcmDict*)0; +bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.1.99" ) + return true; + return false; +} +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a Explicit VR Big Endian one. + * + * @return True when big endian found. False in all other cases. + */ +bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.2" ) //1.2.2 ??? A verifier ! + return true; + return false; +} - return; +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGBaseLineProcess1 one. + * + * @return True when JPEGBaseLineProcess1found. False in all other cases. + */ +bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.50" ) + return true; + return false; } -// Fourth semantics: -// -// ---> Warning : This fourth field is NOT part -// of the 'official' Dicom Dictionnary -// and should NOT be used. -// (Not defined for all the groups -// may be removed in a future release) -// -// CMD Command -// META Meta Information -// DIR Directory -// ID -// PAT Patient -// ACQ Acquisition -// REL Related -// IMG Image -// SDY Study -// VIS Visit -// WAV Waveform -// PRC -// DEV Device -// NMI Nuclear Medicine -// MED -// BFS Basic Film Session -// BFB Basic Film Box -// BIB Basic Image Box -// BAB -// IOB -// PJ -// PRINTER -// RT Radio Therapy -// DVH -// SSET -// RES Results -// CRV Curve -// OLY Overlays -// PXL Pixels -// DL Delimiters -// +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGExtendedProcess2-4 one. + * + * @return True when JPEGExtendedProcess2-4 found. False in all other cases. + */ +bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) { + gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + std::string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.51" ) + return true; + return false; +} /** * \ingroup gdcmHeader - * \brief Discover what the swap code is (among little endian, big endian, - * bad little endian, bad big endian). + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGExtendeProcess3-5 one. * + * @return True when JPEGExtendedProcess3-5 found. False in all other cases. */ -void gdcmHeader::CheckSwap() -{ - // The only guaranted way of finding the swap code is to find a - // group tag since we know it's length has to be of four bytes i.e. - // 0x00000004. Finding the swap code in then straigthforward. Trouble - // occurs when we can't find such group... - guint32 s; - guint32 x=4; // x : for ntohs - bool net2host; // true when HostByteOrder is the same as NetworkByteOrder - - int lgrLue; - char * entCur; - char deb[HEADER_LENGTH_TO_READ]; - - // First, compare HostByteOrder and NetworkByteOrder in order to - // determine if we shall need to swap bytes (i.e. the Endian type). - if (x==ntohs(x)) - net2host = true; - else - net2host = false; - //cout << net2host << endl; - - // The easiest case is the one of a DICOM header, since it possesses a - // file preamble where it suffice to look for the string "DICM". - lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp); - - entCur = deb + 128; - if(memcmp(entCur, "DICM", (size_t)4) == 0) { - dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3"); - // Next, determine the value representation (VR). Let's skip to the - // first element (0002, 0000) and check there if we find "UL" - // - or "OB" if the 1st one is (0002,0001) -, - // in which case we (almost) know it is explicit VR. - // WARNING: if it happens to be implicit VR then what we will read - // is the length of the group. If this ascii representation of this - // length happens to be "UL" then we shall believe it is explicit VR. - // FIXME: in order to fix the above warning, we could read the next - // element value (or a couple of elements values) in order to make - // sure we are not commiting a big mistake. - // We need to skip : - // * the 128 bytes of File Preamble (often padded with zeroes), - // * the 4 bytes of "DICM" string, - // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001) - // i.e. a total of 136 bytes. - entCur = deb + 136; - // FIXME - // Use gdcmHeader::dicom_vr to test all the possibilities - // instead of just checking for UL, OB and UI !? - if( (memcmp(entCur, "UL", (size_t)2) == 0) || - (memcmp(entCur, "OB", (size_t)2) == 0) || - (memcmp(entCur, "UI", (size_t)2) == 0) ) - { - filetype = ExplicitVR; - dbg.Verbose(1, "gdcmHeader::CheckSwap:", - "explicit Value Representation"); - } else { - filetype = ImplicitVR; - dbg.Verbose(1, "gdcmHeader::CheckSwap:", - "not an explicit Value Representation"); - } - if (net2host) { - sw = 4321; - dbg.Verbose(1, "gdcmHeader::CheckSwap:", - "HostByteOrder != NetworkByteOrder"); - } else { - sw = 0; - dbg.Verbose(1, "gdcmHeader::CheckSwap:", - "HostByteOrder = NetworkByteOrder"); - } - - // Position the file position indicator at first tag (i.e. - // after the file preamble and the "DICM" string). - rewind(fp); - fseek (fp, 132L, SEEK_SET); - return; - } // End of DicomV3 - - // Alas, this is not a DicomV3 file and whatever happens there is no file - // preamble. We can reset the file position indicator to where the data - // is (i.e. the beginning of the file). - dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file"); - rewind(fp); - - // Our next best chance would be to be considering a 'clean' ACR/NEMA file. - // By clean we mean that the length of the first tag is written down. - // If this is the case and since the length of the first group HAS to be - // four (bytes), then determining the proper swap code is straightforward. - - entCur = deb + 4; - // We assume the array of char we are considering contains the binary - // representation of a 32 bits integer. Hence the following dirty - // trick : - s = *((guint32 *)(entCur)); - - switch (s) { - case 0x00040000 : - sw = 3412; - filetype = ACR; - return; - case 0x04000000 : - sw = 4321; - filetype = ACR; - return; - case 0x00000400 : - sw = 2143; - filetype = ACR; - return; - case 0x00000004 : - sw = 0; - filetype = ACR; - return; - default : - dbg.Verbose(0, "gdcmHeader::CheckSwap:", - "ACR/NEMA unfound swap info (time to raise bets)"); - } - - // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file. - // It is time for despaired wild guesses. So, let's assume this file - // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is - // not present. Then the only info we have is the net2host one. - filetype = Unknown; - if (! net2host ) - sw = 0; - else - sw = 4321; - return; -} - -/** - * \ingroup gdcmHeader - * \brief - */ -void gdcmHeader::SwitchSwapToBigEndian(void) { - dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian", - "Switching to BigEndian mode."); - if ( sw == 0 ) { - sw = 4321; - return; - } - if ( sw == 4321 ) { - sw = 0; - return; - } - if ( sw == 3412 ) { - sw = 2143; - return; - } - if ( sw == 2143 ) - sw = 3412; -} - -/** - * \ingroup gdcmHeader - * \brief Find the value representation of the current tag. - * @param ElVal - */ -void gdcmHeader::FindVR( gdcmElValue *ElVal) { - if (filetype != ExplicitVR) - return; - - char VR[3]; - std::string vr; - int lgrLue; - char msg[100]; // for sprintf. Sorry - - long PositionOnEntry = ftell(fp); - // Warning: we believe this is explicit VR (Value Representation) because - // we used a heuristic that found "UL" in the first tag. Alas this - // doesn't guarantee that all the tags will be in explicit VR. In some - // cases (see e-film filtered files) one finds implicit VR tags mixed - // within an explicit VR file. Hence we make sure the present tag - // is in explicit VR and try to fix things if it happens not to be - // the case. - bool RealExplicit = true; - - lgrLue=fread (&VR, (size_t)2,(size_t)1, fp); - VR[2]=0; - vr = std::string(VR); - - // Assume we are reading a falsely explicit VR file i.e. we reached - // a tag where we expect reading a VR but are in fact we read the - // first to bytes of the length. Then we will interogate (through find) - // the dicom_vr dictionary with oddities like "\004\0" which crashes - // both GCC and VC++ implementations of the STL map. Hence when the - // expected VR read happens to be non-ascii characters we consider - // we hit falsely explicit VR tag. - - if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) ) - RealExplicit = false; - - // CLEANME searching the dicom_vr at each occurence is expensive. - // PostPone this test in an optional integrity check at the end - // of parsing or only in debug mode. - if ( RealExplicit && !dicom_vr->Count(vr) ) - RealExplicit= false; - - if ( RealExplicit ) { - if ( ElVal->IsVrUnknown() ) { - // When not a dictionary entry, we can safely overwrite the vr. - ElVal->SetVR(vr); - return; - } - if ( ElVal->GetVR() == vr ) { - // The vr we just read and the dictionary agree. Nothing to do. - return; - } - // The vr present in the file and the dictionary disagree. We assume - // the file writer knew best and use the vr of the file. Since it would - // be unwise to overwrite the vr of a dictionary (since it would - // compromise it's next user), we need to clone the actual DictEntry - // and change the vr for the read one. - gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(), - ElVal->GetElement(), - vr, - "FIXME", - ElVal->GetName()); - ElVal->SetDictEntry(NewTag); - return; - } - - // We thought this was explicit VR, but we end up with an - // implicit VR tag. Let's backtrack. - - sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", - ElVal->GetGroup(),ElVal->GetElement()); - dbg.Verbose(1, "gdcmHeader::FindVR: ",msg); - - fseek(fp, PositionOnEntry, SEEK_SET); - // When this element is known in the dictionary we shall use, e.g. for - // the semantics (see the usage of IsAnInteger), the vr proposed by the - // dictionary entry. Still we have to flag the element as implicit since - // we know now our assumption on expliciteness is not furfilled. - // avoid . - if ( ElVal->IsVrUnknown() ) - ElVal->SetVR("Implicit"); - ElVal->SetImplicitVr(); -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a ImplicitVRLittleEndian one. - * - * @return True when ImplicitVRLittleEndian found. False in all other cases. - */ -bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { +bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) { gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); if ( !Element ) return false; LoadElementValueSafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2" ) + if ( Transfer == "1.2.840.10008.1.2.4.52" ) return true; return false; } @@ -446,17 +257,18 @@ bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { /** * \ingroup gdcmHeader * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a ExplicitVRLittleEndian one. + * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one. * - * @return True when ExplicitVRLittleEndian found. False in all other cases. + * @return True when JPEGSpectralSelectionProcess6-8 found. False in all + * other cases. */ -bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { +bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); if ( !Element ) return false; LoadElementValueSafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.1" ) + if ( Transfer == "1.2.840.10008.1.2.4.53" ) return true; return false; } @@ -464,1266 +276,1108 @@ bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { /** * \ingroup gdcmHeader * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a DeflatedExplicitVRLittleEndian one. + * and if it corresponds to a RLE Lossless one. * - * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases. + * @return True when RLE Lossless found. False in all + * other cases. */ -bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { +bool gdcmHeader::IsRLELossLessTransferSyntax(void) { gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); if ( !Element ) return false; LoadElementValueSafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.1.99" ) + if ( Transfer == "1.2.840.10008.1.2.5" ) return true; return false; } /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a Explicit VR Big Endian one. + * \brief * - * @return True when big endian found. False in all other cases. + * @return */ -bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) { +bool gdcmHeader::IsJPEGLossless(void) { gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + // faire qq chose d'intelligent a la place de ça if ( !Element ) return false; LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.2" ) //1.2.2 ??? A verifier ! - return true; + const char * Transfert = Element->GetValue().c_str(); + if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true; + if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true; + if (Element->GetValue() == "1.2.840.10008.1.2.4.57") return true; + return false; } /** * \ingroup gdcmHeader * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGBaseLineProcess1 one. + * and if it corresponds to a JPEG200 one.0 * - * @return True when JPEGBaseLineProcess1found. False in all other cases. + * @return True when JPEG2000 (Lossly or LossLess) found. False in all + * other cases. */ -bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { +bool gdcmHeader::IsJPEG2000(void) { gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); if ( !Element ) return false; LoadElementValueSafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.50" ) + if ( (Transfer == "1.2.840.10008.1.2.4.90") + || (Transfer == "1.2.840.10008.1.2.4.91") ) return true; return false; } /** * \ingroup gdcmHeader - * \brief - * + * \brief Predicate for dicom version 3 file. + * @return True when the file is a dicom version 3. + */ +bool gdcmHeader::IsDicomV3(void) { + if ( (filetype == ExplicitVR) + || (filetype == ImplicitVR) ) + return true; + return false; +} + +/** + * \ingroup gdcmHeader + * \brief * @return */ -bool gdcmHeader::IsJPEGLossless(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - // faire qq chose d'intelligent a la place de ça - if ( !Element ) - return false; - LoadElementValueSafe(Element); - const char * Transfert = Element->GetValue().c_str(); - if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true; - if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true; - if (Element->GetValue() == "1.2.840.10008.1.2.4.57") return true; - - return false; +FileType gdcmHeader::GetFileType(void) +{ + return(filetype); } - /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGExtendedProcess2-4 one. - * - * @return True when JPEGExtendedProcess2-4 found. False in all other cases. + * \brief Retrieve the number of columns of image. + * @return The encountered size when found, 0 by default. */ -bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.51" ) - return true; - return false; +int gdcmHeader::GetXSize(void) { + // We cannot check for "Columns" because the "Columns" tag is present + // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary. + std::string StrSize = GetPubElValByNumber(0x0028,0x0011); + if (StrSize == GDCM_UNFOUND) + return 0; + return atoi(StrSize.c_str()); } /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGExtendeProcess3-5 one. - * - * @return True when JPEGExtendedProcess3-5 found. False in all other cases. + * \brief Retrieve the number of lines of image. + * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize() + * @return The encountered size when found, 1 by default. */ -bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.52" ) - return true; - return false; +int gdcmHeader::GetYSize(void) { + // We cannot check for "Rows" because the "Rows" tag is present + // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary. + std::string StrSize = GetPubElValByNumber(0x0028,0x0010); + if (StrSize != GDCM_UNFOUND) + return atoi(StrSize.c_str()); + if ( IsDicomV3() ) + return 0; + else + // The Rows (0028,0010) entry is optional for ACR/NEMA. It might + // hence be a signal (1d image). So we default to 1: + return 1; } /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one. - * - * @return True when JPEGSpectralSelectionProcess6-8 found. False in all - * other cases. + * \brief Retrieve the number of planes of volume or the number + * of frames of a multiframe. + * \warning When present we consider the "Number of Frames" as the third + * dimension. When absent we consider the third dimension as + * being the "Planes" tag content. + * @return The encountered size when found, 1 by default. */ -bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.53" ) - return true; - return false; +int gdcmHeader::GetZSize(void) { + // Both DicomV3 and ACR/Nema consider the "Number of Frames" + // as the third dimension. + std::string StrSize = GetPubElValByNumber(0x0028,0x0008); + if (StrSize != GDCM_UNFOUND) + return atoi(StrSize.c_str()); + + // We then consider the "Planes" entry as the third dimension [we + // cannot retrieve by name since "Planes tag is present both in + // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. + StrSize = GetPubElValByNumber(0x0028,0x0012); + if (StrSize != GDCM_UNFOUND) + return atoi(StrSize.c_str()); + return 1; } /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a RLE Lossless one. - * - * @return True when RLE Lossless found. False in all - * other cases. + * \brief Retrieve the number of Bits Stored + * (as opposite to number of Bits Allocated) + * + * @return The encountered number of Bits Stored, 0 by default. */ -bool gdcmHeader::IsRLELossLessTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.5" ) - return true; - return false; +int gdcmHeader::GetBitsStored(void) { + std::string StrSize = GetPubElValByNumber(0x0028,0x0101); + if (StrSize == GDCM_UNFOUND) + return 1; + return atoi(StrSize.c_str()); } /** * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEG200 one.0 - * - * @return True when JPEG2000 (Lossly or LossLess) found. False in all - * other cases. + * \brief Retrieve the number of Bits Allocated + * (8, 12 -compacted ACR-NEMA files, 16, ...) + * + * @return The encountered number of Bits Allocated, 0 by default. */ -bool gdcmHeader::IsJPEG2000(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadElementValueSafe(Element); - std::string Transfer = Element->GetValue(); - if ( (Transfer == "1.2.840.10008.1.2.4.90") - || (Transfer == "1.2.840.10008.1.2.4.91") ) - return true; - return false; +int gdcmHeader::GetBitsAllocated(void) { + std::string StrSize = GetPubElValByNumber(0x0028,0x0100); + if (StrSize == GDCM_UNFOUND) + return 1; + return atoi(StrSize.c_str()); } /** * \ingroup gdcmHeader - * \brief Predicate for dicom version 3 file. - * @return True when the file is a dicom version 3. + * \brief Retrieve the number of Samples Per Pixel + * (1 : gray level, 3 : RGB -1 or 3 Planes-) + * + * @return The encountered number of Samples Per Pixel, 1 by default. */ -bool gdcmHeader::IsDicomV3(void) { - if ( (filetype == ExplicitVR) - || (filetype == ImplicitVR) ) - return true; - return false; +int gdcmHeader::GetSamplesPerPixel(void) { + std::string StrSize = GetPubElValByNumber(0x0028,0x0002); + if (StrSize == GDCM_UNFOUND) + return 1; // Well, it's supposed to be mandatory ... + return atoi(StrSize.c_str()); } /** * \ingroup gdcmHeader - * \brief When the length of an element value is obviously wrong (because - * the parser went Jabberwocky) one can hope improving things by - * applying this heuristic. + * \brief Retrieve the Planar Configuration for RGB images + * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane) + * + * @return The encountered Planar Configuration, 0 by default. */ -void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) { - - ElVal->SetReadLength(FoundLength); // will be updated only if a bug is found - - if ( FoundLength == 0xffffffff) { - FoundLength = 0; - } - - // Sorry for the patch! - // XMedCom did the trick to read some nasty GE images ... - else if (FoundLength == 13) { - // The following 'if' will be removed when there is no more - // images on Creatis HDs with a 13 length for Manufacturer... - if ( (ElVal->GetGroup() != 0x0008) || - ( (ElVal->GetElement() != 0x0070) && (ElVal->GetElement() != 0x0080) ) ) { - // end of remove area - FoundLength =10; - ElVal->SetReadLength(10); // a bug is to be fixed - } - } - // to fix some garbage 'Leonardo' Siemens images - // May be commented out to avoid overhead - else if ( (ElVal->GetGroup() == 0x0009) - && - ( (ElVal->GetElement() == 0x1113) || (ElVal->GetElement() == 0x1114) ) ){ - FoundLength =4; - ElVal->SetReadLength(4); // a bug is to be fixed - } - // end of fix - - // to try to 'go inside' SeQuences (with length), and not to skip them - else if ( ElVal->GetVR() == "SQ") { - if (enableSequences) // only if the user does want to ! - FoundLength =0; - } - - // a SeQuence Element is beginning - // Let's forget it's length - // (we want to 'go inside') - else if(ElVal->GetGroup() == 0xfffe){ - FoundLength =0; - } - - ElVal->SetUsableLength(FoundLength); +int gdcmHeader::GetPlanarConfiguration(void) { + std::string StrSize = GetPubElValByNumber(0x0028,0x0006); + if (StrSize == GDCM_UNFOUND) + return 0; + return atoi(StrSize.c_str()); } /** * \ingroup gdcmHeader - * \brief + * \brief Return the size (in bytes) of a single pixel of data. + * @return The size in bytes of a single pixel of data. * - * @return */ - guint32 gdcmHeader::FindLengthOB(void) { - // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. - guint16 g; - guint16 n; - long PositionOnEntry = ftell(fp); - bool FoundSequenceDelimiter = false; - guint32 TotalLength = 0; - guint32 ItemLength; - - while ( ! FoundSequenceDelimiter) { - g = ReadInt16(); - n = ReadInt16(); - if (errno == 1) - return 0; - TotalLength += 4; // We even have to decount the group and element - - if ( g != 0xfffe && g!=0xb00c ) /*for bogus header */ { - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n); - dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); - errno = 1; - return 0; - } - if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header */ - FoundSequenceDelimiter = true; - else if ( n != 0xe000 ){ - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n", - n, g,n); - dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); - errno = 1; - return 0; - } - ItemLength = ReadInt32(); - TotalLength += ItemLength + 4; // We add 4 bytes since we just read - // the ItemLength with ReadInt32 - SkipBytes(ItemLength); - } - fseek(fp, PositionOnEntry, SEEK_SET); - return TotalLength; +int gdcmHeader::GetPixelSize(void) { + std::string PixelType = GetPixelType(); + if (PixelType == "8U" || PixelType == "8S") + return 1; + if (PixelType == "16U" || PixelType == "16S") + return 2; + if (PixelType == "32U" || PixelType == "32S") + return 4; + dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type"); + return 0; } /** * \ingroup gdcmHeader - * \brief - * - * @return + * \brief Build the Pixel Type of the image. + * Possible values are: + * - 8U unsigned 8 bit, + * - 8S signed 8 bit, + * - 16U unsigned 16 bit, + * - 16S signed 16 bit, + * - 32U unsigned 32 bit, + * - 32S signed 32 bit, + * \warning 12 bit images appear as 16 bit. + * \ 24 bit images appear as 8 bit + * @return */ - void gdcmHeader::FindLength (gdcmElValue * ElVal) { - guint16 element = ElVal->GetElement(); - guint16 group = ElVal->GetGroup(); - std::string vr = ElVal->GetVR(); - guint16 length16; - if( (element == 0x0010) && (group == 0x7fe0) ) { - dbg.SetDebug(-1); - dbg.Verbose(2, "gdcmHeader::FindLength: ", - "we reached 7fe0 0010"); - } - - if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) { - if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) { - - // The following reserved two bytes (see PS 3.5-2001, section - // 7.1.2 Data element structure with explicit vr p27) must be - // skipped before proceeding on reading the length on 4 bytes. - fseek(fp, 2L, SEEK_CUR); - - guint32 length32 = ReadInt32(); - - if ( (vr == "OB") && (length32 == 0xffffffff) ) { - ElVal->SetLength(FindLengthOB()); - return; - } - FixFoundLength(ElVal, length32); - return; - } - - // Length is encoded on 2 bytes. - length16 = ReadInt16(); - - // We can tell the current file is encoded in big endian (like - // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag - // and it's value is the one of the encoding of a big endian file. - // In order to deal with such big endian encoded files, we have - // (at least) two strategies: - // * when we load the "Transfer Syntax" tag with value of big endian - // encoding, we raise the proper flags. Then we wait for the end - // of the META group (0x0002) among which is "Transfer Syntax", - // before switching the swap code to big endian. We have to postpone - // the switching of the swap code since the META group is fully encoded - // in little endian, and big endian coding only starts at the next - // group. The corresponding code can be hard to analyse and adds - // many additional unnecessary tests for regular tags. - // * the second strategy consists in waiting for trouble, that shall - // appear when we find the first group with big endian encoding. This - // is easy to detect since the length of a "Group Length" tag (the - // ones with zero as element number) has to be of 4 (0x0004). When we - // encounter 1024 (0x0400) chances are the encoding changed and we - // found a group with big endian encoding. - // We shall use this second strategy. In order to make sure that we - // can interpret the presence of an apparently big endian encoded - // length of a "Group Length" without committing a big mistake, we - // add an additional check: we look in the already parsed elements - // for the presence of a "Transfer Syntax" whose value has to be "big - // endian encoding". When this is the case, chances are we have got our - // hands on a big endian encoded file: we switch the swap code to - // big endian and proceed... - if ( (element == 0x0000) && (length16 == 0x0400) ) { - if ( ! IsExplicitVRBigEndianTransferSyntax() ) { - dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR"); - errno = 1; - return; - } - length16 = 4; - SwitchSwapToBigEndian(); - // Restore the unproperly loaded values i.e. the group, the element - // and the dictionary entry depending on them. - guint16 CorrectGroup = SwapShort(ElVal->GetGroup()); - guint16 CorrectElem = SwapShort(ElVal->GetElement()); - gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup, - CorrectElem); - if (!NewTag) { - // This correct tag is not in the dictionary. Create a new one. - NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem); - } - // FIXME this can create a memory leaks on the old entry that be - // left unreferenced. - ElVal->SetDictEntry(NewTag); - } - - // Heuristic: well some files are really ill-formed. - if ( length16 == 0xffff) { - length16 = 0; - //dbg.Verbose(0, "gdcmHeader::FindLength", - // "Erroneous element length fixed."); - // Actually, length= 0xffff means that we deal with - // Unknown Sequence Length - } - - FixFoundLength(ElVal, (guint32)length16); - return; +std::string gdcmHeader::GetPixelType(void) { + std::string BitsAlloc; + BitsAlloc = GetPubElValByNumber(0x0028, 0x0100); // Bits Allocated + if (BitsAlloc == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); + BitsAlloc = std::string("16"); + } + if (BitsAlloc == "12") // It will be unpacked + BitsAlloc = std::string("16"); + else if (BitsAlloc == "24") // (in order no to be messed up + BitsAlloc = std::string("8"); // by old RGB images) + + std::string Signed; + Signed = GetPubElValByNumber(0x0028, 0x0103); // "Pixel Representation" + if (Signed == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation"); + BitsAlloc = std::string("0"); } + if (Signed == "0") + Signed = std::string("U"); + else + Signed = std::string("S"); - // Either implicit VR or a non DICOM conformal (see not below) explicit - // VR that ommited the VR of (at least) this element. Farts happen. - // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25 - // on Data elements "Implicit and Explicit VR Data Elements shall - // not coexist in a Data Set and Data Sets nested within it".] - // Length is on 4 bytes. - FixFoundLength(ElVal, ReadInt32()); - return; + return( BitsAlloc + Signed); } /** * \ingroup gdcmHeader - * \brief Swaps back the bytes of 4-byte long integer accordingly to - * processor order. - * @return The properly swaped 32 bits integer. + * \brief Recover the offset (from the beginning of the file) of the pixels. */ -guint32 gdcmHeader::SwapLong(guint32 a) { - switch (sw) { - case 0 : - break; - case 4321 : - a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | - ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); - break; - - case 3412 : - a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); - break; - - case 2143 : - a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); - break; - default : - dbg.Error(" gdcmHeader::SwapLong : unset swap code"); - a=0; +size_t gdcmHeader::GetPixelOffset(void) { + // If this file complies with the norm we should encounter the + // "Image Location" tag (0x0028, 0x0200). This tag contains the + // the group that contains the pixel data (hence the "Pixel Data" + // is found by indirection through the "Image Location"). + // Inside the group pointed by "Image Location" the searched element + // is conventionally the element 0x0010 (when the norm is respected). + // When the "Image Location" is absent we default to group 0x7fe0. + guint16 grPixel; + guint16 numPixel; + std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); + if ( ImageLocation == GDCM_UNFOUND ) { // Image Location + grPixel = 0x7fe0; + } else { + grPixel = (guint16) atoi( ImageLocation.c_str() ); } - return(a); + if (grPixel != 0x7fe0) + // This is a kludge for old dirty Philips imager. + numPixel = 0x1010; + else + numPixel = 0x0010; + + gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, + numPixel); + if (PixelElement) + return PixelElement->GetOffset(); + else + return 0; } /** * \ingroup gdcmHeader - * \brief Swaps the bytes so they agree with the processor order - * @return The properly swaped 16 bits integer. + * \brief Recover the pixel area length (in Bytes) . */ -guint16 gdcmHeader::SwapShort(guint16 a) { - if ( (sw==4321) || (sw==2143) ) - a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff)); - return (a); +size_t gdcmHeader::GetPixelAreaLength(void) { + // If this file complies with the norm we should encounter the + // "Image Location" tag (0x0028, 0x0200). This tag contains the + // the group that contains the pixel data (hence the "Pixel Data" + // is found by indirection through the "Image Location"). + // Inside the group pointed by "Image Location" the searched element + // is conventionally the element 0x0010 (when the norm is respected). + // When the "Image Location" is absent we default to group 0x7fe0. + guint16 grPixel; + guint16 numPixel; + std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); + if ( ImageLocation == GDCM_UNFOUND ) { + grPixel = 0x7fe0; + } else { + grPixel = (guint16) atoi( ImageLocation.c_str() ); + } + if (grPixel != 0x7fe0) + // This is a kludge for old dirty Philips imager. + numPixel = 0x1010; + else + numPixel = 0x0010; + + gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, + numPixel); + if (PixelElement) + return PixelElement->GetLength(); + else + return 0; } /** - * \ingroup gdcmHeader - * \brief - * - * @return - */ - void gdcmHeader::SkipBytes(guint32 NBytes) { - //FIXME don't dump the returned value - (void)fseek(fp, (long)NBytes, SEEK_CUR); + * \ingroup gdcmHeader + * \brief tells us if LUT are used + * \warning Right now, Segmented xxx Palette Color Lookup Table Data + * \ are NOT considered as LUT, since nobody knows + *\ how to deal with them + * @return int acts as a Boolean + */ +bool gdcmHeader::HasLUT(void) { + + // Check the presence of the LUT Descriptors + if (GetPubElValByNumber(0x0028,0x1101) == GDCM_UNFOUND) + return false; + // LutDescriptorGreen + if (GetPubElValByNumber(0x0028,0x1102) == GDCM_UNFOUND) + return false; + // LutDescriptorBlue + if (GetPubElValByNumber(0x0028,0x1103) == GDCM_UNFOUND) + return false; + // It is not enough + // we check also + if (GetPubElValByNumber(0x0028,0x1201) == GDCM_UNFOUND) + return false; + if (GetPubElValByNumber(0x0028,0x1202) == GDCM_UNFOUND) + return false; + if (GetPubElValByNumber(0x0028,0x1203) == GDCM_UNFOUND) + return false; + return true; } /** - * \ingroup gdcmHeader - * \brief - * @param ElVal - * @return - */ - void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) { - SkipBytes(ElVal->GetLength()); + * \ingroup gdcmHeader + * \brief gets the info from 0028,1101 : Lookup Table Desc-Red + * \ else 0 + * @return Lookup Table nBit + * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] + */ +int gdcmHeader::GetLUTNbits(void) { + std::vector tokens; + //int LutLength; + //int LutDepth; + int LutNbits; + //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue + // Consistency already checked in GetLUTLength + std::string LutDescription = GetPubElValByNumber(0x0028,0x1101); + if (LutDescription == GDCM_UNFOUND) + return 0; + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (LutDescription, tokens, "\\"); + //LutLength=atoi(tokens[0].c_str()); + //LutDepth=atoi(tokens[1].c_str()); + LutNbits=atoi(tokens[2].c_str()); + tokens.clear(); + return LutNbits; } +/** + * \ingroup gdcmHeader + * \brief builts Red/Green/Blue/Alpha LUT from Header + * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] + * \ and (0028,1101),(0028,1102),(0028,1102) + * \ - xxx Palette Color Lookup Table Descriptor - are found + * \ and (0028,1201),(0028,1202),(0028,1202) + * \ - xxx Palette Color Lookup Table Data - are found + * \warning does NOT deal with : + * \ 0028 1100 Gray Lookup Table Descriptor (Retired) + * \ 0028 1221 Segmented Red Palette Color Lookup Table Data + * \ 0028 1222 Segmented Green Palette Color Lookup Table Data + * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data + * \ no known Dicom reader deails with them :-( + * @return Lookup Table RGBA + */ +unsigned char * gdcmHeader::GetLUTRGBA(void) { +// Not so easy : see +// http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables +// and OT-PAL-8-face.dcm + +// if Photometric Interpretation # PALETTE COLOR, no LUT to be done + if (gdcmHeader::GetPubElValByNumber(0x0028,0x0004) != "PALETTE COLOR ") { + return NULL; + } + + int lengthR, debR, nbitsR; + int lengthG, debG, nbitsG; + int lengthB, debB, nbitsB; + +// Get info from Lut Descriptors +// (the 3 LUT descriptors may be different) + std::string LutDescriptionR = GetPubElValByNumber(0x0028,0x1101); + if (LutDescriptionR == GDCM_UNFOUND) + return NULL; + std::string LutDescriptionG = GetPubElValByNumber(0x0028,0x1102); + if (LutDescriptionG == GDCM_UNFOUND) + return NULL; + std::string LutDescriptionB = GetPubElValByNumber(0x0028,0x1103); + if (LutDescriptionB == GDCM_UNFOUND) + return NULL; + + std::vector tokens; + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (LutDescriptionR, tokens, "\\"); + lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes + debR =atoi(tokens[1].c_str()); // subscript of the first Lut Value + nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits) + tokens.clear(); + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (LutDescriptionG, tokens, "\\"); + lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes + debG =atoi(tokens[1].c_str()); + nbitsG =atoi(tokens[2].c_str()); + tokens.clear(); + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (LutDescriptionB, tokens, "\\"); + lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes + debB =atoi(tokens[1].c_str()); + nbitsB =atoi(tokens[2].c_str()); + tokens.clear(); + +// Load LUTs into memory, (as they were stored on disk) + unsigned char *lutR = (unsigned char *) + GetPubElValVoidAreaByNumber(0x0028,0x1201); + unsigned char *lutG = (unsigned char *) + GetPubElValVoidAreaByNumber(0x0028,0x1202); + unsigned char *lutB = (unsigned char *) + GetPubElValVoidAreaByNumber(0x0028,0x1203); + + if (!lutR || !lutG || !lutB ) { + return NULL; + } + // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT + + unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) + if (!LUTRGBA) { + return NULL; + } + memset(LUTRGBA, 0, 1024); + // Bits Allocated + int nb; + std::string str_nb = GetPubElValByNumber(0x0028,0x0100); + if (str_nb == GDCM_UNFOUND ) { + nb = 16; + } else { + nb = atoi(str_nb.c_str() ); + } + int mult; + + if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size + mult=2; // high byte must be = low byte + else // See PS 3.3-2003 C.11.1.1.2 p 619 + mult=1; + + // if we get a black image, let's just remove the '+1' + // from 'i*mult+1' and check again + // if it works, we shall have to check the 3 Palettes + // to see which byte is ==0 (first one, or second one) + // and fix the code + // We give up the checking to avoid some overhead + unsigned char *a; + int i; + + a = LUTRGBA+0; + for(i=0;i= (guint32)0xffffffff) { - MaxSizeLoadElementValue = 0xffffffff; - return; +std::string gdcmHeader::GetTransfertSyntaxName(void) { + // use the gdcmTS (TS : Transfert Syntax) + std::string TransfertSyntax = GetPubElValByNumber(0x0002,0x0010); + if (TransfertSyntax == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetTransferSyntaxName: unfound Transfert Syntax (0002,0010)"); + return "Uncompressed ACR-NEMA"; } - MaxSizeLoadElementValue = NewSize; + // we do it only when we need it + gdcmTS * ts = gdcmGlobal::GetTS(); + std::string tsName=ts->GetValue(TransfertSyntax); + //delete ts; // Seg Fault when deleted ?! + return tsName; } /** - * \ingroup gdcmHeader - * \brief Loads the element content if it's length is not bigger - * than the value specified with - * gdcmHeader::SetMaxSizeLoadElementValue() + * \ingroup gdcmHeader + * \brief Searches within the public dictionary for element value of + * a given tag. + * @param tagName name of the searched element. + * @return Corresponding element value when it exists, and the string + * GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { - size_t item_read; - guint16 group = ElVal->GetGroup(); - std::string vr= ElVal->GetVR(); - guint32 length = ElVal->GetLength(); - bool SkipLoad = false; - - fseek(fp, (long)ElVal->GetOffset(), SEEK_SET); - - // FIXME Sequences not treated yet ! - // - // Ne faudrait-il pas au contraire trouver immediatement - // une maniere 'propre' de traiter les sequences (vr = SQ) - // car commencer par les ignorer risque de conduire a qq chose - // qui pourrait ne pas etre generalisable - // Well, I'm expecting your code !!! - - // the test was commented out to 'go inside' the SeQuences - // we don't any longer skip them ! - - // if( vr == "SQ" ) - // SkipLoad = true; - - // A SeQuence "contains" a set of Elements. - // (fffe e000) tells us an Element is beginning - // (fffe e00d) tells us an Element just ended - // (fffe e0dd) tells us the current SeQuence just ended - - if( group == 0xfffe ) - SkipLoad = true; +std::string gdcmHeader::GetPubElValByName(std::string tagName) { + gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + if( dictEntry == NULL) + return GDCM_UNFOUND; + return(PubElValSet.GetElValueByNumber(dictEntry->GetGroup(), + dictEntry->GetElement())); +} - if ( SkipLoad ) { - ElVal->SetLength(0); - ElVal->SetValue("gdcm::Skipped"); - return; - } +/** + * \ingroup gdcmHeader + * \brief Searches within the elements parsed with the public dictionary for + * the element value representation of a given tag. + * + * Obtaining the VR (Value Representation) might be needed by caller + * to convert the string typed content to caller's native type + * (think of C++ vs Python). The VR is actually of a higher level + * of semantics than just the native C++ type. + * @param tagName name of the searched element. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. + */ +std::string gdcmHeader::GetPubElValRepByName(std::string tagName) { + gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + if( dictEntry == NULL) + return GDCM_UNFOUND; + gdcmElValue* elem = PubElValSet.GetElementByNumber( + dictEntry->GetGroup(), + dictEntry->GetElement()); + return elem->GetVR(); +} - // When the length is zero things are easy: - if ( length == 0 ) { - ElVal->SetValue(""); - return; - } - - // The elements whose length is bigger than the specified upper bound - // are not loaded. Instead we leave a short notice of the offset of - // the element content and it's length. - if (length > MaxSizeLoadElementValue) { - std::ostringstream s; - s << "gdcm::NotLoaded."; - s << " Address:" << (long)ElVal->GetOffset(); - s << " Length:" << ElVal->GetLength(); - s << " x(" << std::hex << ElVal->GetLength() << ")"; - ElVal->SetValue(s.str()); - return; - } - - // When an integer is expected, read and convert the following two or - // four bytes properly i.e. as an integer as opposed to a string. - - // Actually, elements with Value Multiplicity > 1 - // contain a set of integers (not a single one) - // Any compacter code suggested (?) - - if ( IsAnInteger(ElVal) ) { - guint32 NewInt; - std::ostringstream s; - int nbInt; - if (vr == "US" || vr == "SS") { - nbInt = length / 2; - NewInt = ReadInt16(); - s << NewInt; - if (nbInt > 1) { - for (int i=1; i < nbInt; i++) { - s << '\\'; - NewInt = ReadInt16(); - s << NewInt; - } - } - - } else if (vr == "UL" || vr == "SL") { - nbInt = length / 4; - NewInt = ReadInt32(); - s << NewInt; - if (nbInt > 1) { - for (int i=1; i < nbInt; i++) { - s << '\\'; - NewInt = ReadInt32(); - s << NewInt; - } - } - } -#ifdef GDCM_NO_ANSI_STRING_STREAM - s << std::ends; // to avoid oddities on Solaris -#endif //GDCM_NO_ANSI_STRING_STREAM - ElVal->SetValue(s.str()); - return; - } - - // We need an additional byte for storing \0 that is not on disk - char* NewValue = (char*)malloc(length+1); - if( !NewValue) { - dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue"); - return; - } - NewValue[length]= 0; - - item_read = fread(NewValue, (size_t)length, (size_t)1, fp); - if ( item_read != 1 ) { - free(NewValue); - dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value"); - ElVal->SetValue("gdcm::UnRead"); - return; - } - ElVal->SetValue(NewValue); - free(NewValue); -} +/** + * \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::GetPubElValByNumber(guint16 group, guint16 element) { + return PubElValSet.GetElValueByNumber(group, element); +} /** - * \ingroup gdcmHeader - * \brief Loads the element while preserving the current - * underlying file position indicator as opposed to - * to LoadElementValue that modifies it. - * @param ElVal Element whose value shall be loaded. - * @return + * \ingroup gdcmHeader + * \brief Searches within the public dictionary for element value + * representation of a given tag. + * + * Obtaining the VR (Value Representation) might be needed by caller + * to convert the string typed content to caller's native type + * (think of C++ vs Python). The VR is actually of a higher level + * of semantics than just the native C++ type. + * @param group Group of the researched tag. + * @param element Element of the researched tag. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { - long PositionOnEntry = ftell(fp); - LoadElementValue(ElVal); - fseek(fp, PositionOnEntry, SEEK_SET); +std::string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) { + gdcmElValue* elem = PubElValSet.GetElementByNumber(group, element); + if ( !elem ) + return GDCM_UNFOUND; + return elem->GetVR(); } /** * \ingroup gdcmHeader - * \brief Reads a supposed to be 16 Bits integer - * \ (swaps it depending on processor endianity) - * - * @return integer acts as a boolean + * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance + * through tag name and modifies it's content with the given value. + * @param content new value to substitute with + * @param tagName name of the tag to be modified */ -guint16 gdcmHeader::ReadInt16(void) { - guint16 g; - size_t item_read; - item_read = fread (&g, (size_t)2,(size_t)1, fp); - if ( item_read != 1 ) { - // dbg.Verbose(0, "gdcmHeader::ReadInt16", " Failed to read :"); - // if(feof(fp)) - // dbg.Verbose(0, "gdcmHeader::ReadInt16", " End of File encountered"); - if(ferror(fp)) - dbg.Verbose(0, "gdcmHeader::ReadInt16", " File Error"); - errno = 1; - return 0; - } - errno = 0; - g = SwapShort(g); - return g; +bool gdcmHeader::SetPubElValByName(std::string content, std::string tagName) { + //return ( PubElValSet.SetElValueByName (content, tagName) ); + gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + if( dictEntry == NULL) + return false; + return(PubElValSet.SetElValueByNumber(content, + dictEntry->GetGroup(), + dictEntry->GetElement())); } /** * \ingroup gdcmHeader - * \brief Reads a supposed to be 32 Bits integer - * \ (swaps it depending on processor endianity) - * - * @return + * \brief Accesses an existing gdcmElValue (i.e. a Dicom Element) + * in the PubElValSet 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 */ -guint32 gdcmHeader::ReadInt32(void) { - guint32 g; - size_t item_read; - item_read = fread (&g, (size_t)4,(size_t)1, fp); - if ( item_read != 1 ) { - //dbg.Verbose(0, "gdcmHeader::ReadInt32", " Failed to read :"); - //if(feof(fp)) - // dbg.Verbose(0, "gdcmHeader::ReadInt32", " End of File encountered"); - if(ferror(fp)) - dbg.Verbose(0, "gdcmHeader::ReadInt32", " File Error"); - errno = 1; - return 0; - } - errno = 0; - g = SwapLong(g); - return g; +bool gdcmHeader::SetPubElValByNumber(std::string content, guint16 group, + guint16 element) + +//TODO : homogeneiser les noms : SetPubElValByNumber +// qui appelle PubElValSet.SetElValueByNumber +// pourquoi pas SetPubElValueByNumber ?? +{ + return ( PubElValSet.SetElValueByNumber (content, group, element) ); } /** * \ingroup gdcmHeader - * \brief - * - * @return + * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance + * through it's (group, element) and modifies it's length with + * the given value. + * \warning Use with extreme caution. + * @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. */ - gdcmElValue* gdcmHeader::GetElValueByNumber(guint16 Group, guint16 Elem) { - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); - return (gdcmElValue*)0; - } - return elValue; +bool gdcmHeader::SetPubElValLengthByNumber(guint32 length, guint16 group, + guint16 element) { + return ( PubElValSet.SetElValueLengthByNumber (length, group, element) ); } /** * \ingroup gdcmHeader - * \brief Build a new Element Value from all the low level arguments. - * Check for existence of dictionary entry, and build - * a default one when absent. - * @param Group group of the underlying DictEntry - * @param Elem element of the underlying DictEntry + * \brief Searches within elements parsed with the public dictionary + * and then within the elements parsed with the shadow dictionary + * for the element value of a given tag. + * @param tagName name of the searched element. + * @return Corresponding element value when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -gdcmElValue* gdcmHeader::NewElValueByNumber(guint16 Group, guint16 Elem) { - // Find out if the tag we encountered is in the dictionaries: - gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem); - if (!NewTag) - NewTag = new gdcmDictEntry(Group, Elem); - - gdcmElValue* NewElVal = new gdcmElValue(NewTag); - if (!NewElVal) { - dbg.Verbose(1, "gdcmHeader::NewElValueByNumber", - "failed to allocate gdcmElValue"); - return (gdcmElValue*)0; - } - return NewElVal; +std::string gdcmHeader::GetElValByName(std::string tagName) { + std::string pub = GetPubElValByName(tagName); + return pub; } /** * \ingroup gdcmHeader - * \brief TODO - * @param Value - * @param Group - * @param Elem - * \return integer acts as a boolean + * \brief Searches within elements parsed with the public dictionary + * and then within the elements parsed with the shadow dictionary + * for the element value representation of a given tag. + * + * Obtaining the VR (Value Representation) might be needed by caller + * to convert the string typed content to caller's native type + * (think of C++ vs Python). The VR is actually of a higher level + * of semantics than just the native C++ type. + * @param tagName name of the searched element. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, - guint16 Group, guint16 Elem ) { - // TODO : FIXME JPRx - // curieux, non ? - // on (je) cree une Elvalue ne contenant pas de valeur - // on l'ajoute au ElValSet - // on affecte une valeur a cette ElValue a l'interieur du ElValSet - // --> devrait pouvoir etre fait + simplement ??? - if (CheckIfExistByNumber(Group, Elem) == 0) { - gdcmElValue* a =NewElValueByNumber(Group, Elem); - if (a == NULL) - return false; - PubElValSet.Add(a); - } - PubElValSet.SetElValueByNumber(Value, Group, Elem); - return(true); -} - +std::string gdcmHeader::GetElValRepByName(std::string tagName) { + std::string pub = GetPubElValRepByName(tagName); + return pub; +} /** * \ingroup gdcmHeader - * \brief Modify (or Creates if not found) an element - * @param Value new value - * @param Group - * @param Elem - * \return integer acts as a boolean - * + * \brief Searches within elements parsed with the public dictionary + * and then within the elements parsed with the shadow dictionary + * for the element value of a given tag. + * @param group Group of the searched tag. + * @param element Element of the searched tag. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) { - - gdcmElValue* nvElValue=NewElValueByNumber(Group, Elem); - // TODO : check if fails - PubElValSet.Add(nvElValue); - std::string v = Value; - PubElValSet.SetElValueByNumber(v, Group, Elem); - return(true); -} - +std::string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) { + std::string pub = GetPubElValByNumber(group, element); + return pub; +} /** * \ingroup gdcmHeader - * \brief Set a new value if the invoked element exists - * Seems to be useless !!! - * @param Value - * @param Group - * @param Elem - * \return integer acts as a boolean + * \brief Searches within elements parsed with the public dictionary + * and then within the elements parsed with the shadow dictionary + * for the element value representation of a given tag. + * + * Obtaining the VR (Value Representation) might be needed by caller + * to convert the string typed content to caller's native type + * (think of C++ vs Python). The VR is actually of a higher level + * of semantics than just the native C++ type. + * @param group Group of the searched tag. + * @param element Element of the searched tag. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) { +std::string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) { + std::string pub = GetPubElValRepByNumber(group, element); + return pub; +} - //gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - std::string v = Value; - PubElValSet.SetElValueByNumber(v, Group, Elem); +/** + * \ingroup gdcmElValSet + * \brief Sets the value (string) of the target Dicom Element + * @param content string value of the Dicom Element + * @param tagName name of the searched Dicom Element. + * @return true when found + */ +bool gdcmHeader::SetElValueByName(std::string content, + std::string tagName) { + + gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + if( dictEntry == NULL) + return false; + + + TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), + dictEntry->GetElement()); + if ( ! PubElValSet.GetTagHt().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); + gdcmElValue * a; + IterHT p; + TagElValueHT::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 = ((PubElValSet.GetTagHt().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 Checks if a given ElValue (group,number) - * \ exists in the Public ElValSet - * @param Group - * @param Elem - * @return integer acts as a boolean + * \brief + * @param exception_on_error + * @return */ - -bool gdcmHeader::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { - return (PubElValSet.CheckIfExistByNumber(Group, Elem)); - } - +FILE *gdcmHeader::OpenFile(bool exception_on_error) + throw(gdcmFileError) { + fp=fopen(filename.c_str(),"rb"); + if(exception_on_error) { + if(!fp) + throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)"); + } + + if ( fp ) { + guint16 zero; + fread(&zero, (size_t)2, (size_t)1, fp); + + //ACR -- or DICOM with no Preamble + if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200) + return(fp); + + //DICOM + fseek(fp, 126L, SEEK_CUR); + char dicm[4]; + fread(dicm, (size_t)4, (size_t)1, fp); + if( memcmp(dicm, "DICM", 4) == 0 ) + return(fp); + + fclose(fp); + dbg.Verbose(0, "gdcmHeader::gdcmHeader not DICOM/ACR", filename.c_str()); + } + else { + dbg.Verbose(0, "gdcmHeader::gdcmHeader cannot open file", filename.c_str()); + } + return(NULL); +} + /** * \ingroup gdcmHeader - * \brief Build a new Element Value from all the low level arguments. - * Check for existence of dictionary entry, and build - * a default one when absent. - * @param Name Name of the underlying DictEntry + * \brief + * @return TRUE if the close was successfull */ -gdcmElValue* gdcmHeader::NewElValueByName(std::string Name) { - - gdcmDictEntry * NewTag = GetDictEntryByName(Name); - if (!NewTag) - NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); - - gdcmElValue* NewElVal = new gdcmElValue(NewTag); - if (!NewElVal) { - dbg.Verbose(1, "gdcmHeader::ObtainElValueByName", - "failed to allocate gdcmElValue"); - return (gdcmElValue*)0; - } - return NewElVal; -} +bool gdcmHeader::CloseFile(void) { + int closed = fclose(fp); + fp = (FILE *)0; + if (! closed) + return false; + return true; +} /** * \ingroup gdcmHeader - * \brief Read the next tag but WITHOUT loading it's value - * @return On succes the newly created ElValue, NULL on failure. + * \brief Parses the header of the file but WITHOUT loading element values. */ -gdcmElValue * gdcmHeader::ReadNextElement(void) { - - guint16 g,n; - gdcmElValue * NewElVal; - - g = ReadInt16(); - n = ReadInt16(); - - if (errno == 1) - // We reached the EOF (or an error occured) and header parsing - // has to be considered as finished. - return (gdcmElValue *)0; +void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { + gdcmElValue * newElValue = (gdcmElValue *)0; - NewElVal = NewElValueByNumber(g, n); - FindVR(NewElVal); - FindLength(NewElVal); - - if (errno == 1) { - // Call it quits - return (gdcmElValue *)0; + rewind(fp); + CheckSwap(); + while ( (newElValue = ReadNextElement()) ) { + SkipElementValue(newElValue); + PubElValSet.Add(newElValue); } - NewElVal->SetOffset(ftell(fp)); - //if ( (g==0x7fe0) && (n==0x0010) ) - return NewElVal; } /** * \ingroup gdcmHeader - * \brief Apply some heuristics to predict wether the considered - * element value contains/represents an integer or not. - * @param ElVal The element value on which to apply the predicate. - * @return The result of the heuristical predicate. - */ -bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) { - guint16 element = ElVal->GetElement(); - guint16 group = ElVal->GetGroup(); - std::string vr = ElVal->GetVR(); - guint32 length = ElVal->GetLength(); + * \brief + * @return integer, acts as a Boolean + */ +bool gdcmHeader::Write(FILE * fp, FileType type) { - cout << "Found :" << std::hex - << group << " , " << element << std::endl; - - // When we have some semantics on the element we just read, and if we - // a priori know we are dealing with an integer, then we shall be - // able to swap it's element value properly. - if ( element == 0 ) { // This is the group length of the group - if (length == 4) - return true; - else { - cout << "Error on :" << std::hex - << group << " , " << element << std::endl; - dbg.Error("gdcmHeader::IsAnInteger", - "Erroneous Group Length element length."); - } + // TODO : move the following lines (and a lot of others, to be written) + // to a future function CheckAndCorrectHeader + + if (type == ImplicitVR) { + std::string implicitVRTransfertSyntax = "1.2.840.10008.1.2"; + ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010); + + //FIXME Refer to standards on page 21, chapter 6.2 "Value representation": + // 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 + + PubElValSet.SetElValueLengthByNumber(18, 0x0002, 0x0010); + } + + if (type == ExplicitVR) { + std::string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1"; + ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010); + + //FIXME Refer to standards on page 21, chapter 6.2 "Value representation": + // 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 + + PubElValSet.SetElValueLengthByNumber(20, 0x0002, 0x0010); } - if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") ) - return true; - - return false; + + return PubElValSet.Write(fp, type); } /** - * \ingroup gdcmHeader - * \brief Recover the offset (from the beginning of the file) of the pixels. + * \ingroup gdcmFile + * \brief Sets the Pixel Area size in the Header + * --> not-for-rats function + * + * \warning WARNING doit-etre etre publique ? + * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions + * + * @param ImageDataSize new Pixel Area Size + * warning : nothing else is checked */ -size_t gdcmHeader::GetPixelOffset(void) { - // If this file complies with the norm we should encounter the - // "Image Location" tag (0x0028, 0x0200). This tag contains the - // the group that contains the pixel data (hence the "Pixel Data" - // is found by indirection through the "Image Location"). - // Inside the group pointed by "Image Location" the searched element - // is conventionally the element 0x0010 (when the norm is respected). - // When the "Image Location" is absent we default to group 0x7fe0. - guint16 grPixel; - guint16 numPixel; - std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); - if ( ImageLocation == GDCM_UNFOUND ) { // Image Location - grPixel = 0x7fe0; - } else { - grPixel = (guint16) atoi( ImageLocation.c_str() ); - } - if (grPixel != 0x7fe0) - // This is a kludge for old dirty Philips imager. - numPixel = 0x1010; - else - numPixel = 0x0010; - - gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, - numPixel); - if (PixelElement) - return PixelElement->GetOffset(); - else - return 0; +void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { + std::string content1; + char car[20]; + // Assumes ElValue (0x7fe0, 0x0010) exists ... + sprintf(car,"%d",ImageDataSize); + + gdcmElValue *a = GetElValueByNumber(0x7fe0, 0x0010); + a->SetLength(ImageDataSize); + + ImageDataSize+=8; + sprintf(car,"%d",ImageDataSize); + content1=car; + SetPubElValByNumber(content1, 0x7fe0, 0x0000); } /** * \ingroup gdcmHeader - * \brief Recover the pixel area length (in Bytes) . + * \brief Swaps back the bytes of 4-byte long integer accordingly to + * processor order. + * @return The properly swaped 32 bits integer. */ -size_t gdcmHeader::GetPixelAreaLength(void) { - // If this file complies with the norm we should encounter the - // "Image Location" tag (0x0028, 0x0200). This tag contains the - // the group that contains the pixel data (hence the "Pixel Data" - // is found by indirection through the "Image Location"). - // Inside the group pointed by "Image Location" the searched element - // is conventionally the element 0x0010 (when the norm is respected). - // When the "Image Location" is absent we default to group 0x7fe0. - guint16 grPixel; - guint16 numPixel; - std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); - if ( ImageLocation == GDCM_UNFOUND ) { - grPixel = 0x7fe0; - } else { - grPixel = (guint16) atoi( ImageLocation.c_str() ); +guint32 gdcmHeader::SwapLong(guint32 a) { + switch (sw) { + case 0 : + break; + case 4321 : + a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | + ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); + break; + + case 3412 : + a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); + break; + + case 2143 : + a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); + break; + default : + dbg.Error(" gdcmHeader::SwapLong : unset swap code"); + a=0; } - if (grPixel != 0x7fe0) - // This is a kludge for old dirty Philips imager. - numPixel = 0x1010; - else - numPixel = 0x0010; - - gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, - numPixel); - if (PixelElement) - return PixelElement->GetLength(); - else - return 0; + return(a); } /** * \ingroup gdcmHeader - * \brief Searches both the public and the shadow dictionary (when they - * exist) for the presence of the DictEntry with given - * group and element. The public dictionary has precedence on the - * shadow one. - * @param group group of the searched DictEntry - * @param element element of the searched DictEntry - * @return Corresponding DictEntry when it exists, NULL otherwise. + * \brief Swaps the bytes so they agree with the processor order + * @return The properly swaped 16 bits integer. */ -gdcmDictEntry * gdcmHeader::GetDictEntryByNumber(guint16 group, - guint16 element) { - gdcmDictEntry * found = (gdcmDictEntry*)0; - if (!RefPubDict && !RefShaDict) { - dbg.Verbose(0, "gdcmHeader::GetDictEntry", - "we SHOULD have a default dictionary"); - } - if (RefPubDict) { - found = RefPubDict->GetTagByNumber(group, element); - if (found) - return found; - } - if (RefShaDict) { - found = RefShaDict->GetTagByNumber(group, element); - if (found) - return found; - } - return found; +guint16 gdcmHeader::SwapShort(guint16 a) { + if ( (sw==4321) || (sw==2143) ) + a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff)); + return (a); } +//----------------------------------------------------------------------------- +// Protected /** * \ingroup gdcmHeader - * \brief Searches both the public and the shadow dictionary (when they - * exist) for the presence of the DictEntry with given name. - * The public dictionary has precedence on the shadow one. - * @param Name name of the searched DictEntry - * @return Corresponding DictEntry when it exists, NULL otherwise. + * \brief + * + * @return */ -gdcmDictEntry * gdcmHeader::GetDictEntryByName(std::string Name) { - gdcmDictEntry * found = (gdcmDictEntry*)0; - if (!RefPubDict && !RefShaDict) { - dbg.Verbose(0, "gdcmHeader::GetDictEntry", - "we SHOULD have a default dictionary"); - } - if (RefPubDict) { - found = RefPubDict->GetTagByName(Name); - if (found) - return found; - } - if (RefShaDict) { - found = RefShaDict->GetTagByName(Name); - if (found) - return found; +gdcmElValue* gdcmHeader::GetElValueByNumber(guint16 Group, guint16 Elem) { + + gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); + if (!elValue) { + dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", + "failed to Locate gdcmElValue"); + return (gdcmElValue*)0; } - return found; + return elValue; } /** * \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. + * \brief Checks if a given ElValue (group,number) + * \ exists in the Public ElValSet + * @param Group + * @param Elem + * @return integer acts as a boolean */ -std::string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) { - return PubElValSet.GetElValueByNumber(group, element); +bool gdcmHeader::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { + return (PubElValSet.CheckIfExistByNumber(Group, Elem)); } /** * \ingroup gdcmHeader - * \brief Searches within the public dictionary for element value - * representation of a given tag. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param group Group of the researched tag. - * @param element Element of the researched tag. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. + * \brief Gets (from Header) the offset of a 'non string' element value + * \ (LoadElementValue has already be executed) + * @param Group + * @param Elem + * @return File Offset of the Element Value */ -std::string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) { - gdcmElValue* elem = PubElValSet.GetElementByNumber(group, element); - if ( !elem ) - return GDCM_UNFOUND; - return elem->GetVR(); +size_t gdcmHeader::GetPubElValOffsetByNumber(guint16 Group, guint16 Elem) { + gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); + if (!elValue) { + dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", + "failed to Locate gdcmElValue"); + return (size_t)0; + } + return elValue->GetOffset(); } /** * \ingroup gdcmHeader - * \brief Searches within the public dictionary for element value of - * a given tag. - * @param tagName name of the searched element. - * @return Corresponding element value when it exists, and the string - * GDCM_UNFOUND ("gdcm::Unfound") otherwise. + * \brief Gets (from Header) a 'non string' element value + * \ (LoadElementValue has already be executed) + * @param Group + * @param Elem + * @return Pointer to the 'non string' area */ -std::string gdcmHeader::GetPubElValByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); - if( dictEntry == NULL) - return GDCM_UNFOUND; - return(PubElValSet.GetElValueByNumber(dictEntry->GetGroup(), - dictEntry->GetElement())); +void * gdcmHeader::GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem) { + gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); + if (!elValue) { + dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", + "failed to Locate gdcmElValue"); + return (NULL); + } + return elValue->GetVoidArea(); } /** - * \ingroup gdcmHeader - * \brief Searches within the elements parsed with the public dictionary for - * the element value representation of a given tag. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param tagName name of the searched element. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. + * \ingroup gdcmHeader + * \brief Loads (from disk) the element content + * when a string is not suitable */ -std::string gdcmHeader::GetPubElValRepByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); - if( dictEntry == NULL) - return GDCM_UNFOUND; - gdcmElValue* elem = PubElValSet.GetElementByNumber( - dictEntry->GetGroup(), - dictEntry->GetElement()); - return elem->GetVR(); -} - -/** - * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value of a given tag. - * @param group Group of the searched tag. - * @param element Element of the searched tag. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) { - std::string pub = GetPubElValByNumber(group, element); - return pub; -} - -/** - * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value representation of a given tag. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param group Group of the searched tag. - * @param element Element of the searched tag. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) { - std::string pub = GetPubElValRepByNumber(group, element); - return pub; -} - -/** - * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value of a given tag. - * @param tagName name of the searched element. - * @return Corresponding element value when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmHeader::GetElValByName(std::string tagName) { - std::string pub = GetPubElValByName(tagName); - return pub; -} - -/** - * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value representation of a given tag. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param tagName name of the searched element. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmHeader::GetElValRepByName(std::string tagName) { - std::string pub = GetPubElValRepByName(tagName); - return pub; -} - -/** - * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue (i.e. a Dicom Element) - * in the PubElValSet 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::SetPubElValByNumber(std::string content, guint16 group, - guint16 element) - -//TODO : homogeneiser les noms : SetPubElValByNumber -// qui appelle PubElValSet.SetElValueByNumber -// pourquoi pas SetPubElValueByNumber ?? -{ - return ( PubElValSet.SetElValueByNumber (content, group, element) ); +void * gdcmHeader::LoadElementVoidArea(guint16 Group, guint16 Elem) { + gdcmElValue * Element= PubElValSet.GetElementByNumber(Group, Elem); + if ( !Element ) + return NULL; + size_t o =(size_t)Element->GetOffset(); + fseek(fp, o, SEEK_SET); + int l=Element->GetLength(); + void * a = malloc(l); + if(!a) { + return NULL; + } + /* int res = */ PubElValSet.SetVoidAreaByNumber(a, Group, Elem); + // TODO check the result + size_t l2 = fread(a, 1, l ,fp); + if(l != l2) { + free(a); + return NULL; + } + return a; } /** * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance - * through tag name and modifies it's content with the given value. - * @param content new value to substitute with - * @param tagName name of the tag to be modified + * \brief TODO + * @param Value + * @param Group + * @param Elem + * \return integer acts as a boolean */ -bool gdcmHeader::SetPubElValByName(std::string content, std::string tagName) { - //return ( PubElValSet.SetElValueByName (content, tagName) ); - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); - if( dictEntry == NULL) - return false; - return(PubElValSet.SetElValueByNumber(content, - dictEntry->GetGroup(), - dictEntry->GetElement())); -} +bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, + guint16 Group, guint16 Elem ) { + // TODO : FIXME JPRx + // curieux, non ? + // on (je) cree une Elvalue ne contenant pas de valeur + // on l'ajoute au ElValSet + // on affecte une valeur a cette ElValue a l'interieur du ElValSet + // --> devrait pouvoir etre fait + simplement ??? + if (CheckIfExistByNumber(Group, Elem) == 0) { + gdcmElValue* a =NewElValueByNumber(Group, Elem); + if (a == NULL) + return false; + PubElValSet.Add(a); + } + PubElValSet.SetElValueByNumber(Value, Group, Elem); + return(true); +} /** * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance - * through it's (group, element) and modifies it's length with - * the given value. - * \warning Use with extreme caution. - * @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. + * \brief Modify (or Creates if not found) an element + * @param Value new value + * @param Group + * @param Elem + * \return integer acts as a boolean + * */ +bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) { -bool gdcmHeader::SetPubElValLengthByNumber(guint32 length, guint16 group, - guint16 element) { - return ( PubElValSet.SetElValueLengthByNumber (length, group, element) ); -} - -/** - * \ingroup gdcmHeader - * \brief Parses the header of the file but WITHOUT loading element values. - */ -void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { - gdcmElValue * newElValue = (gdcmElValue *)0; - - rewind(fp); - CheckSwap(); - while ( (newElValue = ReadNextElement()) ) { - SkipElementValue(newElValue); - PubElValSet.Add(newElValue); - } -} + gdcmElValue* nvElValue=NewElValueByNumber(Group, Elem); + // TODO : check if fails + PubElValSet.Add(nvElValue); + std::string v = Value; + PubElValSet.SetElValueByNumber(v, Group, Elem); + return(true); +} /** * \ingroup gdcmHeader - * \brief - * @return + * \brief Set a new value if the invoked element exists + * Seems to be useless !!! + * @param Value + * @param Group + * @param Elem + * \return integer acts as a boolean */ -FileType gdcmHeader::GetFileType(void) -{ - return(filetype); -} +bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) { -/** - * \ingroup gdcmHeader - * \brief This predicate, based on hopefully reasonable heuristics, - * decides whether or not the current gdcmHeader was properly parsed - * and contains the mandatory information for being considered as - * a well formed and usable image. - * @return true when gdcmHeader is the one of a reasonable Dicom file, - * false otherwise. - */ -bool gdcmHeader::IsReadable(void) { - std::string res = GetPubElValByNumber(0x0028, 0x0005); - if ( res != GDCM_UNFOUND - && atoi(res.c_str()) > 4 ) { - return false; // Image Dimensions - } - if ( GetPubElValByNumber(0x0028, 0x0100) == GDCM_UNFOUND ) - return false; // "Bits Allocated" - if ( GetPubElValByNumber(0x0028, 0x0101) == GDCM_UNFOUND ) - return false; // "Bits Stored" - if ( GetPubElValByNumber(0x0028, 0x0102) == GDCM_UNFOUND ) - return false; // "High Bit" - if ( GetPubElValByNumber(0x0028, 0x0103) == GDCM_UNFOUND ) - return false; // "Pixel Representation" + //gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); + std::string v = Value; + PubElValSet.SetElValueByNumber(v, Group, Elem); return true; -} - -/** - * \ingroup gdcmHeader - * \brief Small utility function that creates a new manually crafted - * (as opposed as read from the file) gdcmElValue with user - * specified name and adds it to the public tag hash table. - * \note A fake TagKey is generated so the PubDict can keep it's coherence. - * @param NewTagName The name to be given to this new tag. - * @param VR The Value Representation to be given to this new tag. - * @ return The newly hand crafted Element Value. - */ -gdcmElValue* gdcmHeader::NewManualElValToPubDict(std::string NewTagName, - std::string VR) { - gdcmElValue* NewElVal = (gdcmElValue*)0; - guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info - guint32 FreeElem = 0; - gdcmDictEntry* NewEntry = (gdcmDictEntry*)0; - - FreeElem = PubElValSet.GenerateFreeTagKeyInGroup(StuffGroup); - if (FreeElem == UINT32_MAX) { - dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict", - "Group 0xffff in Public Dict is full"); - return (gdcmElValue*)0; - } - NewEntry = new gdcmDictEntry(StuffGroup, FreeElem, - VR, "GDCM", NewTagName); - NewElVal = new gdcmElValue(NewEntry); - PubElValSet.Add(NewElVal); - return NewElVal; -} +} +//----------------------------------------------------------------------------- +// Private /** * \ingroup gdcmHeader * \brief Loads the element values of all the elements present in the @@ -1740,8 +1394,8 @@ void gdcmHeader::LoadElements(void) { // LoadElementValue(tag->second); //} - for (ListTag::iterator i = GetListElem().begin(); - i != GetListElem().end(); + for (ListTag::iterator i = GetPubListElem().begin(); + i != GetPubListElem().end(); ++i){ LoadElementValue(*i); } @@ -1781,560 +1435,891 @@ void gdcmHeader::LoadElements(void) { } /** - * \ingroup gdcmHeader - * \brief - * @return - */ -void gdcmHeader::PrintPubElVal(std::ostream & os) { - PubElValSet.Print(os); -} - -/** - * \ingroup gdcmHeader - * \brief - * @return - */ -void gdcmHeader::PrintPubDict(std::ostream & os) { - RefPubDict->Print(os); -} - -/** - * \ingroup gdcmHeader - * \brief - * @return integer, acts as a Boolean - */ -bool gdcmHeader::Write(FILE * fp, FileType type) { + * \ingroup gdcmHeader + * \brief Loads the element content if it's length is not bigger + * than the value specified with + * gdcmHeader::SetMaxSizeLoadElementValue() + */ +void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { + size_t item_read; + guint16 group = ElVal->GetGroup(); + std::string vr= ElVal->GetVR(); + guint32 length = ElVal->GetLength(); + bool SkipLoad = false; - // TODO : move the following lines (and a lot of others, to be written) - // to a future function CheckAndCorrectHeader + fseek(fp, (long)ElVal->GetOffset(), SEEK_SET); + + // FIXME Sequences not treated yet ! + // + // Ne faudrait-il pas au contraire trouver immediatement + // une maniere 'propre' de traiter les sequences (vr = SQ) + // car commencer par les ignorer risque de conduire a qq chose + // qui pourrait ne pas etre generalisable + // Well, I'm expecting your code !!! + + // the test was commented out to 'go inside' the SeQuences + // we don't any longer skip them ! + + // if( vr == "SQ" ) + // SkipLoad = true; - if (type == ImplicitVR) { - std::string implicitVRTransfertSyntax = "1.2.840.10008.1.2"; - ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010); - - //FIXME Refer to standards on page 21, chapter 6.2 "Value representation": - // 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 - - PubElValSet.SetElValueLengthByNumber(18, 0x0002, 0x0010); - } + // A SeQuence "contains" a set of Elements. + // (fffe e000) tells us an Element is beginning + // (fffe e00d) tells us an Element just ended + // (fffe e0dd) tells us the current SeQuence just ended + if( group == 0xfffe ) + SkipLoad = true; - if (type == ExplicitVR) { - std::string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1"; - ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010); - - //FIXME Refer to standards on page 21, chapter 6.2 "Value representation": - // 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 - - PubElValSet.SetElValueLengthByNumber(20, 0x0002, 0x0010); + if ( SkipLoad ) { + ElVal->SetLength(0); + ElVal->SetValue("gdcm::Skipped"); + return; } - return PubElValSet.Write(fp, type); -} - -// -// ------------------------ 'non string' elements related functions -// + // When the length is zero things are easy: + if ( length == 0 ) { + ElVal->SetValue(""); + return; + } -/** - * \ingroup gdcmHeader - * \brief Loads (from disk) the element content - * when a string is not suitable - */ -void * gdcmHeader::LoadElementVoidArea(guint16 Group, guint16 Elem) { - gdcmElValue * Element= PubElValSet.GetElementByNumber(Group, Elem); - if ( !Element ) - return NULL; - size_t o =(size_t)Element->GetOffset(); - fseek(fp, o, SEEK_SET); - int l=Element->GetLength(); - void * a = malloc(l); - if(!a) { - return NULL; - } - /* int res = */ PubElValSet.SetVoidAreaByNumber(a, Group, Elem); - // TODO check the result - size_t l2 = fread(a, 1, l ,fp); - if(l != l2) { - free(a); - return NULL; + // The elements whose length is bigger than the specified upper bound + // are not loaded. Instead we leave a short notice of the offset of + // the element content and it's length. + if (length > MaxSizeLoadElementValue) { + std::ostringstream s; + s << "gdcm::NotLoaded."; + s << " Address:" << (long)ElVal->GetOffset(); + s << " Length:" << ElVal->GetLength(); + s << " x(" << std::hex << ElVal->GetLength() << ")"; + ElVal->SetValue(s.str()); + return; } - return a; + + // When an integer is expected, read and convert the following two or + // four bytes properly i.e. as an integer as opposed to a string. + + // Actually, elements with Value Multiplicity > 1 + // contain a set of integers (not a single one) + // Any compacter code suggested (?) + if ( IsAnInteger(ElVal) ) { + guint32 NewInt; + std::ostringstream s; + int nbInt; + if (vr == "US" || vr == "SS") { + nbInt = length / 2; + NewInt = ReadInt16(); + s << NewInt; + if (nbInt > 1) { + for (int i=1; i < nbInt; i++) { + s << '\\'; + NewInt = ReadInt16(); + s << NewInt; + } + } + + } else if (vr == "UL" || vr == "SL") { + nbInt = length / 4; + NewInt = ReadInt32(); + s << NewInt; + if (nbInt > 1) { + for (int i=1; i < nbInt; i++) { + s << '\\'; + NewInt = ReadInt32(); + s << NewInt; + } + } + } +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + ElVal->SetValue(s.str()); + return; + } + + // We need an additional byte for storing \0 that is not on disk + char* NewValue = (char*)malloc(length+1); + if( !NewValue) { + dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue"); + return; + } + NewValue[length]= 0; + + item_read = fread(NewValue, (size_t)length, (size_t)1, fp); + if ( item_read != 1 ) { + free(NewValue); + dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value"); + ElVal->SetValue("gdcm::UnRead"); + return; + } + ElVal->SetValue(NewValue); + free(NewValue); } /** - * \ingroup gdcmHeader - * \brief Gets (from Header) the offset of a 'non string' element value - * \ (LoadElementValue has already be executed) - * @param Group - * @param Elem - * @return File Offset of the Element Value + * \ingroup gdcmHeader + * \brief Loads the element while preserving the current + * underlying file position indicator as opposed to + * to LoadElementValue that modifies it. + * @param ElVal Element whose value shall be loaded. + * @return */ - size_t gdcmHeader::GetPubElValOffsetByNumber(guint16 Group, guint16 Elem) { - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); - return (size_t)0; - } - return elValue->GetOffset(); +void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { + long PositionOnEntry = ftell(fp); + LoadElementValue(ElVal); + fseek(fp, PositionOnEntry, SEEK_SET); } /** * \ingroup gdcmHeader -* \brief Gets (from Header) a 'non string' element value - * \ (LoadElementValue has already be executed) - * @param Group - * @param Elem - * @return Pointer to the 'non string' area - + * \brief + * + * @return */ - void * gdcmHeader::GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem) { - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); - return (NULL); - } - return elValue->GetVoidArea(); -} - - -// -// ============================================================================= -// Heuristics based accessors -//============================================================================== -// - -// TODO : move to an other file. + void gdcmHeader::FindLength (gdcmElValue * ElVal) { + guint16 element = ElVal->GetElement(); + guint16 group = ElVal->GetGroup(); + std::string vr = ElVal->GetVR(); + guint16 length16; + if( (element == 0x0010) && (group == 0x7fe0) ) { + dbg.SetDebug(-1); + dbg.Verbose(2, "gdcmHeader::FindLength: ", + "we reached 7fe0 0010"); + } + + if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) { + if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) { + + // The following reserved two bytes (see PS 3.5-2001, section + // 7.1.2 Data element structure with explicit vr p27) must be + // skipped before proceeding on reading the length on 4 bytes. + fseek(fp, 2L, SEEK_CUR); + guint32 length32 = ReadInt32(); -/** - * \ingroup gdcmHeader - * \brief Retrieve the number of columns of image. - * @return The encountered size when found, 0 by default. - */ -int gdcmHeader::GetXSize(void) { - // We cannot check for "Columns" because the "Columns" tag is present - // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary. - std::string StrSize = GetPubElValByNumber(0x0028,0x0011); - if (StrSize == GDCM_UNFOUND) - return 0; - return atoi(StrSize.c_str()); -} + if ( (vr == "OB") && (length32 == 0xffffffff) ) { + ElVal->SetLength(FindLengthOB()); + return; + } + FixFoundLength(ElVal, length32); + return; + } -/** - * \ingroup gdcmHeader - * \brief Retrieve the number of lines of image. - * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize() - * @return The encountered size when found, 1 by default. - */ -int gdcmHeader::GetYSize(void) { - // We cannot check for "Rows" because the "Rows" tag is present - // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary. - std::string StrSize = GetPubElValByNumber(0x0028,0x0010); - if (StrSize != GDCM_UNFOUND) - return atoi(StrSize.c_str()); - if ( IsDicomV3() ) - return 0; - else - // The Rows (0028,0010) entry is optional for ACR/NEMA. It might - // hence be a signal (1d image). So we default to 1: - return 1; + // Length is encoded on 2 bytes. + length16 = ReadInt16(); + + // We can tell the current file is encoded in big endian (like + // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag + // and it's value is the one of the encoding of a big endian file. + // In order to deal with such big endian encoded files, we have + // (at least) two strategies: + // * when we load the "Transfer Syntax" tag with value of big endian + // encoding, we raise the proper flags. Then we wait for the end + // of the META group (0x0002) among which is "Transfer Syntax", + // before switching the swap code to big endian. We have to postpone + // the switching of the swap code since the META group is fully encoded + // in little endian, and big endian coding only starts at the next + // group. The corresponding code can be hard to analyse and adds + // many additional unnecessary tests for regular tags. + // * the second strategy consists in waiting for trouble, that shall + // appear when we find the first group with big endian encoding. This + // is easy to detect since the length of a "Group Length" tag (the + // ones with zero as element number) has to be of 4 (0x0004). When we + // encounter 1024 (0x0400) chances are the encoding changed and we + // found a group with big endian encoding. + // We shall use this second strategy. In order to make sure that we + // can interpret the presence of an apparently big endian encoded + // length of a "Group Length" without committing a big mistake, we + // add an additional check: we look in the already parsed elements + // for the presence of a "Transfer Syntax" whose value has to be "big + // endian encoding". When this is the case, chances are we have got our + // hands on a big endian encoded file: we switch the swap code to + // big endian and proceed... + if ( (element == 0x0000) && (length16 == 0x0400) ) { + if ( ! IsExplicitVRBigEndianTransferSyntax() ) { + dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR"); + errno = 1; + return; + } + length16 = 4; + SwitchSwapToBigEndian(); + // Restore the unproperly loaded values i.e. the group, the element + // and the dictionary entry depending on them. + guint16 CorrectGroup = SwapShort(ElVal->GetGroup()); + guint16 CorrectElem = SwapShort(ElVal->GetElement()); + gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup, + CorrectElem); + if (!NewTag) { + // This correct tag is not in the dictionary. Create a new one. + NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem); + } + // FIXME this can create a memory leaks on the old entry that be + // left unreferenced. + ElVal->SetDictEntry(NewTag); + } + + // Heuristic: well some files are really ill-formed. + if ( length16 == 0xffff) { + length16 = 0; + //dbg.Verbose(0, "gdcmHeader::FindLength", + // "Erroneous element length fixed."); + // Actually, length= 0xffff means that we deal with + // Unknown Sequence Length + } + + FixFoundLength(ElVal, (guint32)length16); + return; + } + + // Either implicit VR or a non DICOM conformal (see not below) explicit + // VR that ommited the VR of (at least) this element. Farts happen. + // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25 + // on Data elements "Implicit and Explicit VR Data Elements shall + // not coexist in a Data Set and Data Sets nested within it".] + // Length is on 4 bytes. + FixFoundLength(ElVal, ReadInt32()); + return; } /** - * \ingroup gdcmHeader - * \brief Retrieve the number of planes of volume or the number - * of frames of a multiframe. - * \warning When present we consider the "Number of Frames" as the third - * dimension. When absent we consider the third dimension as - * being the "Planes" tag content. - * @return The encountered size when found, 1 by default. + * \ingroup gdcmHeader + * \brief Find the value representation of the current tag. + * @param ElVal */ -int gdcmHeader::GetZSize(void) { - // Both DicomV3 and ACR/Nema consider the "Number of Frames" - // as the third dimension. - std::string StrSize = GetPubElValByNumber(0x0028,0x0008); - if (StrSize != GDCM_UNFOUND) - return atoi(StrSize.c_str()); +void gdcmHeader::FindVR( gdcmElValue *ElVal) { + if (filetype != ExplicitVR) + return; - // We then consider the "Planes" entry as the third dimension [we - // cannot retrieve by name since "Planes tag is present both in - // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. - StrSize = GetPubElValByNumber(0x0028,0x0012); - if (StrSize != GDCM_UNFOUND) - return atoi(StrSize.c_str()); - return 1; + char VR[3]; + std::string vr; + int lgrLue; + char msg[100]; // for sprintf. Sorry + + long PositionOnEntry = ftell(fp); + // Warning: we believe this is explicit VR (Value Representation) because + // we used a heuristic that found "UL" in the first tag. Alas this + // doesn't guarantee that all the tags will be in explicit VR. In some + // cases (see e-film filtered files) one finds implicit VR tags mixed + // within an explicit VR file. Hence we make sure the present tag + // is in explicit VR and try to fix things if it happens not to be + // the case. + bool RealExplicit = true; + + lgrLue=fread (&VR, (size_t)2,(size_t)1, fp); + VR[2]=0; + vr = std::string(VR); + + // Assume we are reading a falsely explicit VR file i.e. we reached + // a tag where we expect reading a VR but are in fact we read the + // first to bytes of the length. Then we will interogate (through find) + // the dicom_vr dictionary with oddities like "\004\0" which crashes + // both GCC and VC++ implementations of the STL map. Hence when the + // expected VR read happens to be non-ascii characters we consider + // we hit falsely explicit VR tag. + + if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) ) + RealExplicit = false; + + // CLEANME searching the dicom_vr at each occurence is expensive. + // PostPone this test in an optional integrity check at the end + // of parsing or only in debug mode. + if ( RealExplicit && !dicom_vr->Count(vr) ) + RealExplicit= false; + + if ( RealExplicit ) { + if ( ElVal->IsVRUnknown() ) { + // When not a dictionary entry, we can safely overwrite the vr. + ElVal->SetVR(vr); + return; + } + if ( ElVal->GetVR() == vr ) { + // The vr we just read and the dictionary agree. Nothing to do. + return; + } + // The vr present in the file and the dictionary disagree. We assume + // the file writer knew best and use the vr of the file. Since it would + // be unwise to overwrite the vr of a dictionary (since it would + // compromise it's next user), we need to clone the actual DictEntry + // and change the vr for the read one. + gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(), + ElVal->GetElement(), + vr, + "FIXME", + ElVal->GetName()); + ElVal->SetDictEntry(NewTag); + return; + } + + // We thought this was explicit VR, but we end up with an + // implicit VR tag. Let's backtrack. + + sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", + ElVal->GetGroup(),ElVal->GetElement()); + dbg.Verbose(1, "gdcmHeader::FindVR: ",msg); + + fseek(fp, PositionOnEntry, SEEK_SET); + // When this element is known in the dictionary we shall use, e.g. for + // the semantics (see the usage of IsAnInteger), the vr proposed by the + // dictionary entry. Still we have to flag the element as implicit since + // we know now our assumption on expliciteness is not furfilled. + // avoid . + if ( ElVal->IsVRUnknown() ) + ElVal->SetVR("Implicit"); + ElVal->SetImplicitVr(); } /** * \ingroup gdcmHeader - * \brief Retrieve the number of Bits Stored - * (as opposite to number of Bits Allocated) - * - * @return The encountered number of Bits Stored, 0 by default. + * \brief + * + * @return */ -int gdcmHeader::GetBitsStored(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0101); - if (StrSize == GDCM_UNFOUND) - return 1; - return atoi(StrSize.c_str()); + guint32 gdcmHeader::FindLengthOB(void) { + // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + guint16 g; + guint16 n; + long PositionOnEntry = ftell(fp); + bool FoundSequenceDelimiter = false; + guint32 TotalLength = 0; + guint32 ItemLength; + + while ( ! FoundSequenceDelimiter) { + g = ReadInt16(); + n = ReadInt16(); + if (errno == 1) + return 0; + TotalLength += 4; // We even have to decount the group and element + + if ( g != 0xfffe && g!=0xb00c ) /*for bogus header */ { + char msg[100]; // for sprintf. Sorry + sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n); + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); + errno = 1; + return 0; + } + if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header */ + FoundSequenceDelimiter = true; + else if ( n != 0xe000 ){ + char msg[100]; // for sprintf. Sorry + sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n", + n, g,n); + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); + errno = 1; + return 0; + } + ItemLength = ReadInt32(); + TotalLength += ItemLength + 4; // We add 4 bytes since we just read + // the ItemLength with ReadInt32 + SkipBytes(ItemLength); + } + fseek(fp, PositionOnEntry, SEEK_SET); + return TotalLength; } /** * \ingroup gdcmHeader - * \brief Retrieve the number of Bits Allocated - * (8, 12 -compacted ACR-NEMA files, 16, ...) - * - * @return The encountered number of Bits Allocated, 0 by default. + * \brief + * @param ElVal + * @return */ -int gdcmHeader::GetBitsAllocated(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0100); - if (StrSize == GDCM_UNFOUND) - return 1; - return atoi(StrSize.c_str()); +void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) { + SkipBytes(ElVal->GetLength()); } /** * \ingroup gdcmHeader - * \brief Retrieve the number of Samples Per Pixel - * (1 : gray level, 3 : RGB -1 or 3 Planes-) - * - * @return The encountered number of Samples Per Pixel, 1 by default. - */ -int gdcmHeader::GetSamplesPerPixel(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0002); - if (StrSize == GDCM_UNFOUND) - return 1; // Well, it's supposed to be mandatory ... - return atoi(StrSize.c_str()); + * \brief When the length of an element value is obviously wrong (because + * the parser went Jabberwocky) one can hope improving things by + * applying this heuristic. + */ +void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) { + + ElVal->SetReadLength(FoundLength); // will be updated only if a bug is found + + if ( FoundLength == 0xffffffff) { + FoundLength = 0; + } + + // Sorry for the patch! + // XMedCom did the trick to read some nasty GE images ... + else if (FoundLength == 13) { + // The following 'if' will be removed when there is no more + // images on Creatis HDs with a 13 length for Manufacturer... + if ( (ElVal->GetGroup() != 0x0008) || + ( (ElVal->GetElement() != 0x0070) && (ElVal->GetElement() != 0x0080) ) ) { + // end of remove area + FoundLength =10; + ElVal->SetReadLength(10); // a bug is to be fixed + } + } + // to fix some garbage 'Leonardo' Siemens images + // May be commented out to avoid overhead + else if ( (ElVal->GetGroup() == 0x0009) && + ( (ElVal->GetElement() == 0x1113) || (ElVal->GetElement() == 0x1114) ) ){ + FoundLength =4; + ElVal->SetReadLength(4); // a bug is to be fixed + } + // end of fix + + // to try to 'go inside' SeQuences (with length), and not to skip them + else if ( ElVal->GetVR() == "SQ") { + if (enableSequences) // only if the user does want to ! + FoundLength =0; + } + + ElVal->SetUsableLength(FoundLength); } /** * \ingroup gdcmHeader - * \brief Retrieve the Planar Configuration for RGB images - * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane) - * - * @return The encountered Planar Configuration, 0 by default. + * \brief Apply some heuristics to predict wether the considered + * element value contains/represents an integer or not. + * @param ElVal The element value on which to apply the predicate. + * @return The result of the heuristical predicate. */ -int gdcmHeader::GetPlanarConfiguration(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0006); - if (StrSize == GDCM_UNFOUND) - return 0; - return atoi(StrSize.c_str()); +bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) { + guint16 element = ElVal->GetElement(); + guint16 group = ElVal->GetGroup(); + std::string vr = ElVal->GetVR(); + guint32 length = ElVal->GetLength(); + + // When we have some semantics on the element we just read, and if we + // a priori know we are dealing with an integer, then we shall be + // able to swap it's element value properly. + if ( element == 0 ) { // This is the group length of the group + if (length == 4) + return true; + else { + std::ostringstream s; + s << "Erroneous Group Length element length on :" \ + << std::hex << group << " , " << element; + dbg.Error("gdcmHeader::IsAnInteger", + s.str().c_str()); + } + } + if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") ) + return true; + + return false; } /** * \ingroup gdcmHeader - * \brief Return the size (in bytes) of a single pixel of data. - * @return The size in bytes of a single pixel of data. + * \brief Reads a supposed to be 16 Bits integer + * \ (swaps it depending on processor endianity) * + * @return integer acts as a boolean */ -int gdcmHeader::GetPixelSize(void) { - std::string PixelType = GetPixelType(); - if (PixelType == "8U" || PixelType == "8S") - return 1; - if (PixelType == "16U" || PixelType == "16S") - return 2; - if (PixelType == "32U" || PixelType == "32S") - return 4; - dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type"); - return 0; +guint16 gdcmHeader::ReadInt16(void) { + guint16 g; + size_t item_read; + item_read = fread (&g, (size_t)2,(size_t)1, fp); + if ( item_read != 1 ) { + // dbg.Verbose(0, "gdcmHeader::ReadInt16", " Failed to read :"); + // if(feof(fp)) + // dbg.Verbose(0, "gdcmHeader::ReadInt16", " End of File encountered"); + if(ferror(fp)) + dbg.Verbose(0, "gdcmHeader::ReadInt16", " File Error"); + errno = 1; + return 0; + } + errno = 0; + g = SwapShort(g); + return g; } /** * \ingroup gdcmHeader - * \brief Build the Pixel Type of the image. - * Possible values are: - * - 8U unsigned 8 bit, - * - 8S signed 8 bit, - * - 16U unsigned 16 bit, - * - 16S signed 16 bit, - * - 32U unsigned 32 bit, - * - 32S signed 32 bit, - * \warning 12 bit images appear as 16 bit. - * \ 24 bit images appear as 8 bit - * @return + * \brief Reads a supposed to be 32 Bits integer + * \ (swaps it depending on processor endianity) + * + * @return */ -std::string gdcmHeader::GetPixelType(void) { - std::string BitsAlloc; - BitsAlloc = GetPubElValByNumber(0x0028, 0x0100); // Bits Allocated - if (BitsAlloc == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); - BitsAlloc = std::string("16"); - } - if (BitsAlloc == "12") // It will be unpacked - BitsAlloc = std::string("16"); - else if (BitsAlloc == "24") // (in order no to be messed up - BitsAlloc = std::string("8"); // by old RGB images) - - std::string Signed; - Signed = GetPubElValByNumber(0x0028, 0x0103); // "Pixel Representation" - if (Signed == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation"); - BitsAlloc = std::string("0"); - } - if (Signed == "0") - Signed = std::string("U"); - else - Signed = std::string("S"); - - return( BitsAlloc + Signed); -} - -/** - * \ingroup gdcmHeader - * \brief gets the info from 0002,0010 : Transfert Syntax - * \ else 1. - * @return Transfert Syntax Name (as oposite to Transfert Syntax UID) - */ -std::string gdcmHeader::GetTransferSyntaxName(void) { - std::string TransfertSyntax = GetPubElValByNumber(0x0002,0x0010); - if (TransfertSyntax == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetTransferSyntaxName: unfound Transfert Syntax (0002,0010)"); - return "Uncompressed ACR-NEMA"; +guint32 gdcmHeader::ReadInt32(void) { + guint32 g; + size_t item_read; + item_read = fread (&g, (size_t)4,(size_t)1, fp); + if ( item_read != 1 ) { + //dbg.Verbose(0, "gdcmHeader::ReadInt32", " Failed to read :"); + //if(feof(fp)) + // dbg.Verbose(0, "gdcmHeader::ReadInt32", " End of File encountered"); + if(ferror(fp)) + dbg.Verbose(0, "gdcmHeader::ReadInt32", " File Error"); + errno = 1; + return 0; } - // we do it only when we need it - gdcmTS * ts = gdcmGlobal::GetTS(); - std::string tsName=ts->GetValue(TransfertSyntax); - //delete ts; // Seg Fault when deleted ?! - return tsName; + errno = 0; + g = SwapLong(g); + return g; } -// -------------------------------- Lookup Table related functions ------------ - /** - * \ingroup gdcmHeader - * \brief tells us if LUT are used - * \warning Right now, Segmented xxx Palette Color Lookup Table Data - * \ are NOT considered as LUT, since nobody knows - *\ how to deal with them - * @return int acts as a Boolean - */ - -bool gdcmHeader::HasLUT(void) { - - // Check the presence of the LUT Descriptors - if (GetPubElValByNumber(0x0028,0x1101) == GDCM_UNFOUND) - return false; - // LutDescriptorGreen - if (GetPubElValByNumber(0x0028,0x1102) == GDCM_UNFOUND) - return false; - // LutDescriptorBlue - if (GetPubElValByNumber(0x0028,0x1103) == GDCM_UNFOUND) - return false; - // It is not enough - // we check also - if (GetPubElValByNumber(0x0028,0x1201) == GDCM_UNFOUND) - return false; - if (GetPubElValByNumber(0x0028,0x1202) == GDCM_UNFOUND) - return false; - if (GetPubElValByNumber(0x0028,0x1203) == GDCM_UNFOUND) - return false; - return true; + * \ingroup gdcmHeader + * \brief + * + * @return + */ +void gdcmHeader::SkipBytes(guint32 NBytes) { + //FIXME don't dump the returned value + (void)fseek(fp, (long)NBytes, SEEK_CUR); } /** - * \ingroup gdcmHeader - * \brief gets the info from 0028,1101 : Lookup Table Desc-Red - * \ else 0 - * @return Lookup Table nBit - * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] - */ - -int gdcmHeader::GetLUTNbits(void) { - std::vector tokens; - //int LutLength; - //int LutDepth; - int LutNbits; - //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue - // Consistency already checked in GetLUTLength - std::string LutDescription = GetPubElValByNumber(0x0028,0x1101); - if (LutDescription == GDCM_UNFOUND) - return 0; - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (LutDescription, tokens, "\\"); - //LutLength=atoi(tokens[0].c_str()); - //LutDepth=atoi(tokens[1].c_str()); - LutNbits=atoi(tokens[2].c_str()); - tokens.clear(); - return LutNbits; + * \ingroup gdcmHeader + * \brief + */ +void gdcmHeader::Initialise(void) { + dicom_vr = gdcmGlobal::GetVR(); + dicom_ts = gdcmGlobal::GetTS(); + Dicts = gdcmGlobal::GetDicts(); + RefPubDict = Dicts->GetDefaultPubDict(); + RefShaDict = (gdcmDict*)0; } /** - * \ingroup gdcmHeader - * \brief builts Red/Green/Blue/Alpha LUT from Header - * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] - * \ and (0028,1101),(0028,1102),(0028,1102) - * \ - xxx Palette Color Lookup Table Descriptor - are found - * \ and (0028,1201),(0028,1202),(0028,1202) - * \ - xxx Palette Color Lookup Table Data - are found - * \warning does NOT deal with : - * \ 0028 1100 Gray Lookup Table Descriptor (Retired) - * \ 0028 1221 Segmented Red Palette Color Lookup Table Data - * \ 0028 1222 Segmented Green Palette Color Lookup Table Data - * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data - * \ no known Dicom reader deails with them :-( - * @return Lookup Table RGBA - */ - -unsigned char * gdcmHeader::GetLUTRGBA(void) { -// Not so easy : see -// http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables -// and OT-PAL-8-face.dcm - -// if Photometric Interpretation # PALETTE COLOR, no LUT to be done - - if (gdcmHeader::GetPubElValByNumber(0x0028,0x0004) != "PALETTE COLOR ") { - return NULL; - } + * \ingroup gdcmHeader + * \brief Discover what the swap code is (among little endian, big endian, + * bad little endian, bad big endian). + * + */ +void gdcmHeader::CheckSwap() +{ + // Fourth semantics: + // + // ---> Warning : This fourth field is NOT part + // of the 'official' Dicom Dictionnary + // and should NOT be used. + // (Not defined for all the groups + // may be removed in a future release) + // + // CMD Command + // META Meta Information + // DIR Directory + // ID + // PAT Patient + // ACQ Acquisition + // REL Related + // IMG Image + // SDY Study + // VIS Visit + // WAV Waveform + // PRC + // DEV Device + // NMI Nuclear Medicine + // MED + // BFS Basic Film Session + // BFB Basic Film Box + // BIB Basic Image Box + // BAB + // IOB + // PJ + // PRINTER + // RT Radio Therapy + // DVH + // SSET + // RES Results + // CRV Curve + // OLY Overlays + // PXL Pixels + // DL Delimiters + // - int lengthR, debR, nbitsR; - int lengthG, debG, nbitsG; - int lengthB, debB, nbitsB; - -// Get info from Lut Descriptors -// (the 3 LUT descriptors may be different) + // The only guaranted way of finding the swap code is to find a + // group tag since we know it's length has to be of four bytes i.e. + // 0x00000004. Finding the swap code in then straigthforward. Trouble + // occurs when we can't find such group... + guint32 s; + guint32 x=4; // x : for ntohs + bool net2host; // true when HostByteOrder is the same as NetworkByteOrder + + int lgrLue; + char * entCur; + char deb[HEADER_LENGTH_TO_READ]; + + // First, compare HostByteOrder and NetworkByteOrder in order to + // determine if we shall need to swap bytes (i.e. the Endian type). + if (x==ntohs(x)) + net2host = true; + else + net2host = false; + //cout << net2host << endl; + + // The easiest case is the one of a DICOM header, since it possesses a + // file preamble where it suffice to look for the string "DICM". + lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp); - std::string LutDescriptionR = GetPubElValByNumber(0x0028,0x1101); - if (LutDescriptionR == GDCM_UNFOUND) - return NULL; - std::string LutDescriptionG = GetPubElValByNumber(0x0028,0x1102); - if (LutDescriptionG == GDCM_UNFOUND) - return NULL; - std::string LutDescriptionB = GetPubElValByNumber(0x0028,0x1103); - if (LutDescriptionB == GDCM_UNFOUND) - return NULL; - - std::vector tokens; + entCur = deb + 128; + if(memcmp(entCur, "DICM", (size_t)4) == 0) { + dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3"); + // Next, determine the value representation (VR). Let's skip to the + // first element (0002, 0000) and check there if we find "UL" + // - or "OB" if the 1st one is (0002,0001) -, + // in which case we (almost) know it is explicit VR. + // WARNING: if it happens to be implicit VR then what we will read + // is the length of the group. If this ascii representation of this + // length happens to be "UL" then we shall believe it is explicit VR. + // FIXME: in order to fix the above warning, we could read the next + // element value (or a couple of elements values) in order to make + // sure we are not commiting a big mistake. + // We need to skip : + // * the 128 bytes of File Preamble (often padded with zeroes), + // * the 4 bytes of "DICM" string, + // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001) + // i.e. a total of 136 bytes. + entCur = deb + 136; + // FIXME + // Use gdcmHeader::dicom_vr to test all the possibilities + // instead of just checking for UL, OB and UI !? + if( (memcmp(entCur, "UL", (size_t)2) == 0) || + (memcmp(entCur, "OB", (size_t)2) == 0) || + (memcmp(entCur, "UI", (size_t)2) == 0) ) + { + filetype = ExplicitVR; + dbg.Verbose(1, "gdcmHeader::CheckSwap:", + "explicit Value Representation"); + } else { + filetype = ImplicitVR; + dbg.Verbose(1, "gdcmHeader::CheckSwap:", + "not an explicit Value Representation"); + } + if (net2host) { + sw = 4321; + dbg.Verbose(1, "gdcmHeader::CheckSwap:", + "HostByteOrder != NetworkByteOrder"); + } else { + sw = 0; + dbg.Verbose(1, "gdcmHeader::CheckSwap:", + "HostByteOrder = NetworkByteOrder"); + } - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (LutDescriptionR, tokens, "\\"); - lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes - debR =atoi(tokens[1].c_str()); // subscript of the first Lut Value - nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits) - tokens.clear(); - - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (LutDescriptionG, tokens, "\\"); - lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes - debG =atoi(tokens[1].c_str()); - nbitsG =atoi(tokens[2].c_str()); - tokens.clear(); - - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (LutDescriptionB, tokens, "\\"); - lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes - debB =atoi(tokens[1].c_str()); - nbitsB =atoi(tokens[2].c_str()); - tokens.clear(); - -// Load LUTs into memory, (as they were stored on disk) - - unsigned char *lutR =(unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1201); - unsigned char *lutG =(unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1202); - unsigned char *lutB =(unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1203); - - if (!lutR || !lutG || !lutB ) { - return NULL; - } - // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT + // Position the file position indicator at first tag (i.e. + // after the file preamble and the "DICM" string). + rewind(fp); + fseek (fp, 132L, SEEK_SET); + return; + } // End of DicomV3 + + // Alas, this is not a DicomV3 file and whatever happens there is no file + // preamble. We can reset the file position indicator to where the data + // is (i.e. the beginning of the file). + dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file"); + rewind(fp); + + // Our next best chance would be to be considering a 'clean' ACR/NEMA file. + // By clean we mean that the length of the first tag is written down. + // If this is the case and since the length of the first group HAS to be + // four (bytes), then determining the proper swap code is straightforward. + + entCur = deb + 4; + // We assume the array of char we are considering contains the binary + // representation of a 32 bits integer. Hence the following dirty + // trick : + s = *((guint32 *)(entCur)); - unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) - if (!LUTRGBA) { - return NULL; - } - memset(LUTRGBA, 0, 1024); - // Bits Allocated - int nb; - std::string str_nb = GetPubElValByNumber(0x0028,0x0100); - if (str_nb == GDCM_UNFOUND ) { - nb = 16; - } else { - nb = atoi(str_nb.c_str() ); - } - int mult; - - if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size - mult=2; // high byte must be = low byte - else // See PS 3.3-2003 C.11.1.1.2 p 619 - mult=1; - - // if we get a black image, let's just remove the '+1' - // from 'i*mult+1' and check again - // if it works, we shall have to check the 3 Palettes - // to see which byte is ==0 (first one, or second one) - // and fix the code - // We give up the checking to avoid some overhead - - unsigned char *a; - int i; - a= LUTRGBA+0; - for(i=0;i not-for-rats function - * - * \warning WARNING doit-etre etre publique ? - * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions - * - * @param ImageDataSize new Pixel Area Size - * warning : nothing else is checked + * \ingroup gdcmHeader + * \brief + * @param NewSize + * @return */ +void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) { + if (NewSize < 0) + return; + if ((guint32)NewSize >= (guint32)0xffffffff) { + MaxSizeLoadElementValue = 0xffffffff; + return; + } + MaxSizeLoadElementValue = NewSize; +} -void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { - std::string content1; - char car[20]; - // Assumes ElValue (0x7fe0, 0x0010) exists ... - sprintf(car,"%d",ImageDataSize); - - gdcmElValue *a = GetElValueByNumber(0x7fe0, 0x0010); - a->SetLength(ImageDataSize); - - ImageDataSize+=8; - sprintf(car,"%d",ImageDataSize); - content1=car; - SetPubElValByNumber(content1, 0x7fe0, 0x0000); +/** + * \ingroup gdcmHeader + * \brief Searches both the public and the shadow dictionary (when they + * exist) for the presence of the DictEntry with given + * group and element. The public dictionary has precedence on the + * shadow one. + * @param group group of the searched DictEntry + * @param element element of the searched DictEntry + * @return Corresponding DictEntry when it exists, NULL otherwise. + */ +gdcmDictEntry * gdcmHeader::GetDictEntryByNumber(guint16 group, + guint16 element) { + gdcmDictEntry * found = (gdcmDictEntry*)0; + if (!RefPubDict && !RefShaDict) { + dbg.Verbose(0, "gdcmHeader::GetDictEntry", + "we SHOULD have a default dictionary"); + } + if (RefPubDict) { + found = RefPubDict->GetTagByNumber(group, element); + if (found) + return found; + } + if (RefShaDict) { + found = RefShaDict->GetTagByNumber(group, element); + if (found) + return found; + } + return found; } +/** + * \ingroup gdcmHeader + * \brief Searches both the public and the shadow dictionary (when they + * exist) for the presence of the DictEntry with given name. + * The public dictionary has precedence on the shadow one. + * @param Name name of the searched DictEntry + * @return Corresponding DictEntry when it exists, NULL otherwise. + */ +gdcmDictEntry * gdcmHeader::GetDictEntryByName(std::string Name) { + gdcmDictEntry * found = (gdcmDictEntry*)0; + if (!RefPubDict && !RefShaDict) { + dbg.Verbose(0, "gdcmHeader::GetDictEntry", + "we SHOULD have a default dictionary"); + } + if (RefPubDict) { + found = RefPubDict->GetTagByName(Name); + if (found) + return found; + } + if (RefShaDict) { + found = RefShaDict->GetTagByName(Name); + if (found) + return found; + } + return found; +} +/** + * \ingroup gdcmHeader + * \brief Read the next tag but WITHOUT loading it's value + * @return On succes the newly created ElValue, NULL on failure. + */ +gdcmElValue * gdcmHeader::ReadNextElement(void) { + + guint16 g,n; + gdcmElValue * NewElVal; + + g = ReadInt16(); + n = ReadInt16(); + + if (errno == 1) + // We reached the EOF (or an error occured) and header parsing + // has to be considered as finished. + return (gdcmElValue *)0; + + NewElVal = NewElValueByNumber(g, n); + FindVR(NewElVal); + FindLength(NewElVal); + + if (errno == 1) { + // Call it quits + return (gdcmElValue *)0; + } + NewElVal->SetOffset(ftell(fp)); + //if ( (g==0x7fe0) && (n==0x0010) ) + return NewElVal; +} +/** + * \ingroup gdcmHeader + * \brief Build a new Element Value from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param Name Name of the underlying DictEntry + */ +gdcmElValue* gdcmHeader::NewElValueByName(std::string Name) { + gdcmDictEntry * NewTag = GetDictEntryByName(Name); + if (!NewTag) + NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); + gdcmElValue* NewElVal = new gdcmElValue(NewTag); + if (!NewElVal) { + dbg.Verbose(1, "gdcmHeader::ObtainElValueByName", + "failed to allocate gdcmElValue"); + return (gdcmElValue*)0; + } + return NewElVal; +} +/** + * \ingroup gdcmHeader + * \brief Build a new Element Value from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param Group group of the underlying DictEntry + * @param Elem element of the underlying DictEntry + */ +gdcmElValue* gdcmHeader::NewElValueByNumber(guint16 Group, guint16 Elem) { + // Find out if the tag we encountered is in the dictionaries: + gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem); + if (!NewTag) + NewTag = new gdcmDictEntry(Group, Elem); + gdcmElValue* NewElVal = new gdcmElValue(NewTag); + if (!NewElVal) { + dbg.Verbose(1, "gdcmHeader::NewElValueByNumber", + "failed to allocate gdcmElValue"); + return (gdcmElValue*)0; + } + return NewElVal; +} /** * \ingroup gdcmHeader @@ -2352,58 +2337,34 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { dictEntry->GetElement())); } - - /** - * \ingroup gdcmElValSet - * \brief Sets the value (string) of the target Dicom Element - * @param content string value of the Dicom Element - * @param tagName name of the searched Dicom Element. - * @return true when found + * \ingroup gdcmHeader + * \brief Small utility function that creates a new manually crafted + * (as opposed as read from the file) gdcmElValue with user + * specified name and adds it to the public tag hash table. + * \note A fake TagKey is generated so the PubDict can keep it's coherence. + * @param NewTagName The name to be given to this new tag. + * @param VR The Value Representation to be given to this new tag. + * @ return The newly hand crafted Element Value. */ -bool gdcmHeader::SetElValueByName(std::string content, - std::string tagName) { - - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); - if( dictEntry == NULL) - return false; - - - TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), - dictEntry->GetElement()); - if ( ! PubElValSet.GetTagHt().count(key)) - return false; - int l = content.length(); - if(l%2) { // Odd length are padded with a space (020H). - l++; - content = content + '\0'; +gdcmElValue* gdcmHeader::NewManualElValToPubDict(std::string NewTagName, + std::string VR) { + gdcmElValue* NewElVal = (gdcmElValue*)0; + guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info + guint32 FreeElem = 0; + gdcmDictEntry* NewEntry = (gdcmDictEntry*)0; + + FreeElem = PubElValSet.GenerateFreeTagKeyInGroup(StuffGroup); + if (FreeElem == UINT32_MAX) { + dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict", + "Group 0xffff in Public Dict is full"); + return (gdcmElValue*)0; } - - //tagHt[key]->SetValue(content); - gdcmElValue * a; - IterHT p; - TagElValueHT::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 = ((PubElValSet.GetTagHt().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; + NewEntry = new gdcmDictEntry(StuffGroup, FreeElem, + VR, "GDCM", NewTagName); + NewElVal = new gdcmElValue(NewEntry); + PubElValSet.Add(NewElVal); + return NewElVal; } + +//----------------------------------------------------------------------------- diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index dff360a7..23df5390 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -1,5 +1,5 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmHeader.h,v 1.47 2004/01/13 11:32:30 jpr Exp $ - +// gdcmHeader.h +//----------------------------------------------------------------------------- #ifndef GDCMHEADER_H #define GDCMHEADER_H @@ -12,10 +12,12 @@ #include "gdcmElValSet.h" #include +//----------------------------------------------------------------------------- typedef std::string VRKey; typedef std::string VRAtr; typedef std::map VRHT; // Value Representation Hash Table +//----------------------------------------------------------------------------- /* * The purpose of an instance of gdcmHeader is to act as a container of * all the DICOM elements and their corresponding values (and @@ -35,96 +37,16 @@ typedef std::map VRHT; // Value Representation Hash Table * gdcmFile and gdcmHeader. */ class GDCM_EXPORT gdcmHeader { -private: - /// Pointer to the Value Representation Hash Table which contains all - /// the VR of the DICOM version3 public dictionary. - gdcmVR *dicom_vr; // Not a class member for thread-safety reasons - - /// Pointer to the Transfert Syntax Hash Table which contains all - /// the TS of the DICOM version3 public dictionary. - gdcmTS *dicom_ts; // Not a class member for thread-safety reasons - - /// Pointer to global dictionary container - gdcmDictSet *Dicts; // Not a class member for thread-safety reasons - - /// Public dictionary used to parse this header - gdcmDict *RefPubDict; - - /// Optional "shadow dictionary" (private elements) used to parse this - /// header - gdcmDict *RefShaDict; - - /// ELement VALueS parsed with the PUBlic dictionary. - gdcmElValSet PubElValSet; - - /// Refering underlying filename. - std::string filename; - - int enableSequences; - - // FIXME sw should be an enum e.g. - //enum EndianType { - //LittleEndian, - //BadLittleEndian, - //BigEndian, - //BadBigEndian}; - /// 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). - guint32 MaxSizeLoadElementValue; - - guint16 ReadInt16(void); - guint32 ReadInt32(void); - guint32 FindLengthOB(void); - void Initialise(void); - void CheckSwap(void); - void SwitchSwapToBigEndian(void); - // CLEAN ME: NewManualElValToPubDict is NOT called any more. - gdcmElValue *NewManualElValToPubDict(std::string NewTagName, - std::string VR); - void SetMaxSizeLoadElementValue(long); - - gdcmDictEntry *GetDictEntryByNumber(guint16, guint16); - gdcmDictEntry *GetDictEntryByName (std::string Name); - - // ElValue related utilities - gdcmElValue *ReadNextElement(void); - gdcmElValue *NewElValueByNumber(guint16 group, guint16 element); - gdcmElValue *NewElValueByName (std::string Name); - - gdcmElValue* GetElementByName (std::string Name); - // moved from gdcmElValSet - - void FindLength (gdcmElValue *); - void FindVR (gdcmElValue *); - void LoadElementValue (gdcmElValue *); - void LoadElementValueSafe(gdcmElValue *); - void SkipElementValue (gdcmElValue *); - void FixFoundLength (gdcmElValue *, guint32); - bool IsAnInteger (gdcmElValue *); - void LoadElements(void); - void SkipBytes(guint32); - -protected: - FILE * fp; - FileType filetype; // ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown - - gdcmElValue * GetElValueByNumber(guint16 group, guint16 element); - bool CheckIfExistByNumber(guint16 Group, guint16 Elem ); - - int write(std::ostream&); - int anonymize(std::ostream&); // FIXME : anonymize should be a friend ? - public: - FILE *OpenFile(bool exception_on_error = false) - throw(gdcmFileError); - bool CloseFile(void); - FileType GetFileType(void); + gdcmHeader(bool exception_on_error = false); + gdcmHeader(const char *filename, + bool exception_on_error = false, + bool enable_sequences = false); + + virtual ~gdcmHeader(); + +// Standard values and informations contained in the header + inline std::string GetFileName(void) {return filename;} bool IsReadable(void); bool IsImplicitVRLittleEndianTransferSyntax(void); @@ -139,24 +61,29 @@ public: bool IsJPEGLossless(void); bool IsJPEG2000(void); bool IsDicomV3(void); - - virtual void ParseHeader(bool exception_on_error = false) - throw(gdcmFormatError); - - gdcmHeader(bool exception_on_error = false); - gdcmHeader(const char *filename, - bool exception_on_error = false, - bool enable_sequences = false); - - virtual ~gdcmHeader(); + FileType GetFileType(void); - inline std::string GetFileName(void) {return filename;} - + // Some heuristic based accessors, end user intended + // (to be move to gdcmHeaderHelper?) + int GetXSize(void); + int GetYSize(void); + int GetZSize(void); + int GetBitsStored(void); + int GetBitsAllocated(void); + int GetSamplesPerPixel(void); + int GetPlanarConfiguration(void); + + int GetPixelSize(void); + std::string GetPixelType(void); size_t GetPixelOffset(void); size_t GetPixelAreaLength(void); - inline int GetSwapCode(void) { return sw; } - + bool HasLUT(void); + int GetLUTNbits(void); + unsigned char * GetLUTRGBA(void); + + std::string GetTransfertSyntaxName(void); + // When some proprietary shadow groups are disclosed, we can set up // an additional specific dictionary to access extra information. @@ -167,64 +94,150 @@ public: // TODO Swig int SetShaDict(std::string filename); // TODO Swig int SetPubDict(std::string filename); +// Public element value std::string GetPubElValByName (std::string tagName); std::string GetPubElValRepByName (std::string tagName); std::string GetPubElValByNumber (guint16 group, guint16 element); std::string GetPubElValRepByNumber(guint16 group, guint16 element); - size_t GetPubElValOffsetByNumber (guint16 Group, guint16 Elem); - void * GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem); - void * LoadElementVoidArea (guint16 Group, guint16 Element); - - inline ListTag & GetListElem(void) { return PubElValSet.GetListElem();}; - inline TagElValueHT & GetPubElVal(void) { return PubElValSet.GetTagHt(); }; - - void PrintPubElVal(std::ostream & os = std::cout); - void PrintPubDict (std::ostream & os = std::cout); - bool SetPubElValByName (std::string content, std::string tagName); bool SetPubElValByNumber(std::string content, guint16 group, guint16 element); bool SetPubElValLengthByNumber(guint32 lgr, guint16 group, guint16 element); - + + inline ListTag & GetPubListElem(void) { return PubElValSet.GetListElem();}; + inline TagElValueHT & GetPubElVal(void) { return PubElValSet.GetTagHt(); }; + + void PrintPubElVal(std::ostream & os = std::cout); + void PrintPubDict (std::ostream & os = std::cout); + +// Element value std::string GetElValByName (std::string tagName); std::string GetElValRepByName (std::string tagName); std::string GetElValByNumber (guint16 group, guint16 element); - std::string GetElValRepByNumber(guint16 group, guint16 element); + std::string GetElValRepByNumber(guint16 group, guint16 element); bool SetElValueByName(std::string content,std::string tagName); - // moved from ElValSet - +// bool SetElValueByNumber(std::string content,guint16 group, guint16 element); + +// inline ListTag & GetListElem(void) { return PubElValSet.GetListElem();}; +// inline TagElValueHT & GetElVal(void) { return PubElValSet.GetTagHt(); }; + +// Read (used in gdcmFile) + FILE *OpenFile(bool exception_on_error = false) throw(gdcmFileError); + bool CloseFile(void); + virtual void ParseHeader(bool exception_on_error = false) throw(gdcmFormatError); + +// Write (used in gdcmFile) + bool Write(FILE *, FileType); + void SetImageDataSize(size_t ExpectedSize); + +// System access + inline int GetSwapCode(void) { return sw; } + guint16 SwapShort(guint16); // needed by gdcmFile + guint32 SwapLong(guint32); // for JPEG Files + +protected: + gdcmElValue * GetElValueByNumber(guint16 group, guint16 element); + bool CheckIfExistByNumber(guint16 Group, guint16 Elem ); + + int write(std::ostream&); + int anonymize(std::ostream&); // FIXME : anonymize should be a friend ? + + size_t GetPubElValOffsetByNumber (guint16 Group, guint16 Elem); + void * GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem); + void * LoadElementVoidArea (guint16 Group, guint16 Element); + bool ReplaceOrCreateByNumber(std::string Value, guint16 Group, guint16 Elem); bool ReplaceOrCreateByNumber( char * Value, guint16 Group, guint16 Elem); bool ReplaceIfExistByNumber ( char * Value, guint16 Group, guint16 Elem); - - bool Write(FILE *, FileType); + +// Variables + FILE * fp; + FileType filetype; // ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown - // Some heuristic based accessors, end user intended - // (to be move to gdcmHeaderHelper?) - - int GetXSize(void); - int GetYSize(void); - int GetZSize(void); - int GetBitsStored(void); - int GetBitsAllocated(void); - int GetSamplesPerPixel(void); - int GetPlanarConfiguration(void); - int GetPixelSize(void); - - std::string GetPixelType(void); +private: + // Read + void LoadElements (void); + void LoadElementValue (gdcmElValue *); + void LoadElementValueSafe(gdcmElValue *); + void FindLength (gdcmElValue *); + void FindVR (gdcmElValue *); + + guint32 FindLengthOB(void); + + void SkipElementValue (gdcmElValue *); + void FixFoundLength (gdcmElValue *, guint32); + bool IsAnInteger (gdcmElValue *); + + guint16 ReadInt16(void); + guint32 ReadInt32(void); + void SkipBytes(guint32); + + void Initialise(void); + void CheckSwap(void); + void SwitchSwapToBigEndian(void); + void SetMaxSizeLoadElementValue(long); + + // Dict + gdcmDictEntry *GetDictEntryByName (std::string Name); + gdcmDictEntry *GetDictEntryByNumber(guint16, guint16); + + // ElValue related utilities + gdcmElValue *ReadNextElement (void); + gdcmElValue *NewElValueByNumber(guint16 group, guint16 element); + gdcmElValue *NewElValueByName (std::string Name); + gdcmElValue* GetElementByName (std::string Name); + + // Deprecated + gdcmElValue *NewManualElValToPubDict(std::string NewTagName, + std::string VR); + +// Variables + // Pointer to the Value Representation Hash Table which contains all + // the VR of the DICOM version3 public dictionary. + gdcmVR *dicom_vr; // Not a class member for thread-safety reasons - std::string GetTransferSyntaxName(void); - bool HasLUT(void); - int GetLUTNbits(void); - unsigned char * GetLUTRGBA(void); + // Pointer to the Transfert Syntax Hash Table which contains all + // the TS of the DICOM version3 public dictionary. + gdcmTS *dicom_ts; // Not a class member for thread-safety reasons + + // Pointer to global dictionary container + gdcmDictSet *Dicts; // Not a class member for thread-safety reasons + + // Public dictionary used to parse this header + gdcmDict *RefPubDict; + + // Optional "shadow dictionary" (private elements) used to parse this + // header + gdcmDict *RefShaDict; + + /// ELement VALueS parsed with the PUBlic dictionary. + gdcmElValSet PubElValSet; + + // Refering underlying filename. + std::string filename; - // voir gdcmFile::SetImageData ?!? - void SetImageDataSize (size_t ExpectedSize); + int enableSequences; -// System access - guint16 SwapShort(guint16); // needed by gdcmFile - guint32 SwapLong(guint32); // for JPEG Files + // FIXME sw should be an enum e.g. + //enum EndianType { + //LittleEndian, + //BadLittleEndian, + //BigEndian, + //BadBigEndian}; + // 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). + guint32 MaxSizeLoadElementValue; + + static const unsigned int HEADER_LENGTH_TO_READ; + static const unsigned int MAX_SIZE_LOAD_ELEMENT_VALUE; }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmHeaderHelper.cxx b/src/gdcmHeaderHelper.cxx index 60e1fbee..15f09275 100644 --- a/src/gdcmHeaderHelper.cxx +++ b/src/gdcmHeaderHelper.cxx @@ -1,60 +1,61 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmHeaderHelper.cxx,v 1.18 2004/01/13 11:32:30 jpr Exp $ - +// gdcmHeaderHelper.cxx +//----------------------------------------------------------------------------- #include "gdcmHeaderHelper.h" #include "gdcmUtil.h" //for debug #include #include -//#include //for bzero -//directory manipulation (os indep). -//cygwin ???? -> _WIN32 ?? #ifdef _MSC_VER -#include -int GetDir(std::string dPath, std::list &filenames) -{ - //For now dPath should have an ending "\" - WIN32_FIND_DATA FileData; - HANDLE hFile; - hFile = FindFirstFile((dPath+"*").c_str(), &FileData); - if ( hFile == INVALID_HANDLE_VALUE ) - { - //No files ! - return false; - } + #include + + int GetDir(std::string dPath, std::list &filenames) + { + //For now dPath should have an ending "\" + WIN32_FIND_DATA FileData; + HANDLE hFile; + hFile = FindFirstFile((dPath+"*").c_str(), &FileData); + if ( hFile == INVALID_HANDLE_VALUE ) + { + //No files ! + return false; + } - if( strncmp(FileData.cFileName, ".", 1) != 0 ) - filenames.push_back( dPath+FileData.cFileName ); - while( FindNextFile(hFile, &FileData ) != 0) - { - if( strncmp(FileData.cFileName, ".", 1) != 0 ) - filenames.push_back( dPath+FileData.cFileName ); - } - return true; -} + if( strncmp(FileData.cFileName, ".", 1) != 0 ) + filenames.push_back( dPath+FileData.cFileName ); + while( FindNextFile(hFile, &FileData ) != 0) + { + if( strncmp(FileData.cFileName, ".", 1) != 0 ) + filenames.push_back( dPath+FileData.cFileName ); + } + return true; + } #else -#include + #include -int GetDir(std::string dPath, std::list &filenames) -{ - DIR *dir = opendir( dPath.c_str() ); - struct dirent *entry; - while((entry = readdir(dir)) != NULL) - { -// if( strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0) - if( strncmp(entry->d_name, ".", 1) != 0 ) + int GetDir(std::string dPath, std::list &filenames) { - filenames.push_back( dPath + "/" + entry->d_name ); + DIR *dir = opendir( dPath.c_str() ); + struct dirent *entry; + while((entry = readdir(dir)) != NULL) + { + // if( strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0) + if( strncmp(entry->d_name, ".", 1) != 0 ) + { + filenames.push_back( dPath + "/" + entry->d_name ); + } + } + closedir(dir); + return true; } - } - closedir(dir); - return true; -} #endif -//---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// gdcmHeaderHelper +//----------------------------------------------------------------------------- +// Constructor / Destructor /** * \ingroup gdcmHeaderHelper * \brief cstor @@ -62,7 +63,7 @@ int GetDir(std::string dPath, std::list &filenames) gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) { } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief cstor @@ -71,7 +72,12 @@ gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, bool exception_on_error) : gdcmHeader( InFilename , exception_on_error) { } -//---------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public /** * \ingroup gdcmHeaderHelper * \brief Return the size (in bytes) of a single pixel of data. @@ -96,69 +102,6 @@ int gdcmHeaderHelper::GetPixelSize() { return 0; } -//---------------------------------------------------------------------------- -/** - * \ingroup gdcmHeaderHelper - * \brief This function is intended to user who doesn't whan - * \ to have to manage a LUT and expects to get an RBG Pixel image - * \ (or a monochrome one ...) - * \warning to be used with GetImagePixels() - * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) - */ -int gdcmHeaderHelper::GetNumberOfScalarComponents() { - - if (GetSamplesPerPixel() ==3) - return 3; - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if (gdcmHeader::GetPubElValByNumber(0x0028,0x0100) == "24") - return 3; - - std::string PhotometricInterpretation = - gdcmHeader::GetPubElValByNumber(0x0028,0x0004); - - if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) { - if (HasLUT()) // PALETTE COLOR is NOT enough - return 3; - else - return 1; - } - - //beware of trailing space at end of string - if (PhotometricInterpretation.find(GDCM_UNFOUND) < - PhotometricInterpretation.length() || - PhotometricInterpretation.find("MONOCHROME1") < - PhotometricInterpretation.length() || - PhotometricInterpretation.find("MONOCHROME2") < - PhotometricInterpretation.length() ) - return 1; - else - // we assume that *all* kinds of YBR are dealt with - return 3; -} - -//---------------------------------------------------------------------------- -/** - * \ingroup gdcmHeaderHelper - * \brief This function is intended to user that DOESN'T want - * \to get RGB pixels image when it's stored as a PALETTE COLOR image - * \ - the (vtk) user is supposed to know how deal with LUTs - - * \warning to be used with GetImagePixelsRaw() - * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) - */ -int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() { - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if (gdcmHeader::GetPubElValByNumber(0x0028,0x0100) == "24") - return 3; - - // we assume that *all* kinds of YBR are dealt with - return GetSamplesPerPixel(); -} - -//---------------------------------------------------------------------------- /** * \ingroup gdcmHeaderHelper * \brief Build the Pixel Type of the image. @@ -198,7 +141,7 @@ std::string gdcmHeaderHelper::GetPixelType() { return( BitsAlloc + Signed); } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0028,0030 : Pixel Spacing @@ -222,7 +165,7 @@ float gdcmHeaderHelper::GetXSpacing() { } return xspacing; } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0028,0030 : Pixel Spacing @@ -247,7 +190,6 @@ float gdcmHeaderHelper::GetYSpacing() { return yspacing; } -//---------------------------------------------------------------------------- /** *\ingroup gdcmHeaderHelper *\brief gets the info from 0018,0088 : Space Between Slices @@ -284,8 +226,112 @@ float gdcmHeaderHelper::GetZSpacing() { } } -//---------------------------------------------------------------------------- -// +float gdcmHeaderHelper::GetRescaleIntercept() +{ + float resInter = 0.; + std::string StrRescInter = GetPubElValByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept + if (StrRescInter != GDCM_UNFOUND) { + if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) { + dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty"); + // bug in the element 0x0028,0x1052 + } + } + return resInter; +} + +float gdcmHeaderHelper::GetRescaleSlope() +{ + float resSlope = 1.; + std::string StrRescSlope = GetPubElValByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope + if (StrRescSlope != GDCM_UNFOUND) { + if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) { + dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty"); + // bug in the element 0x0028,0x1053 + } + } + return resSlope; +} + +/** + * \ingroup gdcmHeaderHelper + * \brief This function is intended to user who doesn't whan + * \ to have to manage a LUT and expects to get an RBG Pixel image + * \ (or a monochrome one ...) + * \warning to be used with GetImagePixels() + * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) + */ +int gdcmHeaderHelper::GetNumberOfScalarComponents() { + + if (GetSamplesPerPixel() ==3) + return 3; + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if (gdcmHeader::GetPubElValByNumber(0x0028,0x0100) == "24") + return 3; + + std::string PhotometricInterpretation = + gdcmHeader::GetPubElValByNumber(0x0028,0x0004); + + if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) { + if (HasLUT()) // PALETTE COLOR is NOT enough + return 3; + else + return 1; + } + + //beware of trailing space at end of string + if (PhotometricInterpretation.find(GDCM_UNFOUND) < + PhotometricInterpretation.length() || + PhotometricInterpretation.find("MONOCHROME1") < + PhotometricInterpretation.length() || + PhotometricInterpretation.find("MONOCHROME2") < + PhotometricInterpretation.length() ) + return 1; + else + // we assume that *all* kinds of YBR are dealt with + return 3; +} + +/** + * \ingroup gdcmHeaderHelper + * \brief This function is intended to user that DOESN'T want + * \to get RGB pixels image when it's stored as a PALETTE COLOR image + * \ - the (vtk) user is supposed to know how deal with LUTs - + * \warning to be used with GetImagePixelsRaw() + * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) + */ +int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() { + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if (gdcmHeader::GetPubElValByNumber(0x0028,0x0100) == "24") + return 3; + + // we assume that *all* kinds of YBR are dealt with + return GetSamplesPerPixel(); +} + +std::string gdcmHeaderHelper::GetStudyUID() +{ + return GetPubElValByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID +} + +std::string gdcmHeaderHelper::GetSeriesUID() +{ + return GetPubElValByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID +} + +std::string gdcmHeaderHelper::GetClassUID() +{ + return GetPubElValByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID +} + +std::string gdcmHeaderHelper::GetInstanceUID() +{ + return GetPubElValByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID +} + // Image Position Patient (0020,0032): // If not found (ACR_NEMA) we try Image Position (0020,0030) // If not found (ACR-NEMA), we consider Slice Location (0020,1041) @@ -295,7 +341,6 @@ float gdcmHeaderHelper::GetZSpacing() { // TODO : find a way to inform the caller nothing was found // TODO : How to tell the caller a wrong number of values was found? - /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0020,0032 : Image Position Patient @@ -320,7 +365,7 @@ float gdcmHeaderHelper::GetXOrigin() { return 0.; return xImPos; } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0020,0032 : Image Position Patient @@ -345,7 +390,7 @@ float gdcmHeaderHelper::GetYOrigin() { return 0.; return yImPos; } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0020,0032 : Image Position Patient @@ -397,7 +442,7 @@ float gdcmHeaderHelper::GetZOrigin() { dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)"); return 0.; // Hopeless } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0020,0013 : Image Number @@ -416,7 +461,7 @@ int gdcmHeaderHelper::GetImageNumber() { } return 0; //Hopeless } -//---------------------------------------------------------------------------- + /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0008,0060 : Modality @@ -476,72 +521,6 @@ ModalityType gdcmHeaderHelper::GetModality(void) { return Unknow; } -//---------------------------------------------------------------------------- -std::string gdcmHeaderHelper::GetStudyUID() -{ - return GetPubElValByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID -} -//---------------------------------------------------------------------------- -std::string gdcmHeaderHelper::GetSeriesUID() -{ - return GetPubElValByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID -} -//---------------------------------------------------------------------------- -std::string gdcmHeaderHelper::GetClassUID() -{ - return GetPubElValByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID -} -//---------------------------------------------------------------------------- -std::string gdcmHeaderHelper::GetInstanceUID() -{ - return GetPubElValByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID -} -//---------------------------------------------------------------------------- -float gdcmHeaderHelper::GetRescaleIntercept() -{ - float resInter = 0.; - std::string StrRescInter = GetPubElValByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept - if (StrRescInter != GDCM_UNFOUND) { - if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) { - dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty"); - // bug in the element 0x0028,0x1052 - } - } - return resInter; -} -//---------------------------------------------------------------------------- -float gdcmHeaderHelper::GetRescaleSlope() -{ - float resSlope = 1.; - std::string StrRescSlope = GetPubElValByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope - if (StrRescSlope != GDCM_UNFOUND) { - if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) { - dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty"); - // bug in the element 0x0028,0x1053 - } - } - return resSlope; -} - - - - - - - - - -gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper() -{ - //! \todo - for (std::list::iterator it = CoherentGdcmFileList.begin(); - it != CoherentGdcmFileList.end(); it++) - { - delete *it; - } - CoherentGdcmFileList.clear(); -} -//---------------------------------------------------------------------------- /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0020,0037 : Image Orientation Patient @@ -576,30 +555,59 @@ void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) { } } -//---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- + + + +//----------------------------------------------------------------------------- +// gdcmSerieHeaderHelper +//----------------------------------------------------------------------------- +// Constructor / Destructor +gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper() +{ + //! \todo + for (std::list::iterator it = CoherentGdcmFileList.begin(); + it != CoherentGdcmFileList.end(); it++) + { + delete *it; + } + CoherentGdcmFileList.clear(); +} + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public /** - * \ingroup gdcmHeaderHelper - * \brief add a gdcmFile to the list based on file name - */ + * \ingroup gdcmHeaderHelper + * \brief add a gdcmFile to the list based on file name + */ void gdcmSerieHeaderHelper::AddFileName(std::string filename) { gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() ); this->CoherentGdcmFileList.push_back( GdcmFile ); } -//---------------------------------------------------------------------------- + /** - * \ingroup gdcmHeaderHelper - * \brief add a gdcmFile to the list - */ + * \ingroup gdcmHeaderHelper + * \brief add a gdcmFile to the list + */ void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file) { this->CoherentGdcmFileList.push_back( file ); } -//---------------------------------------------------------------------------- + /** - * \ingroup gdcmHeaderHelper - * \brief \todo - */ + * \ingroup gdcmHeaderHelper + * \brief \todo + */ void gdcmSerieHeaderHelper::SetDirectory(std::string dir) { std::list filenames_list; @@ -612,7 +620,7 @@ void gdcmSerieHeaderHelper::SetDirectory(std::string dir) this->CoherentGdcmFileList.push_back( file ); } } -//---------------------------------------------------------------------------- + //This could be implemented in a 'Strategy Pattern' approach //But as I don't know how to do it, I leave it this way //BTW, this is also a Strategy, I don't know this is the best approach :) @@ -631,17 +639,27 @@ void gdcmSerieHeaderHelper::OrderGdcmFileList() FileNameOrdering(); } } -//---------------------------------------------------------------------------- + +std::list &gdcmSerieHeaderHelper::GetGdcmFileList() +{ + return CoherentGdcmFileList; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private /** - * \ingroup gdcmHeaderHelper - * \brief - We may order, considering : - -# Image Number - -# Image Position Patient - -# More to come :) -*/ -//based on Jolinda's algorithm + * \ingroup gdcmHeaderHelper + * \brief + * We may order, considering : + * -# Image Number + * -# Image Position Patient + * -# More to come :) + */ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() +//based on Jolinda's algorithm { //iop is calculated based on the file file float *cosines = new float[6]; @@ -748,7 +766,7 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() return true; } -//---------------------------------------------------------------------------- + //Based on Image Number bool gdcmSerieHeaderHelper::ImageNumberOrdering() { @@ -800,16 +818,12 @@ bool gdcmSerieHeaderHelper::ImageNumberOrdering() delete[] partition; return mult; } -//---------------------------------------------------------------------------- + bool gdcmSerieHeaderHelper::FileNameOrdering() { //using the sort //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end()); return true; } -//---------------------------------------------------------------------------- -std::list &gdcmSerieHeaderHelper::GetGdcmFileList() -{ - return CoherentGdcmFileList; -} -//---------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- diff --git a/src/gdcmHeaderHelper.h b/src/gdcmHeaderHelper.h index 0fdb0462..8f441707 100644 --- a/src/gdcmHeaderHelper.h +++ b/src/gdcmHeaderHelper.h @@ -1,56 +1,58 @@ -// $Header: /cvs/public/gdcm/src/Attic/gdcmHeaderHelper.h,v 1.10 2004/01/13 11:32:30 jpr Exp $ - +// gdcmHeaderHelper.h +//----------------------------------------------------------------------------- #ifndef GDCMHEADERHELPER_H #define GDCMHEADERHELPER_H #include "gdcmHeader.h" - // Dicom Part 3.3 Compliant - enum ModalityType { - Unknow, - AU, // Voice Audio - AS, // Angioscopy - BI, // Biomagnetic Imaging - CF, // Cinefluorography - CP, // Culposcopy - CR, // Computed Radiography - CS, // Cystoscopy - CT, // Computed Tomography - DD, // Duplex Dopler - DF, // Digital Fluoroscopy - DG, // Diaphanography - DM, // Digital Microscopy - DS, // Digital Substraction Angiography - DX, // Digital Radiography - ECG, // Echocardiography - EPS, // Basic Cardiac EP - ES, // Endoscopy - FA, // Fluorescein Angiography - FS, // Fundoscopy - HC, // Hard Copy - HD, // Hemodynamic - LP, // Laparoscopy - LS, // Laser Surface Scan - MA, // Magnetic Resonance Angiography - MR, // Magnetic Resonance - NM, // Nuclear Medicine - OT, // Other - PT, // Positron Emission Tomography - RF, // Radio Fluoroscopy - RG, // Radiographic Imaging - RTDOSE, // Radiotherapy Dose - RTIMAGE, // Radiotherapy Image - RTPLAN, // Radiotherapy Plan - RTSTRUCT, // Radiotherapy Structure Set - SM, // Microscopic Imaging - ST, // Single-photon Emission Computed Tomography - TG, // Thermography - US, // Ultrasound - VF, // Videofluorography - XA, // X-Ray Angiography - XC // Photographic Imaging - }; +//----------------------------------------------------------------------------- +// Dicom Part 3.3 Compliant +enum ModalityType { + Unknow, + AU, // Voice Audio + AS, // Angioscopy + BI, // Biomagnetic Imaging + CF, // Cinefluorography + CP, // Culposcopy + CR, // Computed Radiography + CS, // Cystoscopy + CT, // Computed Tomography + DD, // Duplex Dopler + DF, // Digital Fluoroscopy + DG, // Diaphanography + DM, // Digital Microscopy + DS, // Digital Substraction Angiography + DX, // Digital Radiography + ECG, // Echocardiography + EPS, // Basic Cardiac EP + ES, // Endoscopy + FA, // Fluorescein Angiography + FS, // Fundoscopy + HC, // Hard Copy + HD, // Hemodynamic + LP, // Laparoscopy + LS, // Laser Surface Scan + MA, // Magnetic Resonance Angiography + MR, // Magnetic Resonance + NM, // Nuclear Medicine + OT, // Other + PT, // Positron Emission Tomography + RF, // Radio Fluoroscopy + RG, // Radiographic Imaging + RTDOSE, // Radiotherapy Dose + RTIMAGE, // Radiotherapy Image + RTPLAN, // Radiotherapy Plan + RTSTRUCT, // Radiotherapy Structure Set + SM, // Microscopic Imaging + ST, // Single-photon Emission Computed Tomography + TG, // Thermography + US, // Ultrasound + VF, // Videofluorography + XA, // X-Ray Angiography + XC // Photographic Imaging +}; +//----------------------------------------------------------------------------- /* * This class is meant to *interpret* data given from gdcmHeader * That is to say : @@ -61,7 +63,6 @@ * - ... */ class GDCM_EXPORT gdcmHeaderHelper : public gdcmHeader { - public: gdcmHeaderHelper::gdcmHeaderHelper(); gdcmHeaderHelper::gdcmHeaderHelper(const char *filename, @@ -74,7 +75,7 @@ public: float GetYSpacing(); float GetZSpacing(); - //Usefull for rescaling graylevel: + // Usefull for rescaling graylevel: float GetRescaleIntercept(); float GetRescaleSlope(); @@ -86,12 +87,12 @@ public: std::string GetClassUID(); std::string GetInstanceUID(); - /** - change GetXImagePosition -> GetXOrigin in order not to confused reader - -# GetXOrigin can return default value (=0) if it was not ImagePosition - -# Image Position is different in dicomV3 <> ACR NEMA -> better use generic - name - */ + /** + * change GetXImagePosition -> GetXOrigin in order not to confused reader + * -# GetXOrigin can return default value (=0) if it was not ImagePosition + * -# Image Position is different in dicomV3 <> ACR NEMA -> better use generic + * name + */ float GetXOrigin(); float GetYOrigin(); float GetZOrigin(); @@ -100,16 +101,14 @@ public: ModalityType GetModality(); void GetImageOrientationPatient( float* iop ); - - }; +//----------------------------------------------------------------------------- /** This class should be used for a stack of 2D dicom images. For a multiframe dicom image better use directly gdcmHeaderHelper */ class GDCM_EXPORT gdcmSerieHeaderHelper { - public: gdcmSerieHeaderHelper::gdcmSerieHeaderHelper() {}; gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(); @@ -119,7 +118,7 @@ public: void SetDirectory(std::string dir); void OrderGdcmFileList(); - gdcmHeaderHelper *GetGdcmHeader() + inline gdcmHeaderHelper *GetGdcmHeader() { //Assume all element in the list have the same global infos return CoherentGdcmFileList.front(); @@ -133,7 +132,7 @@ private: bool FileNameOrdering(); std::list CoherentGdcmFileList; - }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmJpeg.cxx b/src/gdcmJpeg.cxx index 76f04c23..15bdd1a1 100644 --- a/src/gdcmJpeg.cxx +++ b/src/gdcmJpeg.cxx @@ -1,4 +1,5 @@ - +// gdcmJpeg.cxx +//----------------------------------------------------------------------------- #include #include "gdcmFile.h" @@ -117,74 +118,70 @@ extern "C" { * Here's the extended error handler struct: */ +//----------------------------------------------------------------------------- struct my_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ }; +//----------------------------------------------------------------------------- typedef struct my_error_mgr * my_error_ptr; /* * Here's the routine that will replace the standard error_exit method: */ +METHODDEF(void) my_error_exit (j_common_ptr cinfo) { + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; -METHODDEF(void) -my_error_exit (j_common_ptr cinfo) { - /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ - my_error_ptr myerr = (my_error_ptr) cinfo->err; - - /* Always display the message. */ - /* We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); } - +//----------------------------------------------------------------------------- /* * Sample routine for JPEG decompression. We assume that the source file name * is passed in. We want to return 1 on success, 0 on error. */ //GLOBAL(bool) bool gdcmFile::gdcm_read_JPEG_file (FILE *fp,void * image_buffer) { + char *pimage; -char *pimage; - - /* This struct contains the JPEG decompression parameters and pointers to + /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ - - struct jpeg_decompress_struct cinfo; - - /* -------------- inside, we found : - JDIMENSION image_width; // input image width - JDIMENSION image_height; // input image height - int input_components; // nb of color components in input image - J_COLOR_SPACE in_color_space; // colorspace of input image - double input_gamma; // image gamma of input image + struct jpeg_decompress_struct cinfo; + + /* -------------- inside, we found : + JDIMENSION image_width; // input image width + JDIMENSION image_height; // input image height + int input_components; // nb of color components in input image + J_COLOR_SPACE in_color_space; // colorspace of input image + double input_gamma; // image gamma of input image -------------- */ - - /* We use our private extension JPEG error handler. + + /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ - struct my_error_mgr jerr; - /* More stuff */ - - JSAMPARRAY buffer; /* Output row buffer */ - - // rappel : - // ------ - // typedef unsigned char JSAMPLE; - // typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ - // typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ - // typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + struct my_error_mgr jerr; + /* More stuff */ + + JSAMPARRAY buffer; /* Output row buffer */ - - int row_stride; /* physical row width in output buffer */ + // rappel : + // ------ + // typedef unsigned char JSAMPLE; + // typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ + // typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ + // typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + int row_stride; /* physical row width in output buffer */ - if (DEBUG) printf("entree dans gdcmFile::gdcm_read_JPEG_file, depuis gdcmJpeg\n"); + if (DEBUG) printf("entree dans gdcmFile::gdcm_read_JPEG_file, depuis gdcmJpeg\n"); /* In this example we want to open the input file before doing anything else, @@ -214,33 +211,31 @@ char *pimage; /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); - /* Step 2: specify data source (eg, a file) */ - -if (DEBUG) printf("Entree Step 2\n"); - - jpeg_stdio_src(&cinfo, fp); + /* Step 2: specify data source (eg, a file) */ + if (DEBUG) printf("Entree Step 2\n"); - /* Step 3: read file parameters with jpeg_read_header() */ + jpeg_stdio_src(&cinfo, fp); - if (DEBUG) printf("Entree Step 3\n"); + /* Step 3: read file parameters with jpeg_read_header() */ + if (DEBUG) printf("Entree Step 3\n"); - (void) jpeg_read_header(&cinfo, TRUE); + (void) jpeg_read_header(&cinfo, TRUE); - /* We can ignore the return value from jpeg_read_header since - * (a) suspension is not possible with the stdio data source, and - * (b) we passed TRUE to reject a tables-only JPEG file as an error. - * See libjpeg.doc for more info. - */ - -if (DEBUG) { - printf("--------------Header contents :----------------\n"); - printf("image_width %d image_height %d\n", - cinfo.image_width , cinfo.image_height); - printf("bits of precision in image data %d \n", - cinfo.output_components); - printf("nb of color components returned %d \n", - cinfo.data_precision); -} + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + if (DEBUG) { + printf("--------------Header contents :----------------\n"); + printf("image_width %d image_height %d\n", + cinfo.image_width , cinfo.image_height); + printf("bits of precision in image data %d \n", + cinfo.output_components); + printf("nb of color components returned %d \n", + cinfo.data_precision); + } /* @@ -253,17 +248,14 @@ if (DEBUG) { */ - /* Step 4: set parameters for decompression */ - - if (DEBUG) printf("Entree Step 4\n"); - - /* In this example, we don't need to change any of the defaults set by - * jpeg_read_header(), so we do nothing here. - */ + /* Step 4: set parameters for decompression */ + if (DEBUG) printf("Entree Step 4\n"); + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ - /* Step 5: Start decompressor */ - - if (DEBUG) printf("Entree Step 5\n"); + /* Step 5: Start decompressor */ + if (DEBUG) printf("Entree Step 5\n"); (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible @@ -280,30 +272,28 @@ if (DEBUG) { /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; - if (DEBUG) printf ("cinfo.output_width %d cinfo.output_components %d row_stride %d\n", - cinfo.output_width, cinfo.output_components,row_stride); + if (DEBUG) printf ("cinfo.output_width %d cinfo.output_components %d row_stride %d\n", + cinfo.output_width, cinfo.output_components,row_stride); - /* Make a one-row-high sample array that will go away when done with image */ - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - /* Step 6: while (scan lines remain to be read) */ - - if (DEBUG) printf("Entree Step 6\n"); + /* Step 6: while (scan lines remain to be read) */ + if (DEBUG) printf("Entree Step 6\n"); - /* jpeg_read_scanlines(...); */ + /* jpeg_read_scanlines(...); */ - /* Here we use the library's state variable cinfo.output_scanline as the - * loop counter, so that we don't have to keep track ourselves. - */ - - if (DEBUG) printf ("cinfo.output_height %d cinfo.output_width %d\n", - cinfo.output_height,cinfo.output_width); + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + if (DEBUG) + printf ("cinfo.output_height %d cinfo.output_width %d\n", + cinfo.output_height,cinfo.output_width); - pimage=(char *)image_buffer; - + pimage=(char *)image_buffer; - while (cinfo.output_scanline < cinfo.output_height) { + while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. @@ -327,35 +317,34 @@ if (DEBUG) { } /* Step 7: Finish decompression */ - -if (DEBUG) printf("Entree Step 7\n"); + if (DEBUG) printf("Entree Step 7\n"); - (void) jpeg_finish_decompress(&cinfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ - /* Step 8: Release JPEG decompression object */ - -if (DEBUG) printf("Entree Step 8\n"); + /* Step 8: Release JPEG decompression object */ - /* This is an important step since it will release a good deal of memory. */ - - jpeg_destroy_decompress(&cinfo); + if (DEBUG) printf("Entree Step 8\n"); - /* After finish_decompress, we can close the input file. - * Here we postpone it until after no more JPEG errors are possible, - * so as to simplify the setjmp error logic above. (Actually, I don't - * think that jpeg_destroy can do an error exit, but why assume anything...) - */ + /* This is an important step since it will release a good deal of memory. */ - /* At this point you may want to check to see whether any corrupt-data - * warnings occurred (test whether jerr.pub.num_warnings is nonzero). - */ + jpeg_destroy_decompress(&cinfo); - /* And we're done! */ - - return 1; + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + + return 1; } /* @@ -383,9 +372,4 @@ if (DEBUG) printf("Entree Step 8\n"); * temporary files are deleted if the program is interrupted. See libjpeg.doc. */ - - - - - - +//----------------------------------------------------------------------------- diff --git a/src/gdcmJpeg12.cxx b/src/gdcmJpeg12.cxx index 8a9a4bd8..da5be5d8 100644 --- a/src/gdcmJpeg12.cxx +++ b/src/gdcmJpeg12.cxx @@ -1,4 +1,5 @@ - +// gdcmJpeg12.cxx +//----------------------------------------------------------------------------- #include #include "gdcmFile.h" @@ -70,11 +71,8 @@ #define jpeg_destroy jDestroy #define jpeg_resync_to_restart jResyncRestart -// ----------------- - #define DEBUG 0 - /* * is used for the optional error recovery mechanism shown in * the second part of the example. @@ -132,6 +130,7 @@ extern "C" { * Here's the extended error handler struct: */ +//----------------------------------------------------------------------------- struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ @@ -139,10 +138,10 @@ struct my_error_mgr { typedef struct my_error_mgr * my_error_ptr; +//----------------------------------------------------------------------------- /* * Here's the routine that will replace the standard error_exit method: */ - METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ @@ -157,216 +156,200 @@ my_error_exit (j_common_ptr cinfo) { } +//----------------------------------------------------------------------------- /* * Sample routine for JPEG decompression. We assume that the source file name * is passed in. We want to return 1 on success, 0 on error. */ - - -//GLOBAL(bool) bool gdcmFile::gdcm_read_JPEG_file12 (FILE *fp,void * image_buffer) { + char *pimage; -char *pimage; + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ - /* This struct contains the JPEG decompression parameters and pointers to - * working space (which is allocated as needed by the JPEG library). - */ - - struct jpeg_decompress_struct cinfo; - - /* -------------- inside, we found : - JDIMENSION image_width; // input image width - JDIMENSION image_height; // input image height - int input_components; // nb of color components in input image - J_COLOR_SPACE in_color_space; // colorspace of input image - double input_gamma; // image gamma of input image - -------------- */ - - /* We use our private extension JPEG error handler. - * Note that this struct must live as long as the main JPEG parameter - * struct, to avoid dangling-pointer problems. - */ - struct my_error_mgr jerr; - /* More stuff */ - - JSAMPARRAY buffer; /* Output row buffer */ - - // rappel : - // ------ - // typedef unsigned char JSAMPLE; - // typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ - // typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ - // typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + struct jpeg_decompress_struct cinfo; - - int row_stride; /* physical row width in output buffer */ + /* -------------- inside, we found : + * JDIMENSION image_width; // input image width + * JDIMENSION image_height; // input image height + * int input_components; // nb of color components in input image + * J_COLOR_SPACE in_color_space; // colorspace of input image + * double input_gamma; // image gamma of input image + * -------------- */ - if (DEBUG) printf("entree dans gdcmFile::gdcm_read_JPEG_file12, depuis gdcmJpeg\n"); + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ - /* In this example we want to open the input file before doing anything else, - * so that the setjmp() error recovery below can assume the file is open. - * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that - * requires it in order to read binary files. - */ + // rappel : + // ------ + // typedef unsigned char JSAMPLE; + // typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ + // typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ + // typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ - /* Step 1: allocate and initialize JPEG decompression object */ - - if (DEBUG)printf("Entree Step 1\n"); - /* We set up the normal JPEG error routines, then override error_exit. */ - - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = my_error_exit; + int row_stride; /* physical row width in output buffer */ - /* Establish the setjmp return context for my_error_exit to use. */ + if (DEBUG) printf("entree dans gdcmFile::gdcm_read_JPEG_file12, depuis gdcmJpeg\n"); + + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + /* Step 1: allocate and initialize JPEG decompression object */ + if (DEBUG)printf("Entree Step 1\n"); + + /* We set up the normal JPEG error routines, then override error_exit. */ + + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + return(false); + } + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + if (DEBUG) printf("Entree Step 2\n"); + jpeg_stdio_src(&cinfo, fp); + + /* Step 3: read file parameters with jpeg_read_header() */ + if (DEBUG) printf("Entree Step 3\n"); + (void) jpeg_read_header(&cinfo, TRUE); + + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + if (DEBUG) { + printf("--------------Header contents :----------------\n"); + printf("image_width %d image_height %d\n", + cinfo.image_width , cinfo.image_height); + printf("bits of precision in image data %d \n", + cinfo.output_components); + printf("nb of color components returned %d \n", + cinfo.data_precision); + } + + + /* + * JDIMENSION image_width; // input image width + * JDIMENSION image_height; // input image height + * int output_components; // # of color components returned + * J_COLOR_SPACE in_color_space; // colorspace of input image + * double input_gamma; // image gamma of input image + * int data_precision; // bits of precision in image data + */ + + /* Step 4: set parameters for decompression */ + if (DEBUG) printf("Entree Step 4\n"); + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + if (DEBUG) printf("Entree Step 5\n"); + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_decompress(&cinfo); - return(false); - } - /* Now we can initialize the JPEG decompression object. */ - jpeg_create_decompress(&cinfo); - - /* Step 2: specify data source (eg, a file) */ - -if (DEBUG) printf("Entree Step 2\n"); - - jpeg_stdio_src(&cinfo, fp); - - /* Step 3: read file parameters with jpeg_read_header() */ - - if (DEBUG) printf("Entree Step 3\n"); - - (void) jpeg_read_header(&cinfo, TRUE); - - /* We can ignore the return value from jpeg_read_header since - * (a) suspension is not possible with the stdio data source, and - * (b) we passed TRUE to reject a tables-only JPEG file as an error. - * See libjpeg.doc for more info. - */ - -if (DEBUG) { - printf("--------------Header contents :----------------\n"); - printf("image_width %d image_height %d\n", - cinfo.image_width , cinfo.image_height); - printf("bits of precision in image data %d \n", - cinfo.output_components); - printf("nb of color components returned %d \n", - cinfo.data_precision); - -} + if (DEBUG) + printf ("cinfo.output_width %d cinfo.output_components %d row_stride %d\n", + cinfo.output_width, cinfo.output_components,row_stride); + + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + /* Step 6: while (scan lines remain to be read) */ + if (DEBUG) printf("Entree Step 6\n"); -/* - JDIMENSION image_width; // input image width - JDIMENSION image_height; // input image height - int output_components; // # of color components returned - J_COLOR_SPACE in_color_space; // colorspace of input image - double input_gamma; // image gamma of input image - int data_precision; // bits of precision in image data - -*/ + /* jpeg_read_scanlines(...); */ - /* Step 4: set parameters for decompression */ - - if (DEBUG) printf("Entree Step 4\n"); + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ - /* In this example, we don't need to change any of the defaults set by - * jpeg_read_header(), so we do nothing here. - */ + if (DEBUG) printf ("cinfo.output_height %d cinfo.output_width %d\n", + cinfo.output_height,cinfo.output_width); - /* Step 5: Start decompressor */ - - if (DEBUG) printf("Entree Step 5\n"); - - (void) jpeg_start_decompress(&cinfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ - - /* We may need to do some setup of our own at this point before reading - * the data. After jpeg_start_decompress() we have the correct scaled - * output image dimensions available, as well as the output colormap - * if we asked for color quantization. - * In this example, we need to make an output work buffer of the right size. - */ - - /* JSAMPLEs per row in output buffer */ - row_stride = cinfo.output_width * cinfo.output_components; - - if (DEBUG) printf ("cinfo.output_width %d cinfo.output_components %d row_stride %d\n", - cinfo.output_width, cinfo.output_components,row_stride); - - /* Make a one-row-high sample array that will go away when done with image */ - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + pimage=(char *)image_buffer; - /* Step 6: while (scan lines remain to be read) */ - - if (DEBUG) printf("Entree Step 6\n"); + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ - /* jpeg_read_scanlines(...); */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); - /* Here we use the library's state variable cinfo.output_scanline as the - * loop counter, so that we don't have to keep track ourselves. - */ - - if (DEBUG) printf ("cinfo.output_height %d cinfo.output_width %d\n", - cinfo.output_height,cinfo.output_width); - - pimage=(char *)image_buffer; - - while (cinfo.output_scanline < cinfo.output_height) { - /* jpeg_read_scanlines expects an array of pointers to scanlines. - * Here the array is only one element long, but you could ask for - * more than one scanline at a time if that's more convenient. - */ - - (void) jpeg_read_scanlines(&cinfo, buffer, 1); - - if ( BITS_IN_JSAMPLE == 8) { + if ( BITS_IN_JSAMPLE == 8) { memcpy( pimage, buffer[0],row_stride); pimage+=row_stride; - } else { + } else { memcpy( pimage, buffer[0],row_stride*2 ); // FIXME : *2 car 16 bits?!? pimage+=row_stride*2; // FIXME : *2 car 16 bits?!? - } - } + } + } /* Step 7: Finish decompression */ - -if (DEBUG) printf("Entree Step 7\n"); - + if (DEBUG) printf("Entree Step 7\n"); (void) jpeg_finish_decompress(&cinfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ - /* Step 8: Release JPEG decompression object */ - -if (DEBUG) printf("Entree Step 8\n"); + /* Step 8: Release JPEG decompression object */ + if (DEBUG) printf("Entree Step 8\n"); - /* This is an important step since it will release a good deal of memory. */ - - jpeg_destroy_decompress(&cinfo); + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); - /* After finish_decompress, we can close the input file. - * Here we postpone it until after no more JPEG errors are possible, - * so as to simplify the setjmp error logic above. (Actually, I don't - * think that jpeg_destroy can do an error exit, but why assume anything...) - */ + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ - /* At this point you may want to check to see whether any corrupt-data - * warnings occurred (test whether jerr.pub.num_warnings is nonzero). - */ + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ - /* And we're done! */ - - return(true); + /* And we're done! */ + + return(true); } /* @@ -393,10 +376,5 @@ if (DEBUG) printf("Entree Step 8\n"); * On some systems you may need to set up a signal handler to ensure that * temporary files are deleted if the program is interrupted. See libjpeg.doc. */ - - - - - - +//----------------------------------------------------------------------------- diff --git a/src/gdcmJpeg2000.cxx b/src/gdcmJpeg2000.cxx index 895c865b..2d60fe09 100644 --- a/src/gdcmJpeg2000.cxx +++ b/src/gdcmJpeg2000.cxx @@ -1,16 +1,13 @@ - - /* -------------------------------------------------------------------- */ - // - // JPEG 2000 Files - // - /* -------------------------------------------------------------------- */ - +// gdcmJpeg2000.cxx +//----------------------------------------------------------------------------- #include #include "gdcmFile.h" +//----------------------------------------------------------------------------- bool gdcmFile::gdcm_read_JPEG2000_file (FILE *fp,void * image_buffer) { printf("Sorry JPEG 2000 File not yet taken into account\n"); return false; } +//----------------------------------------------------------------------------- diff --git a/src/gdcmParse.cxx b/src/gdcmParse.cxx index d618c315..57a09dac 100644 --- a/src/gdcmParse.cxx +++ b/src/gdcmParse.cxx @@ -1,5 +1,5 @@ // gdcmParse.cxx - +//----------------------------------------------------------------------------- //This is needed when compiling in debug mode #ifdef _MSC_VER // 'type' : forcing value to bool 'true' or 'false' (performance warning) @@ -17,7 +17,7 @@ #define str2num(str, typeNum) *((typeNum *)(str)) -///////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- /** * \ingroup gdcmFile * \brief Parse pixel data from disk and *prints* the result @@ -28,10 +28,8 @@ * */ bool gdcmFile::ParsePixelData(void) { - // DO NOT remove the printf s. // The ONLY purpose of this methos is to PRINT the content - FILE *fp; if ( !(fp=Header->OpenFile())) @@ -246,3 +244,5 @@ bool gdcmFile::ParsePixelData(void) { } return true; } + +//----------------------------------------------------------------------------- diff --git a/src/gdcmRLE.cxx b/src/gdcmRLE.cxx index ab7f62f7..4387ebcf 100644 --- a/src/gdcmRLE.cxx +++ b/src/gdcmRLE.cxx @@ -1,17 +1,12 @@ - +// gdcmRLE.cxx +//----------------------------------------------------------------------------- #include #include "gdcmFile.h" #include /* to declare isprint() */ #define str2num(str, typeNum) *((typeNum *)(str)) -static int _gdcm_read_RLE_fragment (char ** image_buffer, - long lengthToDecode, - long uncompressedSegmentSize, - FILE* fp); -// static because nothing but gdcm_read_RLE_file may call it - -// ---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- /** * \ingroup gdcmFile * \brief Reads a 'Run Length Encoded' Dicom encapsulated file @@ -21,14 +16,6 @@ static int _gdcm_read_RLE_fragment (char ** image_buffer, * * @return Boolean */ - -// This is a debug version. -// Forget the printf as they will be removed -// as soon as the last Heuristics are checked - -// pb with RLE 16 Bits : - - bool gdcmFile::gdcm_read_RLE_file (FILE *fp,void * image_buffer) { long fragmentBegining; // for ftell, fseek char * im = (char *)image_buffer; @@ -97,7 +84,7 @@ bool gdcmFile::gdcm_read_RLE_file (FILE *fp,void * image_buffer) { RleSegmentLength[k]=RleSegmentOffsetTable[k+1]-RleSegmentOffsetTable[k]; ftellRes=ftell(fp); fragmentBegining=ftell(fp); - _gdcm_read_RLE_fragment (&im, RleSegmentLength[k],uncompressedSegmentSize,fp); + gdcm_read_RLE_fragment (&im, RleSegmentLength[k],uncompressedSegmentSize,fp); fseek(fp,fragmentBegining,SEEK_SET); fseek(fp,RleSegmentLength[k],SEEK_CUR); } @@ -105,7 +92,7 @@ bool gdcmFile::gdcm_read_RLE_file (FILE *fp,void * image_buffer) { RleSegmentLength[nbRleSegments] = fragmentLength - RleSegmentOffsetTable[nbRleSegments]; ftellRes=ftell(fp); fragmentBegining=ftell(fp); - _gdcm_read_RLE_fragment (&im, RleSegmentLength[nbRleSegments],uncompressedSegmentSize, fp); + gdcm_read_RLE_fragment (&im, RleSegmentLength[nbRleSegments],uncompressedSegmentSize, fp); fseek(fp,fragmentBegining,SEEK_SET); fseek(fp,RleSegmentLength[nbRleSegments],SEEK_CUR); @@ -147,20 +134,10 @@ bool gdcmFile::gdcm_read_RLE_file (FILE *fp,void * image_buffer) { } - /* -------------------------------------------------------------------- */ - // - // RLE LossLess Fragment - // - /* -------------------------------------------------------------------- */ - - // static because nothing but gdcm_read_RLE_file can call it - // DO NOT doxygen ! - -static int -_gdcm_read_RLE_fragment (char ** areaToRead, - long lengthToDecode, - long uncompressedSegmentSize, - FILE* fp) { +// ---------------------------------------------------------------------------- +// RLE LossLess Fragment +int gdcmFile::gdcm_read_RLE_fragment(char **areaToRead, long lengthToDecode, + long uncompressedSegmentSize, FILE *fp) { long ftellRes; int count; long numberOfOutputBytes=0; @@ -168,7 +145,6 @@ _gdcm_read_RLE_fragment (char ** areaToRead, ftellRes =ftell(fp); while(numberOfOutputBytes #include "gdcmTS.h" @@ -10,6 +10,8 @@ #endif #define DICT_TS "dicomTS.dic" +//----------------------------------------------------------------------------- +// Constructor / Destructor gdcmTS::gdcmTS(void) { std::string filename=gdcmDictSet::BuildDictPath() + std::string(DICT_TS); std::ifstream from(filename.c_str()); @@ -38,6 +40,11 @@ gdcmTS::~gdcmTS() { ts.clear(); } +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public int gdcmTS::Count(TSKey key) { return ts.count(key); } @@ -47,3 +54,11 @@ std::string gdcmTS::GetValue(TSKey key) { return (GDCM_UNFOUND); return ts[key]; } + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- diff --git a/src/gdcmTS.h b/src/gdcmTS.h index fde45c6b..7cd142bc 100644 --- a/src/gdcmTS.h +++ b/src/gdcmTS.h @@ -1,5 +1,5 @@ // gdcmTS.h - +//----------------------------------------------------------------------------- #ifndef GDCMTS_H #define GDCMTS_H @@ -7,23 +7,26 @@ #include #include +//----------------------------------------------------------------------------- typedef std::string TSKey; typedef std::string TSAtr; typedef std::map TSHT; // Transfert Syntax Hash Table +//----------------------------------------------------------------------------- /* * Container for dicom Transfert Syntax Hash Table * \note This is a singleton */ class GDCM_EXPORT gdcmTS { -private: - TSHT ts; - public: gdcmTS(void); ~gdcmTS(); int Count(TSKey key); std::string GetValue(TSKey key); + +private: + TSHT ts; }; +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmUtil.cxx b/src/gdcmUtil.cxx index 729d400e..40143310 100644 --- a/src/gdcmUtil.cxx +++ b/src/gdcmUtil.cxx @@ -1,14 +1,16 @@ -// $Header: /cvs/public/gdcm/src/gdcmUtil.cxx,v 1.25 2003/10/02 11:26:16 malaterre Exp $ - +// gdcmUtil.cxx +//----------------------------------------------------------------------------- #include "gdcmUtil.h" #include #include // For isspace #include +//----------------------------------------------------------------------------- // Library globals. gdcmDebug dbg; +//----------------------------------------------------------------------------- gdcmDebug::gdcmDebug(int level) { DebugLevel = level; } @@ -19,14 +21,6 @@ void gdcmDebug::Verbose(int Level, const char * Msg1, const char * Msg2) { std::cerr << Msg1 << ' ' << Msg2 << std::endl; } -void gdcmDebug::Assert(int Level, bool Test, - const char * Msg1, const char * Msg2) { - if (Level > DebugLevel) - return ; - if (!Test) - std::cerr << Msg1 << ' ' << Msg2 << std::endl; -} - void gdcmDebug::Error( bool Test, const char * Msg1, const char * Msg2) { if (!Test) return; @@ -40,6 +34,14 @@ void gdcmDebug::Error(const char* Msg1, const char* Msg2, Exit(1); } +void gdcmDebug::Assert(int Level, bool Test, + const char * Msg1, const char * Msg2) { + if (Level > DebugLevel) + return ; + if (!Test) + std::cerr << Msg1 << ' ' << Msg2 << std::endl; +} + void gdcmDebug::Exit(int a) { #ifdef __GNUC__ std::exit(a); @@ -49,7 +51,7 @@ void gdcmDebug::Exit(int a) { #endif } -/////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- gdcmVR * gdcmGlobal::VR = (gdcmVR*)0; gdcmTS * gdcmGlobal::TS = (gdcmTS*)0; gdcmDictSet * gdcmGlobal::Dicts = (gdcmDictSet*)0; @@ -76,11 +78,12 @@ gdcmVR * gdcmGlobal::GetVR(void) { gdcmTS * gdcmGlobal::GetTS(void) { return TS; } + gdcmDictSet * gdcmGlobal::GetDicts(void) { return Dicts; } -/////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // Because is not yet available in g++2.96 std::istream& eatwhite(std::istream& is) { char c; @@ -95,7 +98,6 @@ std::istream& eatwhite(std::istream& is) { /////////////////////////////////////////////////////////////////////////// // Because is not available in C++ (?) - void Tokenize (const std::string& str, std::vector& tokens, const std::string& delimiters) { @@ -111,7 +113,6 @@ void Tokenize (const std::string& str, /////////////////////////////////////////////////////////////////////////// // to prevent a flashing screen when non-printable character - char * _cleanString(char *v) { char *d; int i, l; @@ -128,20 +129,7 @@ char * _cleanString(char *v) { /////////////////////////////////////////////////////////////////////////// // to prevent a flashing screen when non-printable character - std::string _CreateCleanString(std::string s) { -/* char *d, *di, *v; - int i, l; - v=(char*)s.c_str(); - l = strlen(v); - d = di = strdup(v); - for (i=0; - i #include +//----------------------------------------------------------------------------- /* * gdcmDebug is an object for debugging in program. * It has 2 debugging modes : @@ -21,35 +22,42 @@ * message level. */ class gdcmDebug { -private: - int DebugLevel; public: gdcmDebug(int = 0); - void Verbose(int, const char*, const char* =""); + void SetDebug (int i) {DebugLevel = i;} + + void Verbose(int, const char*, const char* =""); void Error(bool, const char*, const char* =""); void Error(const char*, const char* ="", const char* =""); + void Assert(int, bool, const char*, const char*); void Exit(int); - void SetDebug (int i) {DebugLevel = i;} + +private: + int DebugLevel; }; +//----------------------------------------------------------------------------- /* * This class contains all globals elements that might be * instanciated only one time */ class gdcmGlobal { -private: - static gdcmVR *VR; - static gdcmTS *TS; - static gdcmDictSet *Dicts; public: gdcmGlobal(void); ~gdcmGlobal(); + static gdcmVR * GetVR(void); static gdcmTS * GetTS(void); static gdcmDictSet * GetDicts(void); + +private: + static gdcmVR *VR; + static gdcmTS *TS; + static gdcmDictSet *Dicts; }; +//----------------------------------------------------------------------------- std::istream & eatwhite(std::istream & is); void Tokenize (const std::string& str, @@ -61,7 +69,6 @@ extern gdcmDebug dbg; char * _cleanString(char *v); std::string _CreateCleanString(std::string s); -std::string TranslateToKey(guint16 group, guint16 element); - +//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmVR.cxx b/src/gdcmVR.cxx index 3d2ea9c2..de4f1e1c 100644 --- a/src/gdcmVR.cxx +++ b/src/gdcmVR.cxx @@ -1,6 +1,6 @@ // gdcmVR.cxx #include - +//----------------------------------------------------------------------------- #include "gdcmVR.h" #include "gdcmUtil.h" @@ -9,6 +9,8 @@ #endif #define DICT_VR "dicomVR.dic" +//----------------------------------------------------------------------------- +// Constructor / Destructor gdcmVR::gdcmVR(void) { std::string filename=gdcmDictSet::BuildDictPath() + std::string(DICT_VR); std::ifstream from(filename.c_str()); @@ -41,6 +43,19 @@ gdcmVR::~gdcmVR() { vr.clear(); } +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public int gdcmVR::Count(VRKey key) { return vr.count(key); } + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- diff --git a/src/gdcmVR.h b/src/gdcmVR.h index f2932193..82663675 100644 --- a/src/gdcmVR.h +++ b/src/gdcmVR.h @@ -1,5 +1,5 @@ // gdcmVR.h - +//----------------------------------------------------------------------------- #ifndef GDCMVR_H #define GDCMVR_H @@ -7,21 +7,25 @@ #include #include +//----------------------------------------------------------------------------- typedef std::string VRKey; typedef std::string VRAtr; typedef std::map VRHT; // Value Representation Hash Table +//----------------------------------------------------------------------------- /* * Container for dicom Value Representation Hash Table * \note This is a singleton */ class GDCM_EXPORT gdcmVR { -private: - VRHT vr; public: gdcmVR(void); ~gdcmVR(); int Count(VRKey key); + +private: + VRHT vr; }; +//----------------------------------------------------------------------------- #endif -- 2.45.2