]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
src/gdcmHeader.cxx many addons of low level methods -- Frog
[gdcm.git] / src / gdcmHeader.cxx
1 #include "gdcmlib.h"
2 extern "C" {
3 #include "glib.h"
4 }
5 #include <stdio.h>
6 // For nthos:
7 #ifdef _MSC_VER
8 #include <winsock.h>
9 #else
10 #include <netinet/in.h>
11 #endif
12 #include <map>
13
14 #define LGR_ENTETE_A_LIRE 256 // on ne lit plus que le debut
15 #define DEBUG 1
16
17 //FIXME: this looks dirty to me...
18 #define str2num(str, typeNum) *((typeNum *)(str))
19
20 VRHT * gdcmHeader::dicom_vr = (VRHT*)0;
21
22 gdcmHeader::gdcmHeader () {
23         if (!gdcmHeader::dicom_vr)
24                 InitVRDict();
25         bool grPixelTrouve = false;
26         PixelPosition = (size_t)0;
27         PixelsTrouves = false;
28 }
29
30 void gdcmHeader::InitVRDict (void) {
31         if (dicom_vr && DEBUG) {
32                 printf ("InitVRDict : VR dictionary allready set\n");
33                 return;
34         }
35         VRHT *vr = new VRHT;
36         (*vr)["AE"] = "Application Entity";       // 16 car max
37         (*vr)["AS"] = "Age String";               // 4 car fixe
38         (*vr)["AT"] = "Attribute Tag";            // 2 unsigned short int
39         (*vr)["CS"] = "Code String";              // 16 car max
40         (*vr)["DA"] = "Date";                     // 8 car fixe
41         (*vr)["DS"] = "Decimal String";           // Decimal codé Binaire 16 max
42         (*vr)["DT"] = "Date Time";                // 26 car max
43         (*vr)["FL"] = "Floating Point Single";    // 4 octets IEEE 754:1985
44         (*vr)["FD"] = "Floating Point Double";    // 8 octets IEEE 754:1985
45         (*vr)["IS"] = "Integer String";           // en format externe 12 max
46         (*vr)["LO"] = "Long String";              // 64 octets max
47         (*vr)["LT"] = "Long Text";                // 10240 max
48         (*vr)["OB"] = "Other Byte String";
49         (*vr)["OW"] = "Other Word String";
50         (*vr)["PN"] = "Person Name";
51         (*vr)["SH"] = "Short String";             // 16 car max
52         (*vr)["SL"] = "Signed Long";
53         (*vr)["SQ"] = "Sequence of Items";        // Not Applicable
54         (*vr)["SS"] = "Signed Short";             // 2 octets
55         (*vr)["ST"] = "Short Text";               // 1024 car max
56         (*vr)["TM"] = "Time";                     // 16 car max
57         (*vr)["UI"] = "Unique Identifier";        // 64 car max
58         (*vr)["UN"] = "Unknown";
59         (*vr)["UT"] = "Unlimited Text";           //  2 puissance 32 -1 car max
60         (*vr)["UL"] = "Unsigned Long ";           // 4 octets fixe
61         (*vr)["US"] = "Unsigned Short ";          // 2 octets fixe
62    dicom_vr = vr;       
63 }
64
65 /**
66  * \ingroup gdcmHeader
67  * \brief   La seule maniere sure que l'on aie pour determiner 
68  *          si on est en   LITTLE_ENDIAN,       BIG-ENDIAN, 
69  *          BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN
70  *          est de trouver l'element qui donne la longueur d'un 'GROUP'
71  *          (on sait que la longueur de cet element vaut 0x00000004)
72  *          et de regarder comment cette longueur est codee en memoire  
73  *          
74  *          Le probleme vient de ce que parfois, il n'y en a pas ...
75  *          
76  *          On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre.
77  *          (Ce qui est la norme -pas respectee- depuis ACR-NEMA)
78  *          Si ce n'est pas le cas, on ne peut rien faire.
79  *
80  *          (il faudrait avoir des fonctions auxquelles 
81  *          on passe le code Swap en parametre, pour faire des essais 'manuels')
82  */
83 void gdcmHeader::CheckSwap()
84 {
85         guint32  s;
86         guint32  x=4;  // x : pour ntohs
87         bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
88          
89         int lgrLue;
90         char * entCur;
91         char deb[LGR_ENTETE_A_LIRE];
92          
93         // On teste le processeur
94         if (x==ntohs(x)) {
95                 net2host = true;
96         } else {
97                 net2host = false;
98         }
99         
100         // On commence par verifier si c'est du DICOM 'actuel'
101         //                                      -------------
102         lgrLue = fread(deb,1,LGR_ENTETE_A_LIRE, fp);
103         
104         entCur = deb+128;
105         if(memcmp(entCur, "DICM", (size_t)4) == 0) {
106                 filetype = TrueDicom;
107                 if (DEBUG) printf ("_IdDcmCheckSwap : C est du DICOM actuel \n");
108         } else {
109                 filetype = Unknown;
110                 if (DEBUG) printf ("_IdDcmCheckSwap : Ce n'est PAS du DICOM actuel\n");
111         }
112
113         if(filetype == TrueDicom) {
114                 // on saute le File Preamble (souvent a ZERO) : 128 Octets
115                 // + le DICM (4), et le (0002, 0000) soit 4 (136 = 128 + 4 + 4)
116                 entCur = deb+136;
117                 if(memcmp(entCur, "UL", (size_t)2) == 0) {
118                         // les 2 premiers octets de la lgr peuvent valoir UL --> Explicit VR
119                         filetype = ExplicitVR;
120                         if (DEBUG)  printf ("_IdDcmCheckSwap : Explicit VR\n");
121                 } else {
122                         filetype = ImplicitVR;
123                         if (DEBUG)  printf ("_IdDcmCheckSwap : PAS Explicit VR\n");
124                 }
125                 
126                 if (net2host) { // HostByteOrder is different from NetworkByteOrder
127                         sw = 0;    // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
128                         if (DEBUG) printf("HostByteOrder = NetworkByteOrder\n");
129                 } else {    /* on est sur une Sun ou une SGI */
130                         sw = 4321;
131                         if (DEBUG) printf("HostByteOrder != NetworkByteOrder\n");
132                 }
133                 
134                 rewind(fp);
135                 fseek (fp, 132L, SEEK_SET); //On se positionne sur le debut des info
136                 offsetCourant=132;
137         } // End of TrueDicom
138
139         // Pas du TrueDicom : permiere hypothese c'est de l'ACR 'propre', auquel
140         // cas la lgr du premier element du groupe est FORCEMENT 4
141         entCur=deb + 4;
142         s=str2num(entCur,int);
143         
144         switch (s) {
145         case 0x00040000 :
146                 sw=3412; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
147                 filetype = ACR;
148                 break;
149         case 0x04000000 :
150                 sw=4321; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
151                 filetype = ACR;
152                 break;
153         case 0x00000400 :
154                 sw=2143; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
155                         filetype = ACR;
156                 break;
157         case 0x00000004 :
158                 sw=0;    if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
159                 filetype = ACR;
160                 break;
161         default :
162                 sw = -1;
163                 if (DEBUG) printf (" Pas trouve l info de Swap; On va parier\n");
164         }
165         if(sw!=-1) {
166                 rewind(fp);    // les info commencent au debut
167                 offsetCourant=0;
168                 return;
169         }
170
171         // Deuxieme hypothese : c'est de l'ACR 'pas propre' i.e. il manque
172         // la lgr du groupe
173         
174         // On n'a pas trouve l'info de swap.
175         // Si c'est du VRAI ACR NEMA et
176         //  * si on est sur une DEC ou un PC alors swap=0,
177         //  * si on est sur SUN ou SGI,      alors swap=4321
178         // Si c'est du RAW, ca degagera + tard
179         if (DEBUG) printf("On force la chance \n");
180         
181         if (x!=ntohs(x)) // HostByteOrder is different from NetworkByteOrder
182                 // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
183                 sw = 0;
184         else
185                 // on est sur Sun ou SGI
186                 sw = 4321;
187         rewind(fp);    // les info commencent au debut
188         offsetCourant=0;
189         return;
190 }
191
192 /**
193  * \ingroup gdcmHeader
194  * \brief   Pour les fichiers non TrueDicom, si le recognition
195  *          code (0008,0010) s'avere etre "ACR_LIBIDO", alors
196  *          valide la reconnaissance du fichier en positionnant
197  *          filetype.
198  */
199 void gdcmHeader::setAcrLibido() {
200         string RecCode;
201         
202         if ( filetype != TrueDicom) {
203                 printf("_setAcrLibido expects a presumably ACR file\n");
204                 // Recognition Code  --> n'existe plus en DICOM V3 ...
205                 RecCode = GetPubElValByNumber(0x0008, 0x0010);
206                 // FIXME NOW
207                 if (RecCode == "ACRNEMA_LIBIDO" ||
208                     RecCode == "CANRME_AILIBOD" )
209                         filetype = ACR_LIBIDO;
210                 else
211                         filetype = ACR;
212         }
213         return;
214 }
215
216 /**
217  * \ingroup   gdcmHeader
218  * \brief     recupere la longueur d'un champ DICOM.
219  *            Preconditions:
220  *            1/ le fichier doit deja avoir ete ouvert,
221  *            2/ CheckSwap() doit avoir ete appele
222  *            3/ la  partie 'group'  ainsi que la  partie 'elem' 
223  *               de l'acr_element doivent avoir ete lues.
224  *
225  *            ACR-NEMA : we allways get
226  *                 GroupNumber   (2 Octets) 
227  *                 ElementNumber (2 Octets) 
228  *                 ElementSize   (4 Octets)
229  *            DICOM en implicit Value Representation :
230  *                 GroupNumber   (2 Octets) 
231  *                 ElementNumber (2 Octets) 
232  *                 ElementSize   (4 Octets)
233  *
234  *            DICOM en explicit Value Representation :
235  *                 GroupNumber         (2 Octets) 
236  *                 ElementNumber       (2 Octets) 
237  *                 ValueRepresentation (2 Octets) 
238  *                 ElementSize         (2 Octets)
239  *
240  *            ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
241  *                 GroupNumber         (2 Octets) 
242  *                 ElementNumber       (2 Octets) 
243  *                 ValueRepresentation (2 Octets)
244  *                 zone reservee       (2 Octets) 
245  *                 ElementSize         (4 Octets)
246  *
247  * @param sw  code swap
248  * @param skippedLength  pointeur sur nombre d'octets que l'on a saute qd
249  *                       la lecture est finie
250  * @param longueurLue    pointeur sur longueur (en nombre d'octets) 
251  *                       effectivement lue
252  * @return               longueur retenue pour le champ 
253  */
254
255 // FIXME sw n'est plus un argument necessaire
256 long int gdcmHeader::RecupLgr(
257         ElValue *pleCourant,
258         int *skippedLength)
259 {
260         guint32 l_gr; 
261         unsigned short int l_gr_2;
262         int i;
263         char VR[5];
264         int lgrLue;
265         
266         //  FIX ME
267         //   ATTENTION : nbCode correspond au nombre d'elements dans la table
268         //               de type DICOM_VR. A nettoyer.
269         //
270         int nbCode=26;
271         
272         if (filetype == ExplicitVR) {
273                 lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
274                 VR[2]=0;
275                 
276                 // Warning: we believe this is explicit VR (Value Representation) because
277                 // we used a heuristic that found "UL" in the first tag. Alas this
278                 // doesn't guarantee that all the tags will be in explicit VR. In some
279                 // cases (see e-film filtered files) one finds implicit VR tags mixed
280                 // within an explicit VR file. Hence we make sure the present tag
281                 // is in explicit VR and try to fix things if it happens not to be
282                 // the case.
283
284                 // FIXME There should be only one occurence returned. Avoid the
285                 // first extraction by calling proper method.
286                 VRAtr FoundVR = dicom_vr->find(string(VR))->first;
287                 if (FoundVR.empty()) {
288                         pleCourant->SetVR(FoundVR);
289                 } else {
290                         
291                         // On est mal : implicit VR repere
292                         // mais ce n'est pas un code connu ...
293                         // On reconstitue la longueur
294                         
295                         if(DEBUG)
296                                 printf("IdDcmRecupLgr : Explicit VR, mais pas de code connu\n");
297                         memcpy(&l_gr, VR,(size_t)2);
298                         
299                         lgrLue=fread ( ((char*)&l_gr)+2, (size_t)2, (size_t)1, fp);
300                         
301                         l_gr = SWAP_LONG((guint32)l_gr);
302                         
303                         if(DEBUG)
304                                 printf("IdDcmRecupLgr : lgr deduite : %08x , %d\n",l_gr,l_gr);
305                         
306                         pleCourant->SetLgrLue(l_gr);
307                         if ( (int)l_gr == -1)
308                                 l_gr=0;
309                          
310                         *skippedLength = 4; 
311                         if (DEBUG)
312                                 printf(" 1 : lgr %08x (%d )skippedLength %d\n",
313                                        l_gr,l_gr, *skippedLength);
314                         return(l_gr);
315                 }
316                 
317                 // On repart dans la sequence 'sensee'
318                 
319                 if(DEBUG)
320                         printf("VR : [%01x , %01x] (%c%c) en position %d du tableau\n",
321                                 VR[0],VR[1],VR[0],VR[1],i);
322                 
323                 if ( (!memcmp( VR,"OB",(size_t)2 )) || 
324                      (!memcmp( VR,"OW",(size_t)2 )) || 
325                      (!memcmp( VR,"SQ",(size_t)2 )) ||
326                      (!memcmp( VR,"UN",(size_t)2 )) ) {
327                         
328                         // les 2 octets suivants sont reserves: on les saute
329                         if(DEBUG)
330                                 printf("IdDcmRecupLgr : les 2 octets suivants sont reserves\n");
331                         fseek(fp, 2L,SEEK_CUR);
332                         
333                         //on lit la lgr sur QUATRE octets
334                         lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
335                         l_gr = SWAP_LONG((guint32)l_gr);
336                         *skippedLength = 8;
337                 
338                 } else {
339                         //on lit la lgr sur DEUX octets
340                         lgrLue=fread (&l_gr_2, (size_t)2,(size_t)1, fp);
341                         
342                         if(sw) l_gr_2 = SWAP_SHORT((unsigned short)l_gr_2);
343                         
344                         pleCourant->SetLgrLue(l_gr_2);
345                         
346                         
347                         if ( l_gr_2 == 0xffff) {
348                                 l_gr = 0;
349                         } else {
350                                 l_gr = l_gr_2;
351                         }
352                         *skippedLength = 4;
353                 }
354         } else {
355                 // Explicit VR = 0
356                 //on lit la lgr sur QUATRE octets
357                 
358                 lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
359                 
360                 l_gr= SWAP_LONG((long)l_gr);
361                 *skippedLength = 4;
362         }
363         
364         pleCourant->SetLgrLue(l_gr);
365         
366         // Traitement des curiosites sur la longueur
367         
368         if ( (int)l_gr == 0xffffffff)
369                 l_gr=0; 
370         
371         if(!memcmp( VR,"SQ",(size_t)2 )) { // ca annonce une SEQUENCE d'items ?!
372                 l_gr=0;                         // on lira donc les items de la sequence 
373                 if (DEBUG) printf(" SQ trouve : lgr %d \n",l_gr);
374         }
375         
376         if (DEBUG)
377                 printf(" 2 : lgr %08x (%d) skippedLength %d\n",l_gr,l_gr, *skippedLength);
378         return(l_gr);
379 }
380
381 /**
382  * \ingroup gdcmHeader
383  * \brief   remet les octets dans un ordre compatible avec celui du processeur
384
385  * @return  longueur retenue pour le champ 
386  */
387 guint32 gdcmHeader::SWAP_LONG(guint32 a) {
388         // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
389         switch (sw) {
390         case 4321 :
391                 a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
392                       ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
393                 break;
394         
395         case 3412 :
396                 a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
397                 break;
398         
399         case 2143 :
400                 a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
401                 break;
402         default :
403                 printf("\n\n\n *******\n erreur code swap ?!?\n\n\n");
404                 a=0;
405         }
406         return(a);
407 }
408
409 /**
410  * \ingroup gdcmHeader
411  * \brief   remet les octets dans un ordre compatible avec celui du processeur
412
413  * @return  longueur retenue pour le champ 
414  */
415 short int gdcmHeader::SWAP_SHORT(short int a) {
416         if ( (sw==4321)  || (sw==2143) )
417                 a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
418         return (a);
419 }
420
421 /**
422  * \ingroup       gdcmHeader
423  * \brief         lit le dicom_element suivant.
424  *                      (le fichier doit deja avoir ete ouvert,
425  *                       _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele)
426  * @param e      ID_DCM_HDR  dans lequel effectuer la recherche.
427  * @param sw            code swap.
428  * @return              En cas de succes, 1 
429  *                      0 en cas d'echec.
430  */
431
432 ElValue * gdcmHeader::ReadNextElement(void) {
433         unsigned short g;
434         unsigned short n;
435         guint32 l;
436         long int posFich;
437         int skL;
438         size_t lgrLue;
439         //CLEANME DICOM_ELEMENTS *t;
440         ElValue * nouvDcmElem;
441         
442         if (DEBUG) printf(" ===> entree ds _IdDcmReadNextElement\n");
443                 
444         // FIXME la probabilte pour depasser sans s'en rendre compte
445         // est grande avec le test d'egalite' suivant !
446         if(offsetCourant == taille_fich) { // On a atteint la fin du fichier
447                 if (DEBUG) printf(" On a atteint la fin du fichier\n");
448                 return(NULL);
449         } else {
450                 if (DEBUG) {
451                         posFich = ftell(fp);
452                         printf("lgrFich %f positionDsFich %f offset courant %f\n", 
453                         (float)taille_fich,
454                         (float)posFich,
455                         (float)offsetCourant);
456                 }
457         } 
458         
459         // ------------------------- Lecture Num group : g
460         lgrLue=fread (&g, (size_t)2,(size_t)1, fp);
461         
462         if (feof(fp))  {
463                 if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n");
464                 return (NULL);
465         }
466         if (ferror(fp)){
467                 if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumGr\n");
468                 return (NULL);
469         }
470         
471         if (DEBUG) printf("_IdDcmReadNextElement : gr  %04x\n",g );
472         
473         if (sw) g= SWAP_SHORT(((short)g));
474         
475         //CLEANME nouvDcmElem->Gr=g;
476         //FIXME this might be usefull for detecting at parse time that
477         //something is screwy in the file
478         //e->__NumeroGroupePrecedent =g;
479         
480
481         // ------------------------- Lecture Num Elem : n
482         lgrLue=fread (&n, (size_t)2,(size_t)1, fp);
483         
484         if (feof(fp))  {
485                 if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n");
486                 return (NULL);
487         }
488         if (ferror(fp)){
489                 if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumElem\n");
490                 return (NULL);
491         }
492         
493         if (DEBUG) printf("_IdDcmReadNextElement :  num %04x\n",n );
494         
495         if(sw) n= SWAP_SHORT(((short)n));
496         //CLEANMEnouvDcmElem->Num=n;
497
498         // Find out if the tag we encountered is in the dictionaries:
499         DictEntry * NewTag = IsInDicts(g, n);
500         if (!NewTag)
501                 NewTag = new DictEntry(g, n, "Unknown", "Unknown");
502
503         nouvDcmElem = new ElValue(NewTag);
504         if (!nouvDcmElem) {
505                 printf("Echec alloc ElValue *nouvDcmElem\n");
506                 return(NULL);
507         }
508
509         // ------------------------- Lecture longueur element : l
510         
511         l = RecupLgr(nouvDcmElem, &skL);
512         
513         if(g==0xfffe) l=0;  // pour sauter les indicateurs de 'SQ'
514         
515         nouvDcmElem->LgrElem=l;
516         
517         if (DEBUG)
518                 if (n!=0)
519                         printf("_IdDcmReadNextElement : "
520                                " gr %04x\tnum %04x\tlong %08x (%d)\n", g,n,l,l);
521
522         // ------------------------- Lecture Valeur element 
523         
524         // FIXME The exact size should be l if we move to strings or whatever
525         // CLEAN ME NEWValue used to be nouvDcmElem->valeurElem
526         char* NewValue = (char*)g_malloc(l+1);
527         if(NewValue) {
528                 NewValue[l]= 0;
529         } else {
530                 if (DEBUG)
531                          printf(" IdDcmReadNextElement : echec Alloc valeurElem lgr : %d\n",l);
532                 return (NULL);
533         }
534         
535         // FIXME les elements trop long (seuil a fixer a la main) ne devraient
536         // pas etre charge's !!!! Voir TODO.
537         lgrLue=fread (NewValue, (size_t)l,(size_t)1, fp);
538         
539         offsetCourant +=  2 + 2 + skL; // gr +  num + lgr
540         nouvDcmElem->Offset = offsetCourant;
541         offsetCourant += l;            // debut elem suivant
542
543         // ------------------------- Doit-on le Swapper ?
544         
545         if ((n==0) && sw)  {  // n=0 : lgr du groupe : guint32
546                 *(guint32 *) NewValue = SWAP_LONG ((*(guint32 *) NewValue));  
547         } else {
548                 if(sw) {
549                         if ( (g/2)*2-g==0) { /* on ne teste pas les groupes impairs */
550                                 
551                                 if ((l==4)||(l==2)) {  // pour eviter de swapper les chaines 
552                                                             // de lgr 2 ou 4
553                                         if (DEBUG) 
554                                                 printf("Consultation Dictionary DICOM g %04x n %0xx l %d\n",
555                                                         g,n,l);
556                                         
557                                         // FIXME make reference to nouvDcmElem->GetTag
558                                         string VR = NewTag->GetVR();
559                                         if (   (VR == "UL") || (VR == "US")
560                                             || (VR == "SL") || (VR == "SS")
561                                             || (g == 0x0028 && ( n == 0x0005 || n == 0x0200) )) {
562                                                 // seuls (28,5) de vr RET et (28,200) sont des entiers
563                                                 // ... jusqu'a preuve du contraire
564                                                 
565                                                 if(l==4) { 
566                                                         *(guint32 *) NewValue =
567                                                             SWAP_LONG  ((*(guint32 *) NewValue)); 
568                                                 } else {
569                                                         if(l==2) 
570                                                     *(unsigned short *) NewValue =
571                                                         SWAP_SHORT ((*(unsigned short *)NewValue));
572                                                  }
573                                         }
574                                 } /* fin if l==2 ==4 */
575                         } /* fin if g pair */
576                 } /* fin sw */  
577         }
578         nouvDcmElem->value = NewValue;
579         SetAsidePixelData(nouvDcmElem);
580         return nouvDcmElem;
581 }
582
583 /**
584  * \ingroup gdcmHeader
585  * \brief   If we encountered the offset of the pixels in the file
586  *          (Pixel Data) then keep the info aside.
587  */
588 void gdcmHeader::SetAsidePixelData(ElValue* elem) {
589           /// FIXME this wall process is bizarre:
590           // on peut pas lire pixel data et pixel location puis
591           // a la fin de la lecture aller interpreter ce qui existe ?
592           // penser a nettoyer les variables globales associes genre
593           // PixelsTrouve ou grPixelTrouve...
594           //
595         // They are two cases :
596         // * the pixel data (i.e. the image or the volume) is pointed by it's
597         //   default official tag (0x7fe0,0x0010),
598         // * the writer of this file decided to put the image "address" (i.e the
599         //   offset from the begining of the file) at a different tag.
600         //   Then the "Pixel Data" offset might be found by indirection through
601         //   the "Image Location" tag (0x0028,  0x0200). In other terms the Image
602         //   Location tag contains the group where the "Pixel Data" offset is and
603         //   inside this group the element is conventionally at element 0x0010
604         //   (when the norm is respected).
605         // 
606         // Hence getting our hands on the Pixel Data is a two stage process:
607         //  1/ * find if the "Pixel Data" tag exists.
608         //     * if it does not exist, look for the "Pixel Location" tag.
609         //  2/ look at the proper tag ("Pixel Data" or "Pixel Location" when
610         //     it exists) what the offset it.
611         guint16 g;
612         guint16 n;
613         g = elem->GetGroup();
614         n = elem->GetElement();
615         if (!grPixelTrouve) {   // on n a pas encore trouve les pixels
616                 if (g > 0x0028) {
617                         if (n > 0x0200 || g == 0x7FE0 ) {  // on a depasse (28,200)
618                                 grPixel  = 0x7FE0;
619                                 numPixel = 0x0010;
620                                 grPixelTrouve = true;
621                                 if (DEBUG)
622                                         printf("------------------------grPixel %04x numPixel %04x\n",
623                                                grPixel,numPixel);
624                         }
625                 } else {         // on est sur (28,200)
626                         if (g == 0x0028) {
627                                 if (n == 0x0200) {
628                                         grPixelTrouve = 1;
629                                         char* NewValue = (char*)g_malloc(elem->GetLgrElem()+1);
630                                         // FIXME: not very elegant conversion
631                                         for(int i=0;i<4;i++)
632                                                 *((char*)(&grPixel)+i) = *(NewValue+i); 
633                                         elem->SetValue(NewValue);
634                                         
635                                         if (DEBUG)
636                                                 printf("------------------------GrPixel %04x\n", grPixel);
637                                         
638                                         if (grPixel != 0x7FE0)   // Vieux pb Philips
639                                                 numPixel = 0x1010;    // encore utile ??
640                                         else
641                                                 numPixel = 0x0010;
642                                         if (DEBUG)
643                                                 printf("------------------------grPixel %04x numPixel %04x\n",
644                                                        grPixel,numPixel);
645                                 }
646                         }
647                 }
648         } else {     // on vient de trouver les pixels
649                 if (g == grPixel) {
650                         if (n == numPixel) {
651                                 PixelPosition = elem->Offset; 
652                                 PixelsTrouves = true;
653                         if (DEBUG)
654                                 printf(" \t===> Pixels Trouves\n");
655                         }
656                 }
657         }
658 }
659
660 DictEntry * gdcmHeader::IsInDicts(guint32 group, guint32 element) {
661         DictEntry * found = (DictEntry*)0;
662         if (!RefPubDict && !RefShaDict) {
663                 //FIXME build a default dictionary !
664                 printf("FIXME in gdcmHeader::IsInDicts\n");
665         }
666         if (RefPubDict) {
667                 found = RefPubDict->GetTag(group, element);
668                 if (found)
669                         return found;
670         }
671         if (RefShaDict) {
672                 found = RefShaDict->GetTag(group, element);
673                 if (found)
674                         return found;
675         }
676         return found;
677 }