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