+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.
// gdcm.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCM_H
#define GDCM_H
#include "gdcmHeaderHelper.h"
#include "gdcmFile.h"
-//#include "gdcmTS.h"
-//#include "gdcmVR.h"
-//#include "gdcmUtil.h"
-
+//-----------------------------------------------------------------------------
#endif // #ifndef GDCM_H
//gdcmCommon.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMCOMMON_H
#define GDCMCOMMON_H
// Mmmmmm !
// It reminds me the formerly well known LibIDO's idproto.h
+//-----------------------------------------------------------------------------
#ifdef __GNUC__
#ifndef HAVE_NO_STDINT_H
#include <stdint.h>
//For now gdcm is not willing cmake, try to be more quiet
//#cmakedefine GDCM_NO_ANSI_STRING_STREAM
+//-----------------------------------------------------------------------------
#endif
// gdcmDict.cxx
-
+//-----------------------------------------------------------------------------
#include "gdcmDict.h"
#include "gdcmUtil.h"
#include <fstream>
# include <sstream>
#endif
+//-----------------------------------------------------------------------------
+// Constructor / Destructor
/**
* \ingroup gdcmDict
* \brief Construtor
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).
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
}
}
+/**
+ * \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,
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
+
+//-----------------------------------------------------------------------------
// gdcmDict.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMDICT_H
#define GDCMDICT_H
#include "gdcmDictEntry.h"
#include <map>
+//-----------------------------------------------------------------------------
typedef std::map<TagKey, gdcmDictEntry*> TagKeyHT;
typedef std::map<TagName, gdcmDictEntry*> TagNameHT;
+//-----------------------------------------------------------------------------
/*
* \defgroup gdcmDict
* \brief gdcmDict acts a memory representation of a dicom dictionary i.e.
* \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
// gdcmDictEntry.cxx
-
+//-----------------------------------------------------------------------------
#include "gdcmDictEntry.h"
#include <stdio.h> // FIXME For sprintf
#include "gdcmUtil.h"
+//-----------------------------------------------------------------------------
+// Constructor / Destructor
/**
* \ingroup gdcmDictEntry
* \brief Construtor
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
* @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
+
+//-----------------------------------------------------------------------------
+
// gdcmDictEntry.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMDICTENTRY_H
#define GDCMDICTENTRY_H
#include "gdcmCommon.h"
+//-----------------------------------------------------------------------------
/*
* the gdcmDictEntry in an element contained by the gdcmDict.
* It contains :
* - 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
// 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
// gdcmDictEntry
-
+//-----------------------------------------------------------------------------
#include "gdcmDictSet.h"
#include "gdcmUtil.h"
#include <fstream>
#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.
* 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-
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
*/
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);
}
/**
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
+
+//-----------------------------------------------------------------------------
+
+
// gdcmDictSet.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMDICTSET_H
#define GDCMDICTSET_H
typedef std::string DictKey;
typedef std::map<DictKey, gdcmDict*> DictSetHT;
+//-----------------------------------------------------------------------------
/*
* \defgroup gdcmDictSet
* \brief Container for managing a set of loaded dictionaries.
* (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<std::string> * GetPubDictTagNames(void);
- std::map<std::string, std::list<std::string> >*
- 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
// TODO Swig std::string* GetAllDictNames();
gdcmDictSet(void);
~gdcmDictSet(void);
+
void Print(std::ostream& os);
- gdcmDict* GetDict(DictKey DictName);
+ std::list<std::string> * GetPubDictTagNames(void);
+ std::map<std::string, std::list<std::string> >*
+ 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
// gdcmElValSet.cxx
-
+//-----------------------------------------------------------------------------
#include "gdcmUtil.h"
#include "gdcmElValSet.h"
#include "gdcmTS.h"
# include <sstream>
#endif
+//-----------------------------------------------------------------------------
+// Constructor / Destructor
/**
* \ingroup gdcmElValSet
* \brief Destructor
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) {
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){
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){
os<<s.str();
}
+//-----------------------------------------------------------------------------
+// Public
+/**
+ * \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 retrieves a Dicom Element (the first one) using (group, element)
return tagHt.find(key)->second->GetValue();
}
-
/**
* \ingroup gdcmElValSet
* \brief Sets the value (string) of the target Dicom Element
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 ;
}
/**
/**
* \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
}
}
-/**
- * \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);
-}
-
+//-----------------------------------------------------------------------------
-// $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
#include <map>
#include <list> // for linking together *all* the Dicom Elements
-/*
- * Container for a set of successfully parsed ElValues (i.e. Dicom Elements).
- */
-
+//-----------------------------------------------------------------------------
typedef std::multimap<TagKey, gdcmElValue*> TagElValueHT;
typedef std::pair<TagKey, gdcmElValue*> PairHT;
typedef std::pair<TagElValueHT::iterator,TagElValueHT::iterator> IterHT;
typedef std::string GroupKey;
typedef std::map<GroupKey, int> 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
// 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
+
+//-----------------------------------------------------------------------------
-// $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
#include <stdio.h>
+//-----------------------------------------------------------------------------
/*
* 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(); };
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
-
+// gdcmException.cxx
+//-----------------------------------------------------------------------------
#include "gdcmException.h"
#include <typeinfo>
#include <stdio.h>
+//-----------------------------------------------------------------------------
+// gdcmException
gdcmException::gdcmException(const std::string &f, const std::string& msg) throw()
#ifdef __GNUC__
try
#endif
-
void gdcmException::fatal(const char *from) throw() {
try {
std::cerr << "Fatal: exception received in " << from
}
}
-
std::string gdcmException::getName() const throw() {
try {
#ifdef __GNUC__ // GNU C++ compiler class name demangling
}
}
-
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;
return os;
}
-
+//-----------------------------------------------------------------------------
+// gdcmException.h
+//-----------------------------------------------------------------------------
#ifndef GDCM_EXCEPTION_H
#define GDCM_EXCEPTION_H
#include <iostream>
#include <exception>
+//-----------------------------------------------------------------------------
/*
* 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
// 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
SetPixelDataSizeFromHeader();
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief Constructor dedicated to writing a new DICOMV3 part10 compliant
SetPixelDataSizeFromHeader();
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief Destructor dedicated to writing a new DICOMV3 part10 compliant
Header=NULL;
}
+//-----------------------------------------------------------------------------
+// Print
+//-----------------------------------------------------------------------------
+// Public
/**
* \ingroup gdcmFile
* \brief
* @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);
}
}
- // 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<nbPixels;p+=2) {
- fread(&b0,1,1,fp);
- fread(&b1,1,1,fp);
- fread(&b2,1,1,fp);
- //Two steps is necessary to please VC++
- *pdestination++ = ((b0 >> 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);
}
/**
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
* @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();
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 (?!)
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
* (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
*
* @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;
{
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
//
} 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();
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);
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<lgr;i++)
- ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[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<lgr;i++) {
- faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 4321 */
- fort =((unsigned long int*)im)[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<lgr;i++) {
- faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 2143 */
- fort=((unsigned long int*)im)[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<lgr;i++) {
- faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 3412 */
- fort=((unsigned long int*)im)[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
return(true);
}
-
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief Ecrit sur disque les pixels d'UNE image
return(true);
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief Ecrit sur disque UNE image Dicom
return WriteBase(fileName, ImplicitVR);
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief
return WriteDcmImplVR (std::string (fileName));
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief
return WriteBase(fileName, ExplicitVR);
}
-/////////////////////////////////////////////////////////////////
/**
* \ingroup gdcmFile
* \brief Ecrit au format ACR-NEMA sur disque l'entete et les pixels
return WriteBase(fileName, ACR);
}
-/////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
+// Protected
/**
* \ingroup gdcmFile
*
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<lgr;i++)
+ ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[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<lgr;i++) {
+ faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 4321 */
+ fort =((unsigned long int*)im)[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<lgr;i++) {
+ faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 2143 */
+ fort=((unsigned long int*)im)[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<lgr;i++) {
+ faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 3412 */
+ fort=((unsigned long int*)im)[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<nbPixels;p+=2) {
+ fread(&b0,1,1,fp);
+ fread(&b1,1,1,fp);
+ fread(&b2,1,1,fp);
+ //Two steps is necessary to please VC++
+ *pdestination++ = ((b0 >> 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;
+}
+//-----------------------------------------------------------------------------
// 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
*/
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);
void SetPixelDataSizeFromHeader(void);
size_t GetImageDataSize();
size_t GetImageDataSizeRaw();
+
void * GetImageData();
size_t GetImageDataIntoVector(void* destination, size_t MaxSize);
void * GetImageDataRaw();
// 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
-// $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 <stdio.h>
#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
* @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,
else
enableSequences = 0;
- SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_);
+ SetMaxSizeLoadElementValue(MAX_SIZE_LOAD_ELEMENT_VALUE);
filename = InFilename;
Initialise();
if ( !OpenFile(exception_on_error))
* @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;
}
/**
* \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;
}
/**
* \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<std::string> 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<std::string> 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<lengthR;i++) {
+ *a = lutR[i*mult+1];
+ a+=4;
+ }
+ a = LUTRGBA+1;
+ for(i=0;i<lengthG;i++) {
+ *a = lutG[i*mult+1];
+ a+=4;
+ }
+ a = LUTRGBA+2;
+ for(i=0;i<lengthB;i++) {
+ *a = lutB[i*mult+1];
+ a+=4;
+ }
+ a = LUTRGBA+3;
+ for(i=0;i<256;i++) {
+ *a = 1; // Alpha component
+ a+=4;
+ }
+
+//How to free the now useless LUTs?
+
+//free(LutR); free(LutB); free(LutG);
+ return(LUTRGBA);
+}
+
/**
* \ingroup gdcmHeader
- * \brief
- * @param NewSize
- * @return
+ * \brief gets the info from 0002,0010 : Transfert Syntax
+ * \ else 1.
+ * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
*/
- void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) {
- if (NewSize < 0)
- return;
- if ((guint32)NewSize >= (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
// LoadElementValue(tag->second);
//}
- for (ListTag::iterator i = GetListElem().begin();
- i != GetListElem().end();
+ for (ListTag::iterator i = GetPubListElem().begin();
+ i != GetPubListElem().end();
++i){
LoadElementValue(*i);
}
}
/**
- * \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<std::string> 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<std::string> 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<lengthR;i++) {
- *a = lutR[i*mult+1];
- a+=4;
- }
- a= LUTRGBA+1;
- for(i=0;i<lengthG;i++) {
- *a = lutG[i*mult+1];
- a+=4;
- }
- a= LUTRGBA+2;
- for(i=0;i<lengthB;i++) {
- *a = lutB[i*mult+1];
- a+=4;
- }
- a= LUTRGBA+3;
- for(i=0;i<256;i++) {
- *a = 1; // Alpha component
- a+=4;
- }
-
-//How to free the now useless LUTs?
-//
-//free(LutR); free(LutB); free(LutG);
+ 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;
+}
- return(LUTRGBA);
-}
-
-/////////////////////////////////////////////////////////////////
/**
- * \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
+ * \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
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;
}
+
+//-----------------------------------------------------------------------------
-// $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
#include "gdcmElValSet.h"
#include <map>
+//-----------------------------------------------------------------------------
typedef std::string VRKey;
typedef std::string VRAtr;
typedef std::map<VRKey, VRAtr> 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
* 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);
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.
// 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
-// $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 <math.h>
#include <algorithm>
-//#include <string.h> //for bzero
-//directory manipulation (os indep).
-//cygwin ???? -> _WIN32 ??
#ifdef _MSC_VER
-#include <windows.h>
-int GetDir(std::string dPath, std::list<std::string> &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 <windows.h>
+
+ int GetDir(std::string dPath, std::list<std::string> &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 <dirent.h>
+ #include <dirent.h>
-int GetDir(std::string dPath, std::list<std::string> &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<std::string> &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
gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( )
{
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief cstor
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.
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.
return( BitsAlloc + Signed);
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0028,0030 : Pixel Spacing
}
return xspacing;
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0028,0030 : Pixel Spacing
return yspacing;
}
-//----------------------------------------------------------------------------
/**
*\ingroup gdcmHeaderHelper
*\brief gets the info from 0018,0088 : Space Between Slices
}
}
-//----------------------------------------------------------------------------
-//
+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)
// 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
return 0.;
return xImPos;
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0020,0032 : Image Position Patient
return 0.;
return yImPos;
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0020,0032 : Image Position Patient
dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)");
return 0.; // Hopeless
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0020,0013 : Image Number
}
return 0; //Hopeless
}
-//----------------------------------------------------------------------------
+
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0008,0060 : Modality
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<gdcmHeaderHelper*>::iterator it = CoherentGdcmFileList.begin();
- it != CoherentGdcmFileList.end(); it++)
- {
- delete *it;
- }
- CoherentGdcmFileList.clear();
-}
-//----------------------------------------------------------------------------
/**
* \ingroup gdcmHeaderHelper
* \brief gets the info from 0020,0037 : Image Orientation Patient
}
}
-//----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Protected
+
+//-----------------------------------------------------------------------------
+// Private
+
+//-----------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+// gdcmSerieHeaderHelper
+//-----------------------------------------------------------------------------
+// Constructor / Destructor
+gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper()
+{
+ //! \todo
+ for (std::list<gdcmHeaderHelper*>::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<std::string> filenames_list;
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 :)
FileNameOrdering();
}
}
-//----------------------------------------------------------------------------
+
+std::list<gdcmHeaderHelper*> &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];
return true;
}
-//----------------------------------------------------------------------------
+
//Based on Image Number
bool gdcmSerieHeaderHelper::ImageNumberOrdering()
{
delete[] partition;
return mult;
}
-//----------------------------------------------------------------------------
+
bool gdcmSerieHeaderHelper::FileNameOrdering()
{
//using the sort
//sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
return true;
}
-//----------------------------------------------------------------------------
-std::list<gdcmHeaderHelper*> &gdcmSerieHeaderHelper::GetGdcmFileList()
-{
- return CoherentGdcmFileList;
-}
-//----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
-// $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 :
* - ...
*/
class GDCM_EXPORT gdcmHeaderHelper : public gdcmHeader {
-
public:
gdcmHeaderHelper::gdcmHeaderHelper();
gdcmHeaderHelper::gdcmHeaderHelper(const char *filename,
float GetYSpacing();
float GetZSpacing();
- //Usefull for rescaling graylevel:
+ // Usefull for rescaling graylevel:
float GetRescaleIntercept();
float GetRescaleSlope();
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();
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();
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();
bool FileNameOrdering();
std::list<gdcmHeaderHelper*> CoherentGdcmFileList;
-
};
+//-----------------------------------------------------------------------------
#endif
-
+// gdcmJpeg.cxx
+//-----------------------------------------------------------------------------
#include <stdio.h>
#include "gdcmFile.h"
* 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,
/* 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);
+ }
/*
*/
- /* 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
/* 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.
}
/* 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;
}
/*
* temporary files are deleted if the program is interrupted. See libjpeg.doc.
*/
-
-
-
-
-
-
+//-----------------------------------------------------------------------------
-
+// gdcmJpeg12.cxx
+//-----------------------------------------------------------------------------
#include <stdio.h>
#include "gdcmFile.h"
#define jpeg_destroy jDestroy
#define jpeg_resync_to_restart jResyncRestart
-// -----------------
-
#define DEBUG 0
-
/*
* <setjmp.h> is used for the optional error recovery mechanism shown in
* the second part of the example.
* 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 */
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 */
}
+//-----------------------------------------------------------------------------
/*
* 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);
}
/*
* 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.
*/
-
-
-
-
-
-
+//-----------------------------------------------------------------------------
-
- /* -------------------------------------------------------------------- */
- //
- // JPEG 2000 Files
- //
- /* -------------------------------------------------------------------- */
-
+// gdcmJpeg2000.cxx
+//-----------------------------------------------------------------------------
#include <stdio.h>
#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;
}
+//-----------------------------------------------------------------------------
// gdcmParse.cxx
-
+//-----------------------------------------------------------------------------
//This is needed when compiling in debug mode
#ifdef _MSC_VER
// 'type' : forcing value to bool 'true' or 'false' (performance warning)
#define str2num(str, typeNum) *((typeNum *)(str))
-/////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
/**
* \ingroup gdcmFile
* \brief Parse pixel data from disk and *prints* the result
*
*/
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()))
}
return true;
}
+
+//-----------------------------------------------------------------------------
-
+// gdcmRLE.cxx
+//-----------------------------------------------------------------------------
#include <stdio.h>
#include "gdcmFile.h"
#include <ctype.h> /* 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
*
* @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;
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);
}
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);
}
- /* -------------------------------------------------------------------- */
- //
- // 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;
ftellRes =ftell(fp);
while(numberOfOutputBytes<uncompressedSegmentSize) {
-
ftellRes =ftell(fp);
fread(&n,sizeof(char),1,fp);
count=n;
}
return 1;
}
+
+// ----------------------------------------------------------------------------
// gdcmTS.cxx
-
+//-----------------------------------------------------------------------------
#include <fstream>
#include "gdcmTS.h"
#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());
ts.clear();
}
+//-----------------------------------------------------------------------------
+// Print
+
+//-----------------------------------------------------------------------------
+// Public
int gdcmTS::Count(TSKey key) {
return ts.count(key);
}
return (GDCM_UNFOUND);
return ts[key];
}
+
+//-----------------------------------------------------------------------------
+// Protected
+
+//-----------------------------------------------------------------------------
+// Private
+
+//-----------------------------------------------------------------------------
// gdcmTS.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMTS_H
#define GDCMTS_H
#include <map>
#include <string>
+//-----------------------------------------------------------------------------
typedef std::string TSKey;
typedef std::string TSAtr;
typedef std::map<TSKey, TSAtr> 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
-// $Header: /cvs/public/gdcm/src/gdcmUtil.cxx,v 1.25 2003/10/02 11:26:16 malaterre Exp $
-
+// gdcmUtil.cxx
+//-----------------------------------------------------------------------------
#include "gdcmUtil.h"
#include <stdio.h>
#include <ctype.h> // For isspace
#include <string.h>
+//-----------------------------------------------------------------------------
// Library globals.
gdcmDebug dbg;
+//-----------------------------------------------------------------------------
gdcmDebug::gdcmDebug(int level) {
DebugLevel = level;
}
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;
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);
#endif
}
-///////////////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
gdcmVR * gdcmGlobal::VR = (gdcmVR*)0;
gdcmTS * gdcmGlobal::TS = (gdcmTS*)0;
gdcmDictSet * gdcmGlobal::Dicts = (gdcmDictSet*)0;
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;
///////////////////////////////////////////////////////////////////////////
// Because is not available in C++ (?)
-
void Tokenize (const std::string& str,
std::vector<std::string>& tokens,
const std::string& delimiters) {
///////////////////////////////////////////////////////////////////////////
// to prevent a flashing screen when non-printable character
-
char * _cleanString(char *v) {
char *d;
int i, l;
///////////////////////////////////////////////////////////////////////////
// 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<l ;
- i++,di++,v++) {
- if (!isprint(*v))
- *di = '.';
- }
- return d;*/
std::string str=s;
for(int i=0;i<str.size();i++)
{
return(str);
}
-///////////////////////////////////////////////////////////////////////////
-//
-// because it may not be associated to a dictionary ...
-
-std::string TranslateToKey(guint16 group, guint16 element) {
- char trash[10];
- std::string key;
- // CLEAN ME: better call the iostream<< with the hex manipulator on.
- // This requires some reading of the stdlibC++ sources to make the
- // proper call (or copy).
- sprintf(trash, "%04x|%04x", group , element);
- key = trash; // Convertion through assignement
- return key;
-}
-
-
-
-// $Header: /cvs/public/gdcm/src/gdcmUtil.h,v 1.17 2004/01/12 13:12:28 regrain Exp $
-
+// gdcmUtil.h
+//-----------------------------------------------------------------------------
#ifndef GDCMUTIL_H
#define GDCMUTIL_H
#include <vector>
#include <string>
+//-----------------------------------------------------------------------------
/*
* gdcmDebug is an object for debugging in program.
* It has 2 debugging modes :
* 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,
char * _cleanString(char *v);
std::string _CreateCleanString(std::string s);
-std::string TranslateToKey(guint16 group, guint16 element);
-
+//-----------------------------------------------------------------------------
#endif
// gdcmVR.cxx
#include <fstream>
-
+//-----------------------------------------------------------------------------
#include "gdcmVR.h"
#include "gdcmUtil.h"
#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());
vr.clear();
}
+//-----------------------------------------------------------------------------
+// Print
+
+//-----------------------------------------------------------------------------
+// Public
int gdcmVR::Count(VRKey key) {
return vr.count(key);
}
+
+//-----------------------------------------------------------------------------
+// Protected
+
+//-----------------------------------------------------------------------------
+// Private
+
+//-----------------------------------------------------------------------------
// gdcmVR.h
-
+//-----------------------------------------------------------------------------
#ifndef GDCMVR_H
#define GDCMVR_H
#include <map>
#include <string>
+//-----------------------------------------------------------------------------
typedef std::string VRKey;
typedef std::string VRAtr;
typedef std::map<VRKey, VRAtr> 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