// the declaration once you provided the definition of the method...
#include <string>
+#ifdef _MSC_VER
+using namespace std; // string type lives in the std namespace on VC++
+#endif
+
#include <iostream>
#include <stddef.h> // For size_t
#include <stdio.h> // FIXME For FILE on GCC only
-#include <map> // The requirement for the hash table (or map) that
- // we shall use:
- // 1/ First, next, last (iterators)
- // 2/ should be sortable (i.e. sorted by TagKey). This
- // condition shall be droped since the Win32/VC++
- // implementation doesn't look a sorted one. Pffff....
- // 3/ Make sure we can setup some default size value,
- // which should be around 4500 entries which is the
- // average dictionary size (said JPR)
-
-#define g_malloc malloc
-#define g_free free
+#include <map>
#ifdef __GNUC__
#include <stdint.h>
#define guint16 uint16_t
#define guint32 uint32_t
#endif
+
#ifdef _MSC_VER
typedef unsigned short guint16;
typedef unsigned int guint32;
-
#endif
-#ifdef _MSC_VER
- using namespace std; // string type lives in the std namespace on VC++
-#endif
#ifdef _MSC_VER
#define GDCM_EXPORT __declspec( dllexport )
#else
#define GDCM_EXPORT
#endif
+////////////////////////////////////////////////////////////////////////////
// Tag based hash tables.
// We shall use as keys the strings (as the C++ type) obtained by
// concatenating the group value and the element value (both of type
string vr; // Value Representation i.e. some clue about the nature
// of the data represented e.g. "FD" short for
// "Floating Point Double"
- // CLEAN ME: find the official dicom name for this field !
+ // CLEANME: find the official dicom name for this field !
string fourth; // Fourth field containing some semantics.
string name; // e.g. "Patient_Name"
- TagKey key; // This is redundant zith (group, element) but we add
+ TagKey key; // Redundant with (group, element) but we add it
// on efficiency purposes.
// DCMTK has many fields for handling a DictEntry (see below). What are the
// relevant ones for gdcmlib ?
// struct DBI_SimpleEntry {
- // Uint16 group;
- // Uint16 element;
// Uint16 upperGroup;
// Uint16 upperElement;
// DcmEVR evr;
// DcmDictRangeRestriction elementRestriction;
// };
public:
- //CLEANME gdcmDictEntry();
gdcmDictEntry(guint16 group, guint16 element,
string vr = "Unknown",
- string fourth = "Unknown",
- string name = "Unknown");
+ string fourth = "Unknown",
+ string name = "Unknown");
static TagKey TranslateToKey(guint16 group, guint16 element);
guint16 GetGroup(void) { return group;};
guint16 GetElement(void){return element;};
string GetKey(void) {return key;};
};
-typedef map<TagKey, gdcmDictEntry*> TagHT;
-
+////////////////////////////////////////////////////////////////////////////
// A single DICOM dictionary i.e. a container for a collection of dictionary
// entries. There should be a single public dictionary (THE dictionary of
// the actual DICOM v3) but as many shadow dictionaries as imagers
// combined with all software versions...
+typedef map<TagKey, gdcmDictEntry*> TagHT;
+
class GDCM_EXPORT gdcmDict {
string name;
string filename;
void Print(ostream&);
};
+////////////////////////////////////////////////////////////////////////////
// Container for managing a set of loaded dictionaries. Sharing dictionaries
// should avoid :
-// * reloading an allready loaded dictionary.
+// * reloading an allready loaded dictionary,
// * having many in memory representations of the same dictionary.
typedef string DictKey;
typedef map<DictKey, gdcmDict*> DictSetHT;
+
class GDCM_EXPORT gdcmDictSet {
private:
string DictPath; // Directory path to dictionaries
public:
gdcmDictSet(void); // loads THE DICOM v3 dictionary
// TODO Swig int LoadDictFromFile(string filename);
-///// QUESTION: the following function might not be thread safe !? Maybe
-///// we need some mutex here, to avoid concurent creation of
-///// the same dictionary !?!?!
+ // QUESTION: the following function might not be thread safe !? Maybe
+ // we need some mutex here, to avoid concurent creation of
+ // the same dictionary !?!?!
// TODO Swig int LoadDictFromName(string filename);
// TODO Swig int LoadAllDictFromDirectory(string DirectoryName);
// TODO Swig string* GetAllDictNames();
gdcmDict* GetDefaultPublicDict(void);
};
+////////////////////////////////////////////////////////////////////////////
// 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 ElValue {
string GetName(void) { return entry->GetName();};
};
-typedef map<TagKey, ElValue*> TagElValueHT;
-typedef map<string, ElValue*> TagElValueNameHT;
+////////////////////////////////////////////////////////////////////////////
// Container for a set of succefully parsed ElValues.
+typedef map<TagKey, ElValue*> TagElValueHT;
+ typedef map<string, ElValue*> TagElValueNameHT;
+
class GDCM_EXPORT ElValSet {
- // We need both accesses with a TagKey and the Dictentry.Name
+ // We need both accesses with a TagKey and the Dictentry.Name
TagElValueHT tagHt;
TagElValueNameHT NameHt;
public:
void Add(ElValue*);
void Print(ostream &);
void PrintByName(ostream &);
- ElValue* GetElement(guint32 group, guint32 element);
- string GetElValue(guint32 group, guint32 element);
- string GetElValue(string);
+ ElValue* GetElementByNumber(guint32 group, guint32 element);
+ ElValue* GetElementByName(string);
+ string GetElValueByNumber(guint32 group, guint32 element);
+ string GetElValueByName(string);
TagElValueHT & GetTagHt(void);
};
-// The various entries of the explicit value representation (VR) shall
-// be managed within a dictionary.
-typedef string VRKey;
-typedef string VRAtr;
-typedef map<TagKey, VRAtr> VRHT; // Value Representation Hash Table
-
-// The typical usage of objects of this class is to classify a set of
+////////////////////////////////////////////////////////////////////////////
+// The typical usage of instances of class gdcmHeader is to classify a set of
// dicom files according to header information e.g. to create a file hierachy
// reflecting the Patient/Study/Serie informations, or extracting a given
// SerieId. Accesing the content (image[s] or volume[s]) is beyond the
-// functionality of this class (see dmcFile below).
+// functionality of this class and belong to gdmcFile (see below).
// Notes:
+// * the various entries of the explicit value representation (VR) shall
+// be managed within a dictionary which is shared by all gdcmHeader instances
// * the gdcmHeader::Set*Tag* family members cannot be defined as protected
// (Swig limitations for as Has_a dependency between gdcmFile and gdcmHeader)
+
+typedef string VRKey;
+typedef string VRAtr;
+typedef map<TagKey, VRAtr> VRHT; // Value Representation Hash Table
+
class GDCM_EXPORT gdcmHeader {
-//FIXME sw should be qn EndianType !!!
- //enum EndianType {
- //LittleEndian,
- //BadLittleEndian,
- //BigEndian,
- //BadBigEndian};
void SkipBytes(guint32);
private:
- // All instances share the same Value Representation dictionary
static VRHT *dicom_vr;
// Dictionaries of data elements:
- static gdcmDictSet* Dicts; // Global dictionary container
- gdcmDict* RefPubDict; // Public Dictionary
- gdcmDict* RefShaDict; // Shadow Dictionary (optional)
+ static gdcmDictSet* Dicts; // global dictionary container
+ gdcmDict* RefPubDict; // public dictionary
+ gdcmDict* RefShaDict; // shadow dictionary (optional)
// Parsed element values:
ElValSet PubElVals; // parsed with Public Dictionary
ElValSet ShaElVals; // parsed with Shadow Dictionary
- // In order to inspect/navigate through the file
- string filename;
+ string filename; // refering underlying file
FILE * fp;
- // The tag Image Location ((0028,0200) containing the adress of
+ // The tag Image Location ((0028,0200) containing the address of
// the pixels) is not allways present. When we store this information
// FIXME
// outside of the elements:
guint16 grPixel;
guint16 numPixel;
// Swap code (little, big, big-bad endian): this code is not fixed
- // during parsing.
+ // during parsing.FIXME sw should be an enum e.g.
+ //enum EndianType {
+ //LittleEndian,
+ //BadLittleEndian,
+ //BigEndian,
+ //BadBigEndian};
int sw;
// Only the elements whose size are below this bound shall be loaded.
// By default, this upper bound is limited to 1024 (which looks reasonable
ExplicitVR,
ImplicitVR,
ACR,
- ACR_LIBIDO};
+ ACR_LIBIDO}; // CLEANME
FileType filetype;
-///// QUESTION: Maybe Print is a better name than write !?
int write(ostream&);
-///// QUESTION: Maybe anonymize should be a friend function !?!?
-///// See below for an example of how anonymize might be implemented.
- int anonymize(ostream&);
+ int anonymize(ostream&); // FIXME : anonymize should be a friend ?
public:
void LoadElements(void);
virtual void ParseHeader(void);
// TODO Swig int SetShaDict(string filename);
// Retrieve all potentially available tag [tag = (group, element)] names
- // from the standard (or public) dictionary (hence static). Typical usage:
- // enable the user of a GUI based interface to select his favorite fields
- // for sorting or selection.
+ // from the standard (or public) dictionary. Typical usage: enable the
+ // user of a GUI based interface to select his favorite fields for sorting
+ // or selection.
// TODO Swig string* GetPubTagNames();
// Get the element values themselves:
string GetPubElValByName(string TagName);
string GetPubElValByNumber(guint16 group, guint16 element);
- // Get the element value representation: (VR) might be needed by caller
+ // Getting the element value representation (VR) might be needed by caller
// to convert the string typed content to caller's native type (think
// of C/C++ vs Python).
- // TODO Swig string GetPubElValRepByName(string TagName);
- // TODO Swig string GetPubElValRepByNumber(guint16 group, guint16 element);
+ string GetPubElValRepByName(string TagName);
+ string GetPubElValRepByNumber(guint16 group, guint16 element);
TagElValueHT & GetPubElVal(void) { return PubElVals.GetTagHt(); };
void PrintPubElVal(ostream & os = cout);
void PrintPubDict(ostream &);
// Same thing with the shadow :
// TODO Swig string* GetShaTagNames();
- // TODO Swig string GetShaElValByName(string TagName);
- // TODO Swig string GetShaElValByNumber(guint16 group, guint16 element);
- // TODO Swig string GetShaElValRepByName(string TagName);
- // TODO Swig string GetShaElValRepByNumber(guint16 group, guint16 element);
+ string GetShaElValByName(string TagName);
+ string GetShaElValByNumber(guint16 group, guint16 element);
+ string GetShaElValRepByName(string TagName);
+ string GetShaElValRepByNumber(guint16 group, guint16 element);
- // Wrappers of the above (both public and shadow) to avoid bugging the
- // caller with knowing if ElVal is from the public or shadow dictionary.
- // TODO Swig string GetElValByName(string TagName);
- // TODO Swig string GetElValByNumber(guint16 group, guint16 element);
- // TODO Swig string GetElValRepByName(string TagName);
- // TODO Swig string GetElValRepByNumber(guint16 group, guint16 element);
+ // Wrappers of the above (public is privileged over shadow) to avoid
+ // bugging the caller with knowing if ElVal is from the public or shadow
+ // dictionary.
+ string GetElValByName(string TagName);
+ string GetElValByNumber(guint16 group, guint16 element);
+ string GetElValRepByName(string TagName);
+ string GetElValRepByNumber(guint16 group, guint16 element);
// TODO Swig int SetPubElValByName(string content, string TagName);
// TODO Swig int SetPubElValByNumber(string content, guint16 group, guint16 element);
// TODO Swig int GetSwapCode();
};
+////////////////////////////////////////////////////////////////////////////
// In addition to Dicom header exploration, this class is designed
// for accessing the image/volume content. One can also use it to
// write Dicom files.
{
private:
void* Data;
- int Parsed; // weather allready parsed
- string OrigFileName; // To avoid file overwrite
+ int Parsed; // weather allready parsed
+ string OrigFileName; // To avoid file overwrite
public:
// Constructor dedicated to writing a new DICOMV3 part10 compliant
// file (see SetFileName, SetDcmTag and Write)
//class gdcmSerie : gdcmFile;
//class gdcmMultiFrame : gdcmFile;
-
-//
-//Examples:
-// * gdcmFile WriteDicom;
-// WriteDicom.SetFileName("MyDicomFile.dcm");
-// string * AllTags = gdcmHeader.GetDcmTagNames();
-// WriteDicom.SetDcmTag(AllTags[5], "253");
-// WriteDicom.SetDcmTag("Patient Name", "bozo");
-// WriteDicom.SetDcmTag("Patient Name", "bozo");
-// WriteDicom.SetImageData(Image);
-// WriteDicom.Write();
-//
-//
-// Anonymize(ostream& output) {
-// a = gdcmFile("toto1");
-// a.SetPubValueByName("Patient Name", "");
-// a.SetPubValueByName("Date", "");
-// a.SetPubValueByName("Study Date", "");
-// a.write(output);
-// }
/**
* \ingroup gdcmHeader
- * \brief La seule maniere sure que l'on aie pour determiner
- * si on est en LITTLE_ENDIAN, BIG-ENDIAN,
- * BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN
- * est de trouver l'element qui donne la longueur d'un 'GROUP'
- * (on sait que la longueur de cet element vaut 0x00000004)
- * et de regarder comment cette longueur est codee en memoire
- *
- * Le probleme vient de ce que parfois, il n'y en a pas ...
- *
- * On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre.
- * (Ce qui est la norme -pas respectee- depuis ACR-NEMA)
- * Si ce n'est pas le cas, on ne peut rien faire.
- *
- * (il faudrait avoir des fonctions auxquelles
- * on passe le code Swap en parametre, pour faire des essais 'manuels')
+ * \brief Discover what the swap code is (among little endian, big endian,
+ * bad little endian, bad big endian).
*/
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 : pour ntohs
bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
// 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.
- //FIXME Si c'est du RAW, ca degagera + tard
-
if (! net2host )
sw = 0;
else
/**
* \ingroup gdcmHeader
- * \brief recupere la longueur d'un champ DICOM.
- * Preconditions:
- * 1/ le fichier doit deja avoir ete ouvert,
- * 2/ CheckSwap() doit avoir ete appele
- * 3/ la partie 'group' ainsi que la partie 'elem'
- * de l'acr_element doivent avoir ete lues.
- *
- * ACR-NEMA : we allways get
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ElementSize (4 Octets)
- * DICOM en implicit Value Representation :
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ElementSize (4 Octets)
- *
- * DICOM en explicit Value Representation :
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ValueRepresentation (2 Octets)
- * ElementSize (2 Octets)
- *
- * ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ValueRepresentation (2 Octets)
- * zone reservee (2 Octets)
- * ElementSize (4 Octets)
+ * \brief Find the value representation of the current tag.
*
* @param sw code swap
* @param skippedLength pointeur sur nombre d'octets que l'on a saute qd
* @return True when big endian found. False in all other cases.
*/
bool gdcmHeader::IsBigEndianTransferSyntax(void) {
- ElValue* Element = PubElVals.GetElement(0x0002, 0x0010);
+ ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
if ( !Element )
return false;
LoadElementValueSafe(Element);
}
// FIXME The exact size should be length if we move to strings or whatever
- char* NewValue = (char*)g_malloc(length+1);
+ char* NewValue = (char*)malloc(length+1);
if( !NewValue) {
dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
return;
item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
if ( item_read != 1 ) {
- g_free(NewValue);
+ free(NewValue);
Error::FileReadError(fp, "gdcmHeader::LoadElementValue");
ElVal->SetValue("gdcm::UnRead");
return;
guint16 numPixel;
string ImageLocation = GetPubElValByName("Image Location");
if ( ImageLocation == "UNFOUND" ) {
- grPixel = 0x7FE0;
+ grPixel = 0x7fe0;
} else {
grPixel = (guint16) atoi( ImageLocation.c_str() );
}
numPixel = 0x1010;
else
numPixel = 0x0010;
- ElValue* PixelElement = PubElVals.GetElement(grPixel, numPixel);
+ ElValue* PixelElement = PubElVals.GetElementByNumber(grPixel, numPixel);
if (PixelElement)
return PixelElement->GetOffset();
else
}
string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) {
- return PubElVals.GetElValue(group, element);
+ return PubElVals.GetElValueByNumber(group, element);
+}
+
+string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) {
+ ElValue* elem = PubElVals.GetElementByNumber(group, element);
+ if ( !elem )
+ return "gdcm::Unfound";
+ return elem->GetVR();
}
string gdcmHeader::GetPubElValByName(string TagName) {
- return PubElVals.GetElValue(TagName);
+ return PubElVals.GetElValueByName(TagName);
+}
+
+string gdcmHeader::GetPubElValRepByName(string TagName) {
+ ElValue* elem = PubElVals.GetElementByName(TagName);
+ if ( !elem )
+ return "gdcm::Unfound";
+ return elem->GetVR();
+}
+
+string gdcmHeader::GetShaElValByNumber(guint16 group, guint16 element) {
+ return ShaElVals.GetElValueByNumber(group, element);
+}
+
+string gdcmHeader::GetShaElValRepByNumber(guint16 group, guint16 element) {
+ ElValue* elem = ShaElVals.GetElementByNumber(group, element);
+ if ( !elem )
+ return "gdcm::Unfound";
+ return elem->GetVR();
+}
+
+string gdcmHeader::GetShaElValByName(string TagName) {
+ return ShaElVals.GetElValueByName(TagName);
+}
+
+string gdcmHeader::GetShaElValRepByName(string TagName) {
+ ElValue* elem = ShaElVals.GetElementByName(TagName);
+ if ( !elem )
+ return "gdcm::Unfound";
+ return elem->GetVR();
+}
+
+
+string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) {
+ string pub = GetPubElValByNumber(group, element);
+ if (pub.length())
+ return pub;
+ return GetShaElValByNumber(group, element);
+}
+
+string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) {
+ string pub = GetPubElValRepByNumber(group, element);
+ if (pub.length())
+ return pub;
+ return GetShaElValRepByNumber(group, element);
+}
+
+string gdcmHeader::GetElValByName(string TagName) {
+ string pub = GetPubElValByName(TagName);
+ if (pub.length())
+ return pub;
+ return GetShaElValByName(TagName);
+}
+
+string gdcmHeader::GetElValRepByName(string TagName) {
+ string pub = GetPubElValRepByName(TagName);
+ if (pub.length())
+ return pub;
+ return GetShaElValRepByName(TagName);
}
/**