]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
Calcul correct (merci, Eric!) de la longueur de chaque Dicom Group
[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 /**
79  * \ingroup   gdcmFile
80  * \brief TODO
81  * \warning WARNING
82  *
83  * @param 
84  *
85  * @return
86  */
87
88 void * gdcmFile::GetImageData (void) {
89         char * _Pixels;
90         // Longueur en Octets des Pixels a lire
91         size_t taille = GetImageDataSize();// ne faudrait-il pas la stocker?
92         _Pixels = (char *) malloc(taille);
93         GetImageDataIntoVector(_Pixels, taille);
94         
95                 // On l'affecte à un champ du dcmFile   
96         Pixels =    _Pixels;
97         lgrTotale = taille;
98         
99         // ca fait double emploi, il faudra nettoyer ça
100         
101         return(_Pixels);
102 }
103
104
105
106 /////////////////////////////////////////////////////////////////
107 /**
108  * \ingroup   gdcmFile
109  * \brief amene en mémoire dans une zone précisee par l'utilisateur
110  * \les Pixels d'une image NON COMPRESSEE
111  * \Aucun test n'est fait pour le moment sur le caractere compresse ou non de l'image
112  *
113  * @param 
114  *
115  * @return      
116  */
117
118 int gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
119
120 // Question :
121 //      dans quel cas la MaxSize sert-elle a quelque chose?
122 //      que fait-on si la taille de l'image est + gde    que Maxize?
123 //      que fait-on si la taille de l'image est + petite que Maxize?
124
125         
126         void * Pixels = destination;  // pour garder le code identique avec GetImageData
127
128         int nb, nbu, highBit, signe;
129         string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
130         
131         unsigned short int mask = 0xffff;
132         
133         // Longueur en Octets des Pixels a lire
134         size_t _lgrTotale = GetImageDataSize(); // ne faudrait-il pas la stocker?
135         
136         // si lgrTotale < MaxSize ==> Gros pb 
137         // -> on résoud à la goret
138         
139         if ( _lgrTotale < MaxSize ) MaxSize = _lgrTotale;
140         
141         GetPixels(MaxSize, destination);
142                         
143         // Nombre de Bits Alloues pour le stockage d'un Pixel   
144         str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
145
146         if (str_nb == "gdcm::Unfound" ) {
147                 nb = 16;
148         } else {
149                 nb = atoi(str_nb.c_str() );
150         }
151         
152         // Nombre de Bits Utilises      
153         str_nbu=GetPubElValByNumber(0x0028,0x0101);
154
155         if (str_nbu == "gdcm::Unfound" ) {
156                 nbu = nb;
157         } else {
158                 nbu = atoi(str_nbu.c_str() );
159         }       
160         
161         // Position du Bit de Poids Fort        
162         str_highBit=GetPubElValByNumber(0x0028,0x0102);
163
164         if (str_highBit == "gdcm::Unfound" ) {
165                 highBit = nb - 1;
166         } else {
167                 highBit = atoi(str_highBit.c_str() );
168         }
169                 
170         // Signe des Pixels 
171         str_signe=GetPubElValByNumber(0x0028,0x0103);
172
173         if (str_signe == "gdcm::Unfound" ) {
174                 signe = 1;
175         } else {
176                 signe = atoi(str_signe.c_str() );
177         }
178
179         // On remet les Octets dans le bon ordre si besoin est
180         if (nb != 8) {
181                 int _sw = GetSwapCode();
182
183                 _Swap (destination, _sw, _lgrTotale, nb);
184         }
185         
186         // On remet les Bits des Octets dans le bon ordre si besoin est
187         //
188         // ATTENTION :  Jamais confronté a des pixels stockes sur 32 bits 
189         //                      avec moins de 32 bits utilises
190         //                      et dont le bit de poids fort ne serait pas la ou on l'attend ...
191         //                      --> ne marchera pas dans ce cas 
192         if (nbu!=nb){
193                 mask = mask >> (nb-nbu);
194                 int l=(int)MaxSize/(nb/8);
195                 unsigned short *deb = (unsigned short *)Pixels;
196                 for(int i=0;i<l;i++) {
197                                 *deb = (*deb >> (nbu-highBit-1)) & mask;
198                                 deb ++;
199                 }
200         }
201                         
202         // VOIR s'il ne faudrait pas l'affecter à un champ du dcmHeader
203         
204         return 1; 
205 }
206
207
208 //
209 // Je laisse le code integral, au cas ça puisse etre reutilise ailleurs
210 //
211
212 static void _Swap(void* im, int swap, int lgr, int nb) {                     
213 guint32 s32;
214 guint16 fort,faible;
215 int i;
216
217 if(nb == 16)
218     
219         switch(swap) {
220                 case 0:
221                 case 12:
222                 case 1234:
223                         break;
224                 
225                 case 21:
226                 case 3412:
227                 case 2143:
228                 case 4321:
229
230                         for(i=0;i<lgr;i++)
231                                 ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
232                                                 | ((((unsigned short int*)im)[i])<<8);
233                         break;
234                         
235                 default:
236                         printf("valeur de SWAP (16 bits) non autorisee : %d\n", swap);
237         } 
238  
239 if( nb == 32 )
240
241         switch (swap) {
242                 case 0:
243                 case 1234:
244                          break;
245
246                 case 4321:
247                          for(i=0;i<lgr;i++) {
248                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 4321 */
249                                 fort  =((unsigned long int*)im)[i]>>16;
250                                 fort=  (fort>>8)   | (fort<<8);
251                                 faible=(faible>>8) | (faible<<8);
252                                 s32=faible;
253                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
254                         }
255                         break;
256
257                 case 2143:
258                         for(i=0;i<lgr;i++) {
259                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 2143 */
260                                 fort=((unsigned long int*)im)[i]>>16;
261                                 fort=  (fort>>8)   | (fort<<8);
262                                 faible=(faible>>8) | (faible<<8);
263                                 s32=fort; 
264                                 ((unsigned long int*)im)[i]=(s32<<16)|faible;
265                         }
266                         break;
267   
268                 case 3412:
269                         for(i=0;i<lgr;i++) {
270                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 3412 */
271                                 fort=((unsigned long int*)im)[i]>>16;                  
272                                 s32=faible; 
273                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
274                         }                 
275                         break; 
276                                 
277                 default:
278                         printf("valeur de SWAP (32 bits) non autorisee : %d\n", swap);
279         } 
280 return;
281 }
282
283 /////////////////////////////////////////////////////////////////
284 /**
285  * \ingroup   gdcmFile
286  * \brief TODO
287  * \warning WARNING doit-etre etre publique ? 
288  *
289  * @param 
290  *
291  * @return      
292  */
293
294 int gdcmFile::SetImageData(void * Data, size_t ExpectedSize) {
295         
296         SetImageDataSize(ExpectedSize);
297         
298         Pixels =    Data;
299         lgrTotale = ExpectedSize;
300         
301         return(1);
302 }
303
304
305 /////////////////////////////////////////////////////////////////
306 /**
307  * \ingroup   gdcmFile
308  * \brief TODO
309  * \
310  * \warning WARNING doit-etre etre publique ?
311  *
312  * @param 
313  *
314  * @return
315  */
316
317 void gdcmFile::SetImageDataSize(size_t ImageDataSize) {
318
319         string content1;
320         string content2;
321         char car[20];
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) 
341  *
342  * @param 
343  *
344  * @return      
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) 
370  *
371  * @param 
372  *
373  * @return      
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         GetPubElVals().Write(fp1);
398                 
399         fwrite(Pixels, lgrTotale, 1, fp1);
400
401         fclose (fp1);
402         return(1);
403 }
404         
405 /////////////////////////////////////////////////////////////////
406 /**
407  * \ingroup   gdcmFile
408  * \brief Ecrit sur disque UNE image ACR-NEMA 
409  * \ (a l'attention des logiciels cliniques 
410  * \ qui ne prennent en entrée QUE des images ACR ...
411  * \ si un header DICOM est fourni en entree,
412  * \ les groupes < 0x0008 et les groupes impairs sont ignores)
413  * \ Aucun test n'est fait sur l'"Endiannerie" du processeur.
414  * \ Ca fonctionnera correctement (?) sur processeur Intel
415  * \ (Equivalent a IdDcmWrite) 
416  *
417  * @param 
418  *
419  * @return      
420  */
421
422 int gdcmFile::WriteAcr (string nomFichier) {
423
424 // ATTENTION : fonction non terminée (commitée a titre de precaution)
425
426         FILE * fp1;
427         fp1 = fopen(nomFichier.c_str(),"wb");
428         if (fp1 == NULL) {
429                 printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
430                 return (0);
431         } 
432
433         // un accesseur de + est obligatoire ???
434         // pourtant le gdcmElValSet contenu dans le gdcmHeader 
435         // ne devrait pas être visible par l'utilisateur final (?)
436         
437         GetPubElVals().WriteAcr(fp1);
438                 
439         fwrite(Pixels, lgrTotale, 1, fp1);
440
441         fclose (fp1);
442         return(1);
443 }