X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2Fgdcm.h;h=aea4edc5c3a450ef9a9d4570a0b5af1ee7b45e92;hb=953fdb8435f0957ba61cf9f0154ed0dc67d53981;hp=ae6da2f2998602d46c2a53e1bdca1bc0f3db40a9;hpb=f22035516061f75820d0accadee770ddefa06e2b;p=gdcm.git diff --git a/src/gdcm.h b/src/gdcm.h index ae6da2f2..aea4edc5 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -3,7 +3,7 @@ // gdcmlib Intro: // * gdcmlib is a library dedicated to reading and writing dicom files. // * LGPL for the license -// * lightweigth as opposed to CTN or DCMTK wich come bundled which try +// * lightweigth as opposed to CTN or DCMTK which come bundled which try // to implement the full DICOM standard (networking...). gdcmlib concentrates // on reading and writing // * Formats: this lib should be able to read ACR-NEMA v1 and v2, Dicom v3 (as @@ -17,16 +17,19 @@ // problems appears at loading of _gdcm.[so/dll]). So, simply uncomment // the declaration once you provided the definition of the method... +#ifndef GDCM_H +#define GDCM_H + #include -#ifdef _MSC_VER -using namespace std; // string type lives in the std namespace on VC++ -#endif +using namespace std; #include #include // For size_t #include // FIXME For FILE on GCC only #include #include +#include "gdcmException.h" + // The requirement for the hash table (or map) that // we shall use: @@ -38,8 +41,8 @@ using namespace std; // string type lives in the std namespace on VC++ // which should be around 4500 entries which is the // average dictionary size (said JPR) // - // En fait, je disais que dans LE Directory Dicom (dans son etat 2002) - // il y a 1600 entrees. + // En fait, je disais que dans LE Directory Dicom (dans son etat 2001) + // il y a +/- 1600 entrees. // Une valeur raisonable pour un majorant du nombre d'entrees // dans une entete DICOM d'une image semble semble etre 300 // Si on 'decortique' les elements SQ (ce qui ne semble pas etre fait pour le moment) @@ -48,11 +51,10 @@ using namespace std; // string type lives in the std namespace on VC++ // Quant au nombre d'entrees dans un DICOMDIR, c'est encore pire : il n'est limité // que par la taille d'un CD-ROM (les DVD-ROM ne sont pas encore pris en compte) // On peut s'attendre a 30 entrees par fichier dicom présent sur le CD-ROM - // Remarque : il faudra se pencher sur le pb de la creation du DICOMDIR lorsqu'on voudra + // REMARQUE : il faudra se pencher sur le pb de la creation du DICOMDIR lorsqu'on voudra // exporter des images lisibles par les consoles cliniques // et pas seulement importables dans e-film. - #ifdef __GNUC__ #include #define guint16 uint16_t @@ -70,14 +72,6 @@ typedef unsigned int guint32; #define GDCM_EXPORT #endif - -// -// ---------------------------------------------------- gdcmDictEntry -// -// c'est une ligne du Dictionnaire Dicom -// - - //////////////////////////////////////////////////////////////////////////// // Tag based hash tables. // We shall use as keys the strings (as the C++ type) obtained by @@ -89,6 +83,7 @@ typedef unsigned int guint32; // gdcmDictEntry::TranslateToKey for this conversion function. typedef string TagKey; +typedef string TagName; class GDCM_EXPORT gdcmDictEntry { private: @@ -116,73 +111,54 @@ private: // DcmDictRangeRestriction elementRestriction; // }; public: - - // fabrique une ligne de Dictionnaire Dicom à partir des parametres en entrée - - - gdcmDictEntry(guint16 group, guint16 element, + gdcmDictEntry(guint16 group, + guint16 element, string vr = "Unknown", string fourth = "Unknown", string name = "Unknown"); - // fabrique une 'clé' par concaténation du numGroupe et du numElement - static TagKey TranslateToKey(guint16 group, guint16 element); - guint16 GetGroup(void) { return group;}; + guint16 GetGroup(void) { return group; }; guint16 GetElement(void){return element;}; - string GetVR(void) {return vr; }; + string GetVR(void) {return vr; }; void SetVR(string); + void SetKey(string k){ key = k; } bool IsVrUnknown(void); string GetFourth(void) {return fourth;}; - string GetName(void) {return name;}; - string GetKey(void) {return key;}; + string GetName(void) {return name; }; + string GetKey(void) {return key; }; }; -// -// ---------------------------------------------------- gdcmDict -// -// c'est le Dictionnaire Dicom -// - - //////////////////////////////////////////////////////////////////////////// // 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 TagHT; - // Table de Hachage (group,Elem) --> ligne du Dictionnaire Dicom - -typedef map TagHT; +typedef map TagKeyHT; +typedef map TagNameHT; class GDCM_EXPORT gdcmDict { string name; string filename; - TagHT entries; + TagKeyHT KeyHt; // Both accesses with a TagKey or with a + TagNameHT NameHt; // TagName are required. public: - // rempli le Dictionnaire Dicom à partir d'un fichier texte - gdcmDict(const char* FileName); // Read Dict from disk - - // TODO Swig int AppendEntry(gdcmDictEntry* NewEntry); - - // renvoie une ligne de Dictionnaire Dicom à partir de (numGroup, numElement) - gdcmDictEntry * GetTag(guint32 group, guint32 element); + gdcmDict(const char* FileName); // Reads Dict from ascii file + int AddNewEntry (gdcmDictEntry* NewEntry); + int ReplaceEntry(gdcmDictEntry* NewEntry); + int RemoveEntry (TagKey key); + int RemoveEntry (guint16 group, guint16 element); + gdcmDictEntry * GetTagByKey(guint16 group, guint16 element); + gdcmDictEntry * GetTagByName(TagName name); void Print(ostream&); - TagHT & GetEntries(void) { return entries; } + void PrintByKey(ostream&); + void PrintByName(ostream&); + TagKeyHT & GetEntries(void) { return KeyHt; } }; -// -// ---------------------------------------------------- gdcmDictSet -// -// Ensemble de Dictionnaires Dicom (le public + 'des' privés) -// Au cas ou l'on traiterait un jour les 'dictionnaires privés' -// - pratiquement un par constructeur, par machine, et par version du logiciel - -// -// - //////////////////////////////////////////////////////////////////////////// // Container for managing a set of loaded dictionaries. Sharing dictionaries // should avoid : @@ -211,6 +187,7 @@ public: // // Question : ne faudra-t-il pas mettre LE dictionnaire DICOM dans un Directory // et les eventuels 'dictionnaires prives' dans un autre? + // (pour eviter a un utilisateur mal dégourdi de tout saccager ?) // int LoadDicomV3Dict(void); void Print(ostream&); @@ -218,25 +195,9 @@ public: gdcmDict* GetDefaultPublicDict(void); }; - -// -// ---------------------------------------------------- ElValue -// -// C'est un Element Dicom -// (ce qu'on a trouve dans l'entete de l'image -// + ce qu'on est allé chercher dans le Dictionnaire Dicom) -// - -// QUESTION: -// -// Ne faudrait-il pas trouver un autre nom, qui preterait moins à confusion? -// ElValue n'EST PAS la 'valeur d'un Element', mais la reunion d'infos -// trouvees dans l'Entete" du fichier ET dans le Dictionnaire -// - +/////////////////////////////////////////////////////////////////////////// // 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 { private: gdcmDictEntry *entry; @@ -245,37 +206,39 @@ private: // elements happen to be implicit. Flag them here // since we can't use the entry->vr without breaking // the underlying dictionary. - // Might prove of some interest (see _ID_DCM_ELEM) - // int Swap; public: - string value; // used to be char * valeurElem + string value; size_t Offset; // Offset from the begining of file for direct user access + ElValue(gdcmDictEntry*); void SetDictEntry(gdcmDictEntry *NewEntry) { entry = NewEntry; }; - bool IsVrUnknown(void) { return entry->IsVrUnknown(); }; - void SetLength(guint32 l){ LgrElem = l; }; - void SetValue(string val){ value = val; }; - void SetOffset(size_t of){ Offset = of; }; void SetImplicitVr(void) { ImplicitVr = true; }; bool IsImplicitVr(void) { return ImplicitVr; }; - void SetVR(string); - string GetVR(void); - string GetValue(void) { return value; }; - guint32 GetLength(void) { return LgrElem; }; - size_t GetOffset(void) { return Offset; }; - guint16 GetGroup(void) { return entry->GetGroup(); }; - guint16 GetElement(void) { return entry->GetElement(); }; - string GetKey(void) { return entry->GetKey(); }; - string GetName(void) { return entry->GetName();}; -}; + + guint16 GetGroup(void) { return entry->GetGroup(); }; + guint16 GetElement(void) { return entry->GetElement();}; + string GetKey(void) { return entry->GetKey(); }; + string GetName(void) { return entry->GetName(); }; + string GetVR(void) { return entry->GetVR(); }; + void SetVR(string v) { entry->SetVR(v); }; + void SetLength(guint32 l){ LgrElem = l; }; + guint32 GetLength(void) { return LgrElem; }; + + // Question : SetLength est public + // (sinon, on ne pourrait pas l'appeler dans ElValSet) + // alors que *personne* ne devrait s'en servir ! + // c'est *forcément* la lgr de la string 'value', non? + void SetValue(string val){ value = val; }; + string GetValue(void) { return value;}; + + void SetOffset(size_t of){ Offset = of; }; + size_t GetOffset(void) { return Offset;}; + // Question : SetOffset est public ... + // Quel utilisateur serait ammené à modifier l'Offset ? +}; -// -// ---------------------------------------------------- ElValSet -// -// ... un ensemble d'Elements Dicom -// //////////////////////////////////////////////////////////////////////////// // Container for a set of successfully parsed ElValues. @@ -283,30 +246,33 @@ typedef map TagElValueHT; typedef map TagElValueNameHT; class GDCM_EXPORT ElValSet { - // We need both accesses with a TagKey and the Dictentry.Name - TagElValueHT tagHt; - TagElValueNameHT NameHt; -public: - void Add(ElValue*); + TagElValueHT tagHt; // Both accesses with a TagKey or with a + TagElValueNameHT NameHt; // the DictEntry.Name are required. +public: + void Add(ElValue*); void Print(ostream &); void PrintByName(ostream &); + int Write(FILE *fp); ElValue* GetElementByNumber(guint32 group, guint32 element); ElValue* GetElementByName (string); string GetElValueByNumber(guint32 group, guint32 element); string GetElValueByName (string); - TagElValueHT & GetTagHt(void); -}; - + + TagElValueHT & GetTagHt(void); + + int SetElValueByNumber(string content, guint32 group, guint32 element); + int SetElValueByName (string content, string TagName); + + int SetElValueLengthByNumber(guint32 l, guint32 group, guint32 element); + int SetElValueLengthByName (guint32 l, string TagName); -// -// ---------------------------------------------------- gdcmHeader -// -// C'est le Dicom Header d'une image donnée -// (tous les elements Dicom qui la composent -// + des info 'de service') -// +}; //////////////////////////////////////////////////////////////////////////// +// The purpous of an instance of gdcmHeader is to act as a container of +// all the elements and their corresponding values (and additionaly the +// corresponding DICOM dictionary entry) of the header of a DICOM file. +// // The typical usage of instances of class gdcmHeader is to classify a set of // dicom files according to header information e.g. to create a file hierarchy // reflecting the Patient/Study/Serie informations, or extracting a given @@ -317,19 +283,17 @@ public: // 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 VRHT; // Value Representation Hash Table - // Cette Table de Hachage ne devrait servir qu'a determiner - // si deux caractères correspondent à une VR existante ? +typedef map VRHT; // Value Representation Hash Table class GDCM_EXPORT gdcmHeader { void SkipBytes(guint32); private: static VRHT *dicom_vr; // Dictionaries of data elements: + static gdcmDictSet* Dicts; // global dictionary container gdcmDict* RefPubDict; // public dictionary gdcmDict* RefShaDict; // shadow dictionary (optional) @@ -338,17 +302,13 @@ private: ElValSet ShaElVals; // parsed with Shadow Dictionary string filename; // refering underlying file FILE * fp; - // 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; // Ne faudrait-il pas une indication sur la presence ou non // du 'groupe des pixels' dans l'entete? // (voir pb du DICOMDIR) - // Swap code (little, big, big-bad endian): this code is not fixed + // Swap code (little, big, bad-big, bad-little endian): this code is not fixed // during parsing.FIXME sw should be an enum e.g. //enum EndianType { //LittleEndian, @@ -357,7 +317,7 @@ private: //BadBigEndian}; int sw; - // Only the elements whose size are below this bound shall be loaded. + // Only the elements whose size is below this bound will be loaded. // By default, this upper bound is limited to 1024 (which looks reasonable // when one considers the definition of the various VR contents). guint32 MaxSizeLoadElementValue; @@ -366,16 +326,26 @@ private: guint32 ReadInt32(void); guint16 SwapShort(guint16); guint32 SwapLong(guint32); + guint32 FindLengthOB(void); void Initialise(void); void CheckSwap(void); + void InitVRDict(void); + void SwitchSwapToBigEndian(void); + void AddAndDefaultElements(void); + void SetMaxSizeLoadElementValue(long); + + gdcmDictEntry * GetDictEntryByKey(guint16, guint16); + gdcmDictEntry * GetDictEntryByName(string name); + + // ElValue related utilities + ElValue * ReadNextElement(void); + ElValue * NewElValueByKey(guint16 group, guint16 element); + ElValue * NewElValueByName(string name); void FindLength(ElValue *); - guint32 FindLengthOB(void); void FindVR(ElValue *); void LoadElementValue(ElValue *); void LoadElementValueSafe(ElValue *); void SkipElementValue(ElValue *); - void InitVRDict(void); - void SwitchSwapToBigEndian(void); void FixFoundLength(ElValue*, guint32); bool IsAnInteger(ElValue *); @@ -387,17 +357,7 @@ private: bool IsJPEGExtendedProcess2_4TransferSyntax(void); bool IsJPEGExtendedProcess3_5TransferSyntax(void); bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void); -// -// Euhhhhhhh -// Il y en a encore DIX-SEPT, comme ça. -// Il faudrait trouver qq chose + rusé ... -// - - - - void SetMaxSizeLoadElementValue(long); - ElValue * ReadNextElement(void); - gdcmDictEntry * IsInDicts(guint32, guint32); + protected: enum FileType { Unknown = 0, @@ -411,8 +371,10 @@ protected: int anonymize(ostream&); // FIXME : anonymize should be a friend ? public: void LoadElements(void); - virtual void ParseHeader(void); - gdcmHeader(const char* filename); + virtual void ParseHeader(bool exception_on_error = false) + throw(gdcmFormatError); + gdcmHeader(const char *filename, bool exception_on_error = false) + throw(gdcmFileError); virtual ~gdcmHeader(); size_t GetPixelOffset(void); @@ -420,14 +382,14 @@ public: int GetSwapCode(void) { return sw; } // TODO Swig int SetPubDict(string filename); - // When some proprietary shadow groups are disclosed, we can set - // up an additional specific dictionary to access extra information. + // When some proprietary shadow groups are disclosed, we can set up + // an additional specific dictionary to access extra information. // TODO Swig int SetShaDict(string filename); // Retrieve all potentially available tag [tag = (group, element)] names - // from the standard (or public) dictionary. Typical usage: enable the + // 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. + // or selecting. list * GetPubTagNames(void); map > * GetPubTagNamesByCategory(void); // Get the element values themselves: @@ -436,8 +398,8 @@ public: string GetPubElValByNumber(guint16 group, guint16 element); // 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). + // to convert the string typed content to caller's native type + // (think of C/C++ vs Python). string GetPubElValRepByName(string TagName); string GetPubElValRepByNumber(guint16 group, guint16 element); @@ -461,37 +423,48 @@ public: 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 SetShaElValByName(string content, string ShadowTagName); - // TODO Swig int SetShaElValByNumber(string content, guint16 group, guint16 element); + int SetPubElValByName(string content, string TagName); + int SetPubElValByNumber(string content, guint16 group, guint16 element); + int SetShaElValByName(string content, string ShadowTagName); + int SetShaElValByNumber(string content, guint16 group, guint16 element); - // TODO Swig int GetSwapCode(); + ElValSet GetPubElVals() { return(PubElVals); } }; // // ---------------------------------------------------- gdcmFile // // un fichier EST_UNE entete, ou A_UNE entete ? -// -// +// +// On dit 'EST_UNE' ... //////////////////////////////////////////////////////////////////////////// // 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. -////// QUESTION: this looks still like an open question wether the +////// QUESTION: this looks still like an open question whether the ////// relationship between a gdcmFile and gdcmHeader is of ////// type IS_A or HAS_A ! class GDCM_EXPORT gdcmFile: public gdcmHeader { private: + // QUESTION : + // Data pointe sur quoi? + // sur les Pixels lus? + // --> j'ajoute un champ public : Pixels + // (il faudra que l'utilisateur puisse modifier les pixels ?) + void* Data; int Parsed; // weather allready parsed string OrigFileName; // To avoid file overwrite public: + // je ne suis pas sur d'avoir compris *où* il serait légitime de ranger ca. + // on pourra tjs le deplacer, et mettre des accesseurs + void * Pixels; + size_t lgrTotale; + // Constructor dedicated to writing a new DICOMV3 part10 compliant // file (see SetFileName, SetDcmTag and Write) // TODO Swig gdcmFile(); @@ -511,7 +484,7 @@ public: // On writing purposes. When instance was created through // gdcmFile(string filename) then the filename argument MUST be different - // from the constructor's one (no overwriting aloud). + // from the constructor's one (no overwriting allowed). // TODO Swig int SetFileName(string filename); // Allocates necessary memory, copies the data (image[s]/volume[s]) to @@ -527,13 +500,34 @@ public: // Copies (at most MaxSize bytes) of data to caller's memory space. // Returns an error code on failure (if MaxSize is not big enough) - int PutImageDataHere(void* destination, size_t MaxSize ); + int GetImageDataIntoVector(void* destination, size_t MaxSize ); + + // Question : + // + // GetImageData et GetImageDataIntoVector + // Get et Put pour 2 fonctions qui font presque la meme chose :-( + // // Allocates ExpectedSize bytes of memory at this->Data and copies the // pointed data to it. + + // Question : + // Pourquoi dupliquer les pixels, alors qu'on les a deja en mémoire, + // et que Data (dans le gdcmHeader) est un pointeur ? + // TODO Swig int SetImageData(void * Data, size_t ExpectedSize); + // Push to disk. + // A NE PAS OUBLIER : que fait-on en cas de Transfert Syntax (dans l'entete) + // 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 + + int WriteRawData (string nomFichier); + int WriteDcm (string nomFichier); }; // @@ -555,3 +549,4 @@ public: //class gdcmMultiFrame : gdcmFile; +#endif // #ifndef GDCM_H