]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
Brutal commit. Changelog to come.... Frog
[gdcm.git] / src / gdcmFile.cxx
1 // gdcmFile.cxx
2
3 #include "gdcmFile.h"
4
5 static void _Swap(void* im, int swap, int lgr, int nb);
6
7 /////////////////////////////////////////////////////////////////
8 /**
9  * \ingroup   gdcmFile
10  * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant
11  *        file (see SetFileName, SetDcmTag and Write)
12  *        Opens (in read only and when possible) an existing file and checks
13  *        for DICOM compliance. Returns NULL on failure.
14  * \Note  the in-memory representation of all available tags found in
15  *        the DICOM header is post-poned to first header information access.
16  *        This avoid a double parsing of public part of the header when
17  *        one sets an a posteriori shadow dictionary (efficiency can be
18  *        seen as a side effect).   
19  *
20  * @param filename file to be opened for parsing
21  *
22  * @return      
23  */
24  
25 gdcmFile::gdcmFile(string & filename) 
26         :gdcmHeader(filename.c_str())   
27 {
28 }
29
30 gdcmFile::gdcmFile(const char * filename) 
31         :gdcmHeader(filename)   
32 {
33 }
34
35
36 /////////////////////////////////////////////////////////////////
37 /**
38  * \ingroup   gdcmFile
39  * \brief     Renvoie la longueur A ALLOUER pour recevoir les pixels de l'image
40  *              ou DES images dans le cas d'un multiframe
41  *              ATTENTION : il ne s'agit PAS de la longueur du groupe des Pixels        
42  *              (dans le cas d'images compressees, elle n'a pas de sens).
43  *
44  * @return      longueur a allouer 
45  */
46
47 size_t gdcmFile::GetImageDataSize(void) {
48         int nbLignes, nbCol, nbFrames, nb;
49         string str_nbFrames, str_nb;
50         // Nombre de Lignes     
51         nbLignes=atoi(gdcmHeader::GetPubElValByNumber(0x0028,0x0010).c_str());
52         // Nombre de Colonnes   
53         nbCol   =atoi(gdcmHeader::GetPubElValByNumber(0x0028,0x0011).c_str());
54
55         // Nombre de Frames     
56         str_nbFrames=gdcmHeader::GetPubElValByNumber(0x0028,0x0008);
57         
58         if (str_nbFrames == "gdcm::Unfound" ) {
59                 nbFrames = 1;
60         } else {
61                 nbFrames = atoi(str_nbFrames.c_str() );
62         }
63         
64         // Nombre de Bits Alloues pour le stockage d'un Pixel   
65         str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
66
67         if (str_nb == "gdcm::Unfound" ) {
68                 nb = 16;
69         } else {
70                 nb = atoi(str_nb.c_str() );
71         }
72
73         size_t lgrTotale = nbFrames*nbLignes*nbCol*(nb/8);
74         return (lgrTotale);
75 }
76
77
78
79 /////////////////////////////////////////////////////////////////
80 /**
81  * \ingroup   gdcmFile
82  * \brief TODO
83  * \warning WARNING
84  *
85  */
86 void * gdcmFile::GetImageData (void) {
87         char * _Pixels;
88         // Longueur en Octets des Pixels a lire
89         size_t taille = GetImageDataSize();// ne faudrait-il pas la stocker?
90         _Pixels = (char *) malloc(taille);
91         GetImageDataIntoVector(_Pixels, taille);
92         
93                 // On l'affecte à un champ du dcmFile   
94         Pixels =    _Pixels;
95         lgrTotale = taille;
96         
97         // ca fait double emploi, il faudra nettoyer ça
98         
99         return(_Pixels);
100 }
101
102
103
104 /////////////////////////////////////////////////////////////////
105 /**
106  * \ingroup   gdcmFile
107  * \brief amene en mémoire dans une zone précisee par l'utilisateur
108  *        les Pixels d'une image NON COMPRESSEE
109  * \Warning Aucun test n'est fait pour le moment sur le caractere compresse ou non de l'image
110  *
111  * @param destination
112  * @param MaxSize
113  *
114  * @return TODO JPR     
115  */
116
117 int gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
118
119 // Question :
120 //      dans quel cas la MaxSize sert-elle a quelque chose?
121 //      que fait-on si la taille de l'image est + gde    que Maxize?
122 //      que fait-on si la taille de l'image est + petite que Maxize?
123
124         
125         void * Pixels = destination;  // pour garder le code identique avec GetImageData
126
127         int nb, nbu, highBit, signe;
128         string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
129         
130         unsigned short int mask = 0xffff;
131         
132         // Longueur en Octets des Pixels a lire
133         size_t _lgrTotale = GetImageDataSize(); // ne faudrait-il pas la stocker?
134         
135         // si lgrTotale < MaxSize ==> Gros pb 
136         // -> on résoud à la goret
137         
138         if ( _lgrTotale < MaxSize ) MaxSize = _lgrTotale;
139         
140         GetPixels(MaxSize, destination);
141                         
142         // Nombre de Bits Alloues pour le stockage d'un Pixel   
143         str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
144
145         if (str_nb == "gdcm::Unfound" ) {
146                 nb = 16;
147         } else {
148                 nb = atoi(str_nb.c_str() );
149         }
150         
151         // Nombre de Bits Utilises      
152         str_nbu=GetPubElValByNumber(0x0028,0x0101);
153
154         if (str_nbu == "gdcm::Unfound" ) {
155                 nbu = nb;
156         } else {
157                 nbu = atoi(str_nbu.c_str() );
158         }       
159         
160         // Position du Bit de Poids Fort        
161         str_highBit=GetPubElValByNumber(0x0028,0x0102);
162
163         if (str_highBit == "gdcm::Unfound" ) {
164                 highBit = nb - 1;
165         } else {
166                 highBit = atoi(str_highBit.c_str() );
167         }
168                 
169         // Signe des Pixels 
170         str_signe=GetPubElValByNumber(0x0028,0x0103);
171
172         if (str_signe == "gdcm::Unfound" ) {
173                 signe = 1;
174         } else {
175                 signe = atoi(str_signe.c_str() );
176         }
177
178         // On remet les Octets dans le bon ordre si besoin est
179         if (nb != 8) {
180                 int _sw = GetSwapCode();
181
182                 _Swap (destination, _sw, _lgrTotale, nb);
183         }
184         
185         // On remet les Bits des Octets dans le bon ordre si besoin est
186         //
187         // ATTENTION :  Jamais confronté a des pixels stockes sur 32 bits 
188         //                      avec moins de 32 bits utilises
189         //                      et dont le bit de poids fort ne serait pas la ou on l'attend ...
190         //                      --> ne marchera pas dans ce cas 
191         if (nbu!=nb){
192                 mask = mask >> (nb-nbu);
193                 int l=(int)MaxSize/(nb/8);
194                 unsigned short *deb = (unsigned short *)Pixels;
195                 for(int i=0;i<l;i++) {
196                                 *deb = (*deb >> (nbu-highBit-1)) & mask;
197                                 deb ++;
198                 }
199         }
200                         
201         // VOIR s'il ne faudrait pas l'affecter à un champ du dcmHeader
202         
203         return 1; 
204 }
205
206
207 //
208 // Je laisse le code integral, au cas ça puisse etre reutilise ailleurs
209 //
210
211 static void _Swap(void* im, int swap, int lgr, int nb) {                     
212 guint32 s32;
213 guint16 fort,faible;
214 int i;
215
216 if(nb == 16)
217     
218         switch(swap) {
219                 case 0:
220                 case 12:
221                 case 1234:
222                         break;
223                 
224                 case 21:
225                 case 3412:
226                 case 2143:
227                 case 4321:
228
229                         for(i=0;i<lgr;i++)
230                                 ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
231                                                 | ((((unsigned short int*)im)[i])<<8);
232                         break;
233                         
234                 default:
235                         printf("valeur de SWAP (16 bits) non autorisee : %d\n", swap);
236         } 
237  
238 if( nb == 32 )
239
240         switch (swap) {
241                 case 0:
242                 case 1234:
243                          break;
244
245                 case 4321:
246                          for(i=0;i<lgr;i++) {
247                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 4321 */
248                                 fort  =((unsigned long int*)im)[i]>>16;
249                                 fort=  (fort>>8)   | (fort<<8);
250                                 faible=(faible>>8) | (faible<<8);
251                                 s32=faible;
252                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
253                         }
254                         break;
255
256                 case 2143:
257                         for(i=0;i<lgr;i++) {
258                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 2143 */
259                                 fort=((unsigned long int*)im)[i]>>16;
260                                 fort=  (fort>>8)   | (fort<<8);
261                                 faible=(faible>>8) | (faible<<8);
262                                 s32=fort; 
263                                 ((unsigned long int*)im)[i]=(s32<<16)|faible;
264                         }
265                         break;
266   
267                 case 3412:
268                         for(i=0;i<lgr;i++) {
269                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 3412 */
270                                 fort=((unsigned long int*)im)[i]>>16;                  
271                                 s32=faible; 
272                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
273                         }                 
274                         break; 
275                                 
276                 default:
277                         printf("valeur de SWAP (32 bits) non autorisee : %d\n", swap);
278         } 
279 return;
280 }
281
282 /////////////////////////////////////////////////////////////////
283 /**
284  * \ingroup   gdcmFile
285  * \brief TODO JPR
286  * \warning doit-etre etre publique ?  FIXME JPR
287  *
288  * @param Data TODO JPR
289  * @param ExpectedSize TODO JPR
290  *
291  * @return TODO JPR     
292  */
293 int gdcmFile::SetImageData(void * Data, size_t ExpectedSize) {
294         
295         SetImageDataSize(ExpectedSize);
296         
297         Pixels =    Data;
298         lgrTotale = ExpectedSize;
299         
300         return(1);
301 }
302
303
304 /////////////////////////////////////////////////////////////////
305 /**
306  * \ingroup   gdcmFile
307  * \brief TODO JPR
308  * \
309  * \warning WARNING doit-etre etre publique ? FIXME JPR
310  *
311  * @param ImageDataSize TODO JPR
312  *
313  */
314
315 void gdcmFile::SetImageDataSize(size_t ImageDataSize) {
316
317         string content1;
318         string content2;
319         char car[20];
320         
321         // suppose que le ElValue (0x7fe0, 0x0010) existe ...
322         
323         sprintf(car,"%d",ImageDataSize);
324         content2=car;
325         SetPubElValByNumber(content2, 0x7fe0, 0x0010);
326         
327         ImageDataSize+=8;
328         sprintf(car,"%d",ImageDataSize);
329         content1=car;   
330         SetPubElValByNumber(content1, 0x7fe0, 0x0000);
331 }
332
333
334 /////////////////////////////////////////////////////////////////
335 /**
336  * \ingroup   gdcmFile
337  * \brief Ecrit sur disque les pixels d'UNE image
338  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
339  *        Ca sera à l'utilisateur d'appeler son Reader correctement
340  *        (Equivalent a IdImaWriteRawFile) FIXME JPR
341  *
342  * @param nomFichier TODO JPR
343  *
344  * @return TODO JPR     
345  */
346
347 int gdcmFile::WriteRawData (string nomFichier) {
348
349         FILE * fp1;
350         fp1 = fopen(nomFichier.c_str(),"wb");
351         if (fp1 == NULL) {
352                 printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
353                 return (0);
354         } 
355         
356         fwrite (Pixels,lgrTotale, 1, fp1);
357         fclose (fp1);
358         return(1);
359 }
360
361
362
363 /////////////////////////////////////////////////////////////////
364 /**
365  * \ingroup   gdcmFile
366  * \brief Ecrit sur disque UNE image Dicom
367  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
368  *         Ca fonctionnera correctement (?) sur processeur Intel
369  *         (Equivalent a IdDcmWrite) FIXME JPR 
370  *
371  * @param nomFichier TODO JPR
372  *
373  * @return      TODO JPR
374  */
375
376 int gdcmFile::WriteDcm (string nomFichier) {
377
378 // ATTENTION : fonction non terminée (commitée a titre de precaution)
379
380         FILE * fp1;
381         char* filePreamble;
382         fp1 = fopen(nomFichier.c_str(),"wb");
383         if (fp1 == NULL) {
384                 printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
385                 return (0);
386         } 
387         
388         //      Ecriture Dicom File Preamble
389         filePreamble=(char*)calloc(128,1);
390         fwrite(filePreamble,128,1,fp1);
391         fwrite("DICM",4,1,fp1);
392
393         // un accesseur de + est obligatoire ???
394         // pourtant le gdcmElValSet contenu dans le gdcmHeader 
395         // ne devrait pas être visible par l'utilisateur final (?)
396         
397         GetPubElValSet().Write(fp1);
398                 
399         fwrite(Pixels, lgrTotale, 1, fp1);
400
401         fclose (fp1);
402         return(1);
403 }
404
405 int gdcmFile::WriteDcm (const char* nomFichier) {
406    WriteDcm (string (nomFichier));
407 }
408         
409         
410 /////////////////////////////////////////////////////////////////
411 /**
412  * \ingroup   gdcmFile
413  *
414  * @param  nomFichier TODO JPR
415  *
416  * @return TODO JPR
417  */
418
419 int gdcmFile::WriteDcmExplVR (string nomFichier) {
420
421 // ATTENTION : fonction non terminée (commitée a titre de precaution)
422
423         FILE * fp1;
424         char* filePreamble;
425         fp1 = fopen(nomFichier.c_str(),"wb");
426         if (fp1 == NULL) {
427                 printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
428                 return (0);
429         } 
430         
431         //      Ecriture Dicom File Preamble
432         filePreamble=(char*)calloc(128,1);
433         fwrite(filePreamble,128,1,fp1);
434         fwrite("DICM",4,1,fp1);
435
436         // un accesseur de + est obligatoire ???
437         // pourtant le gdcmElValSet contenu dans le gdcmHeader 
438         // ne devrait pas être visible par l'utilisateur final (?)
439         
440         GetPubElValSet().WriteExplVR(fp1);
441                 
442         fwrite(Pixels, lgrTotale, 1, fp1);
443
444         fclose (fp1);
445         return(1);
446 }
447         
448 /////////////////////////////////////////////////////////////////
449 /**
450  * \ingroup   gdcmFile
451  * \brief  Ecrit sur disque UNE image ACR-NEMA 
452  *        (a l'attention des logiciels cliniques 
453  *        qui ne prennent en entrée QUE des images ACR ...
454  *        si un header DICOM est fourni en entree,
455  *        les groupes < 0x0008 et les groupes impairs sont ignores)
456  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
457  *        Ca fonctionnera correctement (?) sur processeur Intel
458  *        (Equivalent a IdDcmWrite) 
459  *
460  * @param nomFichier TODO JPR
461  *
462  * @return TODO JPR     
463  */
464
465 int gdcmFile::WriteAcr (string nomFichier) {
466
467 // ATTENTION : fonction non terminée (commitée a titre de precaution)
468
469         FILE * fp1;
470         fp1 = fopen(nomFichier.c_str(),"wb");
471         if (fp1 == NULL) {
472                 printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
473                 return (0);
474         } 
475
476         // un accesseur de + est obligatoire ???
477         // pourtant le gdcmElValSet contenu dans le gdcmHeader 
478         // ne devrait pas être visible par l'utilisateur final (?)
479         
480         GetPubElValSet().WriteAcr(fp1);
481                 
482         fwrite(Pixels, lgrTotale, 1, fp1);
483
484         fclose (fp1);
485         return(1);
486 }