]> Creatis software - gdcm.git/commitdiff
Ajout de quelques Accesseurs pour la Transfert Syntax.
authorjpr <jpr>
Thu, 19 Dec 2002 17:51:42 +0000 (17:51 +0000)
committerjpr <jpr>
Thu, 19 Dec 2002 17:51:42 +0000 (17:51 +0000)
IsExplicitBigEndianTransfertSyntax IsJPEGSpectralSelectionTransfertSyntax, etc...
(Je ne suis pas sur que ce soit la bonne maniere dee proceder.
Il y en a VINGT-CING en tout,
J'ai craque au bout de 8 ...
Y a-t-il la possibilite de faire chose generalisable ?

Testing/TestHash.cxx
src/gdcm.h
src/gdcmFile.cxx
src/gdcmHeader.cxx

index f8d58bcc32fc129dc854b821f57e5727b8f34229..56cbdfcdfe16d6281bc92e157db99d6cc2188406 100644 (file)
@@ -6,19 +6,19 @@ int main()
 {
   typedef map<string, char*> dict;
   
-  dict current;
-       dict::iterator im = current.find("00380010");
-  current["00100010"] = "Patient Name";
-  current["7fe00010"] = "Pixel Data";
-  current["50000010"] = "Number of points";
-  current["00380010"] = "Admission ID";
+  dict tb1;
+  dict::iterator im = tb1.find("00380010");
+  tb1["00100010"] = "Patient Name";
+  tb1["7fe00010"] = "Pixel Data";
+  tb1["50000010"] = "Number of points";
+  tb1["00380010"] = "Admission ID";
 
        cout << "Traversal of dictionary (note the proper ordering on key)." << endl;
-       for ( dict::iterator im = current.begin(); im != current.end(); ++im )
+       for ( dict::iterator im = tb1.begin(); im != tb1.end(); ++im )
                cout << "   \"" << im->first << "\" = " << im->second << endl;
        cout << "End of dictionary." << endl;
 
        cout << "Find request on key 00380010" << endl;
-       im = current.find("00380010");
+       im = tb1.find("00380010");
        cout << "   \"" << im->first << "\" = " << im->second << endl;
 }
index c8bf4d046deaff68b79fe0ae34a51283a4748700..4bdef369ecc046d76f6d1cdecd32b3dcd33b19bd 100644 (file)
@@ -61,7 +61,7 @@ using namespace std;  // string type lives in the std namespace on VC++
 
 #ifdef _MSC_VER 
 typedef  unsigned short guint16;
-typedef  unsigned int guint32;
+typedef  unsigned int   guint32;
 #endif
 
 #ifdef _MSC_VER
@@ -227,6 +227,12 @@ public:
 //     + 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)
@@ -272,7 +278,7 @@ public:
 //
 
 ////////////////////////////////////////////////////////////////////////////
-// Container for a set of succefully parsed ElValues.
+// Container for a set of successfully parsed ElValues.
 typedef map<TagKey, ElValue*> TagElValueHT;
 typedef map<string, ElValue*> TagElValueNameHT;
 
@@ -285,9 +291,9 @@ public:
        void Print(ostream &);
        void PrintByName(ostream &);
        ElValue* GetElementByNumber(guint32 group, guint32 element);
-       ElValue* GetElementByName(string);
-       string GetElValueByNumber(guint32 group, guint32 element);
-       string GetElValueByName(string);
+       ElValue* GetElementByName  (string);
+       string   GetElValueByNumber(guint32 group, guint32 element);
+       string   GetElValueByName  (string);
        TagElValueHT & GetTagHt(void);
 };
 
@@ -338,6 +344,9 @@ private:
        // 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
        // during parsing.FIXME sw should be an enum e.g.
@@ -369,7 +378,23 @@ private:
        void SwitchSwapToBigEndian(void);
        void FixFoundLength(ElValue*, guint32);
        bool IsAnInteger(ElValue *);
-       bool IsBigEndianTransferSyntax(void);
+       
+       bool IsImplicitVRLittleEndianTransferSyntax(void);
+       bool IsExplicitVRLittleEndianTransferSyntax(void);
+       bool IsDeflatedExplicitVRLittleEndianTransferSyntax(void);
+       bool IsExplicitVRBigEndianTransferSyntax(void);
+       bool IsJPEGBaseLineProcess1TransferSyntax(void);
+       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);
@@ -460,7 +485,7 @@ public:
 //////           relationship between a gdcmFile and gdcmHeader is of
 //////           type IS_A or HAS_A !
 
-class GDCM_EXPORT gdcmFile: gdcmHeader
+class GDCM_EXPORT gdcmFile: public gdcmHeader
 {
 private:
        void* Data;
@@ -491,11 +516,13 @@ public:
 
        // Allocates necessary memory, copies the data (image[s]/volume[s]) to
        // newly allocated zone and return a pointer to it:
-       // TODO Swig void * GetImageData();
+       
+        void * GetImageData();
        
        // Returns size (in bytes) of required memory to contain data
        // represented in this file.
-       // TODO Swig size_t GetImageDataSize();
+       
+       size_t GetImageDataSize();
        
        // Copies (at most MaxSize bytes) of data to caller's memory space.
        // Returns an error code on failure (if MaxSize is not big enough)
index d5a85294a273a84c6cbeeb003b3f20e322339962..031b26554ac0441ac30140b462c36d20a3a81a7f 100644 (file)
@@ -2,8 +2,272 @@
 
 #include "gdcm.h"
 
+static void _Swap(void* im, int swap, int lgr, int nb);
+
+/////////////////////////////////////////////////////////////////
+/**
+ * \ingroup   gdcmFile
+ * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant
+ * \file (see SetFileName, SetDcmTag and Write)
+ * \Opens (in read only and when possible) an existing file and checks
+ * \for DICOM compliance. Returns NULL on failure.
+ * \Note: the in-memory representation of all available tags found in
+ * \the DICOM header is post-poned to first header information access.
+ * \This avoid a double parsing of public part of the header when
+ * \one sets an a posteriori shadow dictionary (efficiency can be
+ * \seen as a side effect).   
+ *
+ * @param 
+ *
+ * @return     
+ */
+
+/////////////////////////////////////////////////////////////////
+/**
+ * \ingroup   gdcmFile
+ * \brief    constructeur 
+ *
+ * @param 
+ *
+ * @return
+ */
 gdcmFile::gdcmFile(string & filename)
        :gdcmHeader(filename.c_str())
 {
+}
+
+
+/////////////////////////////////////////////////////////////////
+/**
+ * \ingroup   gdcmFile
+ * \brief     Renvoie la longueur A ALLOUER pour recevoir les pixels de l'image
+ * \           ou DES images dans le cas d'un multiframe
+ * \           ATTENTION : il ne s'agit PAS de la lgr du groupe des Pixels     
+ * \           (dans le cas d'images compressees, elle n'a pas de sens).
+ *
+ * @param void Rien en entree
+ *
+ * @return     longueur a allouer 
+ */
+
+size_t gdcmFile::GetImageDataSize(void) {
+       int nbLignes, nbCol, nbFrames, nb;
+       string str_nbFrames, str_nb;
+       // Nombre de Lignes     
+       nbLignes=atoi(gdcmHeader::GetPubElValByNumber(0x0028,0x0010).c_str());
+       // Nombre de Colonnes   
+       nbCol   =atoi(gdcmHeader::GetPubElValByNumber(0x0028,0x0011).c_str());
+
+       // Nombre de Frames     
+       str_nbFrames=gdcmHeader::GetPubElValByNumber(0x0028,0x0008);
+       
+       if (str_nbFrames == "UNFOUND" ) {
+               nbFrames = 1;
+       } else {
+               nbFrames = atoi(str_nbFrames.c_str() );
+       }
        
+       // Nombre de Bits Alloues pour le stockage d'un Pixel   
+       str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
+
+       if (str_nb == "UNFOUND" ) {
+               nb = 16;
+       } else {
+               nb = atoi(str_nb.c_str() );
+       }
+
+       size_t lgrTotale = nbFrames*nbLignes*nbCol*(nb/8);
+       return (lgrTotale);
+
 }
+
+/////////////////////////////////////////////////////////////////
+/**
+ * \ingroup   gdcmFile
+ * \brief amene en mémoire les Pixels d'une image NON COMPRESSEE
+ * \Aucun test n'est fait pour le moment sur le caractere compresse ou non de l'image
+ *
+ * @param rien
+ *
+ * @return     Pointeur sur la zone mémoire contenant les Pixels lus
+ */
+
+void * gdcmFile::GetImageData (void) {
+       
+       char* Pixels;
+       int nbLignes, nbCol;
+
+       int nbFrames, nb, nbu, highBit, signe;
+       string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
+       
+       unsigned short int mask = 0xffff;
+               
+       // Nombre de Lignes     
+       nbLignes=atoi(GetPubElValByNumber(0x0028,0x0010).c_str());
+       // Nombre de Colonnes   
+       nbCol   =atoi(GetPubElValByNumber(0x0028,0x0011).c_str());
+
+       // Nombre de Frames     
+       str_nbFrames=GetPubElValByNumber(0x0028,0x0008);
+
+       
+       if (str_nbFrames == "UNFOUND" ) {
+               nbFrames = 1;
+       } else {
+               nbFrames = atoi(str_nbFrames.c_str() );
+       }
+       
+       // Nombre de Bits Alloues       
+       str_nb=GetPubElValByNumber(0x0028,0x0100);
+
+       if (str_nb == "UNFOUND" ) {
+               nb = 16;
+       } else {
+               nb = atoi(str_nb.c_str() );
+       }
+       
+       // Nombre de Bits Utilises      
+       str_nbu=GetPubElValByNumber(0x0028,0x0101);
+
+       if (str_nbu == "UNFOUND" ) {
+               nbu = nb;
+       } else {
+               nbu = atoi(str_nbu.c_str() );
+       }       
+       
+       // Position du Bit de Poids Fort        
+       str_highBit=GetPubElValByNumber(0x0028,0x0102);
+
+       if (str_highBit == "UNFOUND" ) {
+               highBit = nb - 1;
+       } else {
+               highBit = atoi(str_highBit.c_str() );
+       }
+               
+       // Signe des Pixels 
+       str_signe=GetPubElValByNumber(0x0028,0x0103);
+
+       if (str_signe == "UNFOUND" ) {
+               signe = 1;
+       } else {
+               signe = atoi(str_signe.c_str() );
+       }
+       
+       // Longueur en Octets des Pixels a lire
+       size_t lgrTotale = nbFrames*nbLignes*nbCol*(nb/8);
+       
+       //Pixels = (char *) g_malloc(lgrTotale);
+       Pixels = (char *) malloc(lgrTotale);
+       
+       GetPixels(lgrTotale, Pixels);
+
+       // On remet les Octets dans le bon ordre si besoin est
+       if (nb != 8) {
+               //int sw = GetSwapCode();
+
+       //      _Swap (Pixels, sw, lgrTotale, nb);                                               // A REMETTRE
+       }
+       
+       // On remet les Bits des Octets dans le bon ordre si besoin est
+       //
+       // ATTENTION :  Jamais confronté a des pixels stockes sur 32 bits 
+       //                      avec moins de 32 bits utilises
+       //                      et dont le bit de poids fort ne serait pas la ou on l'attend ...
+       //                      --> ne marchera pas dans ce cas 
+       if (nbu!=nb){
+               mask = mask >> (nb-nbu);
+               int l=(int)lgrTotale/(nb/8);
+               unsigned short *deb = (unsigned short *)Pixels;
+               for(int i=0;i<l;i++) {
+                               *deb = (*deb >> (nbu-highBit-1)) & mask;
+                               deb ++;
+               }
+       }
+               
+       printf ("on est sorti\n");
+       
+       // VOIR s'il ne faudrait pas l'affecter à un champ du dcmHeader
+       
+       return (Pixels);                
+}
+
+
+//
+// Je laisse le code integral, au cas ça puisse etre reutilise ailleurs
+//
+
+static void _Swap(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) non autorisee : %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("valeur de SWAP (32 bits) non autorisee : %d\n", swap);
+       } 
+return;
+}
+
+
+
index 3107da2ff3bf31765a6245aedcf5dcc9181e8854..dd49a4593625189a8cc13dd27d70fca35f55f6a4 100644 (file)
@@ -243,6 +243,8 @@ void gdcmHeader::GetPixels(size_t lgrTotale, void* Pixels) {
        fread(Pixels, 1, lgrTotale, fp);
 }
 
+
+
 /**
  * \ingroup   gdcmHeader
  * \brief     Find the value representation of the current tag.
@@ -254,6 +256,11 @@ void gdcmHeader::GetPixels(size_t lgrTotale, void* Pixels) {
  *                       effectivement lue
  * @return               longueur retenue pour le champ 
  */
+// -->
+// --> Oops
+// --> C'etait la description de quoi, ca?
+// -->
 
 void gdcmHeader::FindVR( ElValue *ElVal) {
        if (filetype != ExplicitVR)
@@ -334,11 +341,66 @@ void gdcmHeader::FindVR( ElValue *ElVal) {
 /**
  * \ingroup gdcmHeader
  * \brief   Determines if the Transfer Syntax was allready encountered
- *          and if it corresponds to a Big Endian one.
+ *          and if it corresponds to a ImplicitVRLittleEndian one.
+ *
+ * @return  True when ImplicitVRLittleEndian found. False in all other cases.
+ */
+bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2" )
+               return true;
+       return false;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready encountered
+ *          and if it corresponds to a ExplicitVRLittleEndian one.
+ *
+ * @return  True when ExplicitVRLittleEndian found. False in all other cases.
+ */
+bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2.1" )
+               return true;
+       return false;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready encountered
+ *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
+ *
+ * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
+ */
+bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       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 allready 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::IsBigEndianTransferSyntax(void) {
+bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
        ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
        if ( !Element )
                return false;
@@ -349,11 +411,92 @@ bool gdcmHeader::IsBigEndianTransferSyntax(void) {
        return false;
 }
 
-void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoudLength) {
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready encountered
+ *          and if it corresponds to a JPEGBaseLineProcess1 one.
+ *
+ * @return  True when JPEGBaseLineProcess1found. False in all other cases.
+ */
+bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2.4.50" )
+               return true;
+       return false;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready 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) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2.4.51" )
+               return true;
+       return false;
+}
+
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready encountered
+ *          and if it corresponds to a JPEGExtendeProcess3-5 one.
+ *
+ * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
+ */
+bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2.4.52" )
+               return true;
+       return false;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief   Determines if the Transfer Syntax was allready encountered
+ *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
+ *
+ * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all other cases.
+ */
+bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
+       ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
+       if ( !Element )
+               return false;
+       LoadElementValueSafe(Element);
+       string Transfer = Element->GetValue();
+       if ( Transfer == "1.2.840.10008.1.2.4.53" )
+               return true;
+       return false;
+}
+
+//
+// Euhhhhhhh
+// Il y en a encore DIX-SEPT, comme ça.
+// Il faudrait trouver qq chose + rusé ...
+//
+
+
+void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoundLength) {
        // Heuristic: a final fix.
-       if ( FoudLength == 0xffffffff)
-               FoudLength = 0;
-       ElVal->SetLength(FoudLength);
+       if ( FoundLength == 0xffffffff)
+               FoundLength = 0;
+       ElVal->SetLength(FoundLength);
 }
 
 guint32 gdcmHeader::FindLengthOB(void) {
@@ -442,7 +585,7 @@ void gdcmHeader::FindLength(ElValue * ElVal) {
                // hands on a big endian encoded file: we switch the swap code to
                // big endian and proceed...
                if ( (element  == 0x000) && (length16 == 0x0400) ) {
-                       if ( ! IsBigEndianTransferSyntax() )
+                       if ( ! IsExplicitVRBigEndianTransferSyntax() )
                                throw Error::FileReadError(fp, "gdcmHeader::FindLength");
                        length16 = 4;
                        SwitchSwapToBigEndian();
@@ -628,6 +771,11 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) {
        }
        
        // FIXME The exact size should be length if we move to strings or whatever
+       
+       //
+       // QUESTION : y a-t-il une raison pour ne pas utiliser g_malloc ici ?
+       //
+       
        char* NewValue = (char*)malloc(length+1);
        if( !NewValue) {
                dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");