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