]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* src/gdcmHeader>[h/cxx] added gdcmHeader::GetPixelSize()
[gdcm.git] / src / gdcmFile.cxx
1 // gdcmFile.cxx
2
3 #include "gdcmFile.h"
4 #include "gdcmUtil.h"
5 #include "iddcmjpeg.h"
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    SetPixelDataSizeFromHeader();
29 }
30
31 gdcmFile::gdcmFile(const char * filename) 
32         :gdcmHeader(filename)   
33 {
34    SetPixelDataSizeFromHeader();
35 }
36
37 /**
38  * \ingroup   gdcmFile
39  * \brief     calcule la longueur (in bytes) A ALLOUER pour recevoir les
40  *        pixels de l'image
41  *              ou DES images dans le cas d'un multiframe
42  *              ATTENTION : il ne s'agit PAS de la longueur du groupe des Pixels        
43  *              (dans le cas d'images compressees, elle n'a pas de sens).
44  *
45  * @return      longueur a allouer 
46  */
47 void gdcmFile::SetPixelDataSizeFromHeader(void) {
48    int nb;
49    string str_nb;
50
51    str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
52    if (str_nb == "gdcm::Unfound" ) {
53       nb = 16;
54    } else {
55       nb = atoi(str_nb.c_str() );
56       if (nb == 12) nb =16;
57    }
58    lgrTotale =  GetXSize() *  GetYSize() *  GetZSize() * (nb/8);
59 }
60
61 /**
62  * \ingroup   gdcmFile
63  * \brief     Returns the size (in bytes) of required memory to hold
64  *            the pixel data represented in this file.
65  * @return    The size of pixel data in bytes.
66  */
67 size_t gdcmFile::GetImageDataSize(void) {
68    return (lgrTotale);
69 }
70
71 /**
72  * \ingroup gdcmFile
73  * \brief   Read pixel data from disk (optionaly decompressing) into the
74  *          caller specified memory location.
75  * @param   destination Where the pixel data should be stored.
76  *
77  */
78 bool gdcmFile::ReadPixelData(void* destination) {
79    if ( !OpenFile())
80       return false;
81       
82     if ( fseek(fp, GetPixelOffset(), SEEK_SET) == -1 ) {
83       CloseFile();
84       return false;
85    }     
86     
87    if ( !IsDicomV3()                             ||
88         IsImplicitVRLittleEndianTransferSyntax() ||
89         IsExplicitVRLittleEndianTransferSyntax() ||
90         IsExplicitVRBigEndianTransferSyntax()    ||
91         IsDeflatedExplicitVRLittleEndianTransferSyntax() ) { 
92                     
93       size_t ItemRead = fread(destination, lgrTotale, 1, fp);
94       if ( ItemRead != 1 ) {
95          CloseFile();
96          return false;
97       } else {
98          CloseFile();
99          return true;
100       }
101    }
102          
103    if (IsJPEGLossless()) {
104       int ln;
105       fseek(fp,4,SEEK_CUR);
106       fread(&ln,4,1,fp); 
107       if(GetSwapCode()) 
108          ln=SwapLong(ln);
109       //if (DEBUG) 
110          printf ("ln %d\n",ln);
111       fseek(fp,ln,SEEK_CUR);
112       fseek(fp,4,SEEK_CUR);
113       fread(&ln,4,1,fp); 
114       if(GetSwapCode()) 
115          ln=SwapLong(ln);
116       //if (DEBUG) 
117          printf ("ln image comprimée %d\n",ln);
118
119       ClbJpeg* jpg = _IdDcmJpegRead(fp);
120       if(jpg == NULL) {
121          CloseFile();
122          return false;
123       }     
124       memcpy(destination,jpg->DataImg,lgrTotale);
125       _IdDcmJpegFree (jpg);
126       CloseFile();
127       return true;
128    }
129    
130     printf ("Sorry, TransfertSyntax not yet taken into account ...\n");
131     CloseFile();
132     return false;
133
134 }   
135
136 /**
137  * \ingroup gdcmFile
138  * \brief   Allocates necessary memory, copies the pixel data
139  *          (image[s]/volume[s]) to newly allocated zone.
140  * @return  Pointer to newly allocated pixel data. 
141  */
142 void * gdcmFile::GetImageData (void) {
143    PixelData = (void *) malloc(lgrTotale);
144    GetImageDataIntoVector(PixelData, lgrTotale);
145    return(PixelData);
146 }
147
148 /**
149  * \ingroup gdcmFile
150  * \brief   Copies at most MaxSize bytes of pixel data to caller's
151  *          memory space.
152  * @param   destination Address (in caller's memory space) at which the
153  *          pixel data should be copied
154  * @param   MaxSize Maximum number of bytes to be copied. When MaxSize
155  *          is not sufficient to hold the pixel data the copy is not
156  *          executed (i.e. no partial copy).
157  * @return  On success, the number of bytes actually copied. Zero on
158  *          failure e.g. MaxSize is lower than necessary.
159  */
160
161 size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
162
163    int nb, nbu, highBit, signe;
164    string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
165  
166    if ( lgrTotale > MaxSize ) {
167       dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: pixel data bigger"
168                      "than caller's expected MaxSize");
169       return (size_t)0; 
170    }
171         
172         (void)ReadPixelData(destination);
173                         
174         // Nombre de Bits Alloues pour le stockage d'un Pixel
175         str_nb = GetPubElValByNumber(0x0028,0x0100);
176         if (str_nb == "gdcm::Unfound" ) {
177                 nb = 16;
178         } else {
179                 nb = atoi(str_nb.c_str() );
180         }
181         
182         // Nombre de Bits Utilises
183         str_nbu=GetPubElValByNumber(0x0028,0x0101);
184         if (str_nbu == "gdcm::Unfound" ) {
185                 nbu = nb;
186         } else {
187                 nbu = atoi(str_nbu.c_str() );
188         }       
189         
190         // Position du Bit de Poids Fort
191         str_highBit=GetPubElValByNumber(0x0028,0x0102);
192         if (str_highBit == "gdcm::Unfound" ) {
193                 highBit = nb - 1;
194         } else {
195                 highBit = atoi(str_highBit.c_str() );
196         }
197                 
198         // Signe des Pixels 
199         str_signe=GetPubElValByNumber(0x0028,0x0103);
200         if (str_signe == "gdcm::Unfound" ) {
201                 signe = 1;
202         } else {
203                 signe = atoi(str_signe.c_str() );
204         }
205
206    // On remet les Octets dans le bon ordre si besoin est
207    if (nb != 8)
208      SwapZone(destination, GetSwapCode(), lgrTotale, nb);
209  
210    // On remet les Bits des Octets dans le bon ordre si besoin est
211    if (nbu != nb){
212       int l = (int)lgrTotale / (nb/8);
213       if (nb == 16) {
214          guint16 mask = 0xffff;
215          mask = mask >> (nb-nbu);
216          guint16 *deb = (guint16 *)destination;
217          for(int i = 0; i<l; i++) {
218             *deb = (*deb >> (nbu-highBit-1)) & mask;
219             deb ++;
220          }
221       } else if (nb == 32 ) {
222          guint32 mask = 0xffffffff;
223          mask = mask >> (nb-nbu);
224          guint32 *deb = (guint32 *)destination;
225          for(int i = 0; i<l; i++) {
226             *deb = (*deb >> (nbu-highBit-1)) & mask;
227             deb ++;
228          }
229       } else {
230          dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: wierd image");
231          return (size_t)0; 
232       }
233    }
234    return lgrTotale; 
235 }
236
237
238 //
239 // Je laisse le code integral, au cas ça puisse etre reutilise ailleurs
240 //
241
242 void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) {
243 guint32 s32;
244 guint16 fort,faible;
245 int i;
246
247 if(nb == 16)
248     
249         switch(swap) {
250                 case 0:
251                 case 12:
252                 case 1234:
253                         break;
254                 
255                 case 21:
256                 case 3412:
257                 case 2143:
258                 case 4321:
259
260                         for(i=0;i<lgr;i++)
261                                 ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
262                                                 | ((((unsigned short int*)im)[i])<<8);
263                         break;
264                         
265                 default:
266                         printf("valeur de SWAP (16 bits) non autorisee : %d\n", swap);
267         } 
268  
269 if( nb == 32 )
270
271         switch (swap) {
272                 case 0:
273                 case 1234:
274                          break;
275
276                 case 4321:
277                          for(i=0;i<lgr;i++) {
278                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 4321 */
279                                 fort  =((unsigned long int*)im)[i]>>16;
280                                 fort=  (fort>>8)   | (fort<<8);
281                                 faible=(faible>>8) | (faible<<8);
282                                 s32=faible;
283                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
284                         }
285                         break;
286
287                 case 2143:
288                         for(i=0;i<lgr;i++) {
289                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 2143 */
290                                 fort=((unsigned long int*)im)[i]>>16;
291                                 fort=  (fort>>8)   | (fort<<8);
292                                 faible=(faible>>8) | (faible<<8);
293                                 s32=fort; 
294                                 ((unsigned long int*)im)[i]=(s32<<16)|faible;
295                         }
296                         break;
297   
298                 case 3412:
299                         for(i=0;i<lgr;i++) {
300                                 faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 3412 */
301                                 fort=((unsigned long int*)im)[i]>>16;                  
302                                 s32=faible; 
303                                 ((unsigned long int*)im)[i]=(s32<<16)|fort;
304                         }                 
305                         break; 
306                                 
307                 default:
308                         printf("valeur de SWAP (32 bits) non autorisee : %d\n", swap);
309         } 
310 return;
311 }
312
313 /////////////////////////////////////////////////////////////////
314 /**
315  * \ingroup   gdcmFile
316  * \brief TODO JPR
317  * \warning doit-etre etre publique ?  FIXME JPR
318  * TODO : y a-t-il un inconvenient à fusioner ces 2 fonctions
319  *
320  * @param inData TODO JPR
321  * @param ExpectedSize TODO JPR
322  *
323  * @return TODO JPR     
324  */
325 int gdcmFile::SetImageData(void * inData, size_t ExpectedSize) {
326    SetImageDataSize(ExpectedSize);
327    PixelData = inData;
328    lgrTotale = ExpectedSize;
329    
330    
331    return(1);
332 }
333
334
335 /////////////////////////////////////////////////////////////////
336 /**
337  * \ingroup   gdcmFile
338  * \brief TODO JPR
339  * \
340  * \warning WARNING doit-etre etre publique ? FIXME JPR
341  * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions
342  *
343  * @param ImageDataSize TODO JPR
344  *
345  */
346
347 void gdcmFile::SetImageDataSize(size_t ImageDataSize) {
348
349         string content1;
350         char car[20];
351         
352         // suppose que le ElValue (0x7fe0, 0x0010) existe ...
353         
354         sprintf(car,"%d",ImageDataSize);
355  
356         gdcmElValue*a = GetElValueByNumber(0x7fe0, 0x0010);
357         a->SetLength(ImageDataSize);
358                 
359         ImageDataSize+=8;
360         sprintf(car,"%d",ImageDataSize);
361         content1=car;   
362         SetPubElValByNumber(content1, 0x7fe0, 0x0000);
363 }
364
365
366 /////////////////////////////////////////////////////////////////
367 /**
368  * \ingroup   gdcmFile
369  * \brief Ecrit sur disque les pixels d'UNE image
370  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
371  *        Ca sera à l'utilisateur d'appeler son Reader correctement
372  *        (Equivalent a IdImaWriteRawFile) FIXME JPR
373  *
374  * @param nomFichier TODO JPR
375  *
376  * @return TODO JPR     
377  */
378
379 int gdcmFile::WriteRawData (string nomFichier) {
380
381         FILE * fp1;
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         fwrite (PixelData,lgrTotale, 1, fp1);
389         fclose (fp1);
390         return(1);
391 }
392
393
394
395 /////////////////////////////////////////////////////////////////
396 /**
397  * \ingroup   gdcmFile
398  * \brief Ecrit sur disque UNE image Dicom
399  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
400  *         Ca fonctionnera correctement (?) sur processeur Intel
401  *         (Equivalent a IdDcmWrite) FIXME JPR 
402  *
403  * @param nomFichier TODO JPR
404  *
405  * @return      TODO JPR
406  */
407
408 int gdcmFile::WriteDcmImplVR (string nomFichier) {
409    return WriteBase(nomFichier, ImplicitVR);
410 }
411
412 int gdcmFile::WriteDcmImplVR (const char* nomFichier) {
413    return WriteDcmImplVR (string (nomFichier));
414 }
415         
416 /////////////////////////////////////////////////////////////////
417 /**
418  * \ingroup   gdcmFile
419  *
420  * @param  nomFichier TODO JPR
421  *
422  * @return TODO JPR
423  */
424
425 int gdcmFile::WriteDcmExplVR (string nomFichier) {
426    return WriteBase(nomFichier, ExplicitVR);
427 }
428         
429 /////////////////////////////////////////////////////////////////
430 /**
431  * \ingroup   gdcmFile
432  * \brief  Ecrit au format ACR-NEMA sur disque l'entete et les pixels
433  *        (a l'attention des logiciels cliniques 
434  *        qui ne prennent en entrée QUE des images ACR ...
435  * \warning si un header DICOM est fourni en entree,
436  *        les groupes < 0x0008 et les groupes impairs sont ignores)
437  * \warning Aucun test n'est fait sur l'"Endiannerie" du processeur.
438  *        Ca fonctionnera correctement (?) sur processeur Intel
439  *        (Equivalent a IdDcmWrite) 
440  *
441  * @param nomFichier TODO JPR
442  *
443  * @return TODO JPR     
444  */
445
446 int gdcmFile::WriteAcr (string nomFichier) {
447    return WriteBase(nomFichier, ACR);
448 }
449
450 int gdcmFile::WriteBase (string nomFichier, FileType type) {
451
452    FILE * fp1;
453    fp1 = fopen(nomFichier.c_str(),"wb");
454    if (fp1 == NULL) {
455       printf("Echec ouverture (ecriture) Fichier [%s] \n",nomFichier.c_str());
456       return (0);
457    }
458
459    if ( (type == ImplicitVR) || (type == ExplicitVR) ) {
460       char * filePreamble;
461       // Ecriture Dicom File Preamble
462       filePreamble=(char*)calloc(128,1);
463       fwrite(filePreamble,128,1,fp1);
464       fwrite("DICM",4,1,fp1);
465    }
466
467    gdcmHeader::Write(fp1, type);
468    fwrite(PixelData, lgrTotale, 1, fp1);
469    fclose (fp1);
470    return(1);
471 }