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