]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
6689c01f437ef8e70898c5f717af19ecc64b898c
[gdcm.git] / src / gdcmFile.cxx
1 // gdcmFile.cxx
2
3 #include "gdcmFile.h"
4 #include "gdcmUtil.h"
5 #include "iddcmjpeg.h" // for the 'LibIDO' Jpeg LossLess
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(std::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    std::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)* GetSamplesPerPixel();
59    std::string str_PhotometricInterpretation = gdcmHeader::GetPubElValByNumber(0x0028,0x0004);
60    if ( str_PhotometricInterpretation == "PALETTE COLOR " ) { 
61       lgrTotale*=3;
62    }
63 }
64    // see PS 3.3-2003 : C.7.6.3.2.1  
65    // 
66    //   MONOCHROME1
67    //   MONOCHROME2
68    //   PALETTE COLOR
69    //   RGB
70    //   HSV  (Retired)
71    //   ARGB (Retired)
72    //   CMYK (Retired)
73    //   YBR_FULL
74    //   YBR_FULL_422 (no LUT, no Palette)
75    //   YBR_PARTIAL_422
76    //   YBR_ICT
77    //   YBR_RCT
78
79   // LUT's
80   // ex : gdcm-US-ALOKA-16.dcm
81   // 0028|1221 [OW]   [Segmented Red Palette Color Lookup Table Data]
82   // 0028|1222 [OW]   [Segmented Green Palette Color Lookup Table Data]  
83   // 0028|1223 [OW]   [Segmented Blue Palette Color Lookup Table Data]
84
85   // ex : US-PAL-8-10x-echo.dcm, 8BitsRunLengthColor.dcm
86   // 0028|1201 [OW]   [Red Palette Color Lookup Table Data]
87   // 0028|1202 [OW]   [Green Palette Color Lookup Table Data]
88   // 0028|1203 [OW]   [Blue Palette Color Lookup Table Data]
89
90   // ex  : OT-PAL-8-face.dcm
91   // 0028|1201 [US]   [Red Palette Color Lookup Table Data]
92   // 0028|1202 [US]   [Green Palette Color Lookup Table Data]
93   // 0028|1203 [US]   [Blue Palette Color Lookup Table Data]
94
95
96 /////////////////////////////////////////////////////////////////
97 /**
98  * \ingroup   gdcmFile
99  * \brief     Returns the size (in bytes) of required memory to hold
100  *            the pixel data represented in this file.
101  * @return    The size of pixel data in bytes.
102  */
103
104 size_t gdcmFile::GetImageDataSize(void) {
105    return (lgrTotale);
106 }
107
108
109 /////////////////////////////////////////////////////////////////
110 /**
111  * \ingroup gdcmFile
112  * \brief   Read pixel data from disk (optionaly decompressing) into the
113  *          caller specified memory location.
114  * @param   destination where the pixel data should be stored.
115  *
116  */
117 bool gdcmFile::ReadPixelData(void* destination) {
118
119    if ( !OpenFile())
120       return false;
121       
122     if ( fseek(fp, GetPixelOffset(), SEEK_SET) == -1 ) {
123       CloseFile();
124       return false;
125    }     
126
127 // -------------------------  Uncompressed File
128     
129    if ( !IsDicomV3()                             ||
130         IsImplicitVRLittleEndianTransferSyntax() ||
131         IsExplicitVRLittleEndianTransferSyntax() ||
132         IsExplicitVRBigEndianTransferSyntax()    ||
133         IsDeflatedExplicitVRLittleEndianTransferSyntax() ) { 
134                     
135       size_t ItemRead = fread(destination, lgrTotale, 1, fp);
136       if ( ItemRead != 1 ) {
137          CloseFile();
138          return false;
139       } else {
140          CloseFile();
141          return true;
142       }
143    } 
144     
145  // ------------------------  Compressed File .
146        
147       int nb;
148       std::string str_nb=gdcmHeader::GetPubElValByNumber(0x0028,0x0100);
149       if (str_nb == GDCM_UNFOUND ) {
150          nb = 16;
151       } else {
152          nb = atoi(str_nb.c_str() );
153          if (nb == 12) nb =16;
154       }
155       int nBytes= nb/8;
156       
157       int taille = GetXSize() *  GetYSize()  * GetSamplesPerPixel(); 
158           
159                 
160   // ------------------------------- JPEG LossLess : call to Jpeg Libido
161    
162    if (IsJPEGLossless() && GetZSize() == 1) {
163    
164       int ln; //  Position on begining of Jpeg Pixels
165       fseek(fp,4,SEEK_CUR);  // skipping (fffe,e000) : Basic Offset Table Item
166       fread(&ln,4,1,fp); 
167       if(GetSwapCode()) 
168          ln=SwapLong(ln);    // Item length
169       fseek(fp,ln,SEEK_CUR); // skipping Basic Offset Table ('ln' bytes) 
170       fseek(fp,4,SEEK_CUR);  // skipping (fffe,e000) : First fragment Item Tag
171       fread(&ln,4,1,fp);     // First fragment length (just to know)
172       if(GetSwapCode()) 
173          ln=SwapLong(ln);      
174  
175       ClbJpeg* jpg = _IdDcmJpegRead(fp); // TODO : find a 'full' one.
176                                          // (We use the LibIDO one :-(
177       if(jpg == NULL) {
178          CloseFile();
179          return false;
180       }      
181       int * dataJpg = jpg->DataImg;
182  
183       switch (nBytes) {   
184          case 1:
185          {
186             unsigned short *dest = (unsigned short *)destination;
187             for (int i=0; i<taille; i++) {
188                *((unsigned char *)dest+i) = *(dataJpg +i);   
189             }
190          }
191          break;        
192          
193          case 2:
194          {
195             unsigned short *dest = (unsigned short *)destination;
196             for (int i=0; i<taille; i++) {           
197                *((unsigned short *)dest+i) = *(dataJpg +i);    
198             }
199          }
200          break;       
201      }
202       _IdDcmJpegFree (jpg);
203       return true;
204    } 
205  
206   // ------------------------------- RLE
207
208       if (gdcmHeader::IsRLELossLessTransferSyntax()) {
209             int res = (bool)gdcm_read_RLE_file (destination);
210             return res; 
211       }
212
213   // ------------------------------- Multiframe JPEG 
214     
215       long fragmentBegining; // for ftell, fseek
216       bool b = gdcmHeader::IsJPEG2000();
217        
218       bool res;
219       guint16 ItemTagGr,ItemTagEl;
220       int ln;  //  Position on begining of Jpeg Pixels
221       
222       fread(&ItemTagGr,2,1,fp);  // Reading (fffe) : Item Tag Gr
223       fread(&ItemTagEl,2,1,fp);  // Reading (e000) : Item Tag El
224       if(GetSwapCode()) {
225          ItemTagGr=SwapShort(ItemTagGr); 
226          ItemTagEl=SwapShort(ItemTagEl);            
227       }
228       fread(&ln,4,1,fp); 
229       if(GetSwapCode()) 
230          ln=SwapLong(ln);    // Basic Offset Table Item length
231          
232       if (ln != 0) {
233          // What is it used for ?!?
234          char *BasicOffsetTableItemValue = (char *)malloc(ln+1);        
235          fread(BasicOffsetTableItemValue,ln,1,fp); 
236       }
237       
238       // first Fragment initialisation
239       fread(&ItemTagGr,2,1,fp);  // Reading (fffe) : Item Tag Gr
240       fread(&ItemTagEl,2,1,fp);  // Reading (e000) : Item Tag El
241       if(GetSwapCode()) {
242          ItemTagGr=SwapShort(ItemTagGr); 
243          ItemTagEl=SwapShort(ItemTagEl);            
244       }
245               
246       // parsing fragments until Sequence Delim. Tag found
247       //unsigned short *dest = (unsigned short *)destination;
248          
249       while (  ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) {      
250          fread(&ln,4,1,fp); 
251          if(GetSwapCode()) 
252             ln=SwapLong(ln);    // Fragment Item length
253       
254          // FIXME : multi fragments 
255          fragmentBegining=ftell(fp);   
256  
257          if (b)
258             res = (bool)gdcm_read_JPEG2000_file (destination);  // Not Yet written 
259             
260          else if (IsJPEGLossless()) { // JPEG LossLess : call to LibIDO Jpeg
261                   
262                   // -------------  for each Fragment
263                   
264                   // Warning : Works only if there is one fragment per frame
265                   //           (Or a single fragment for the multiframe file)
266             ClbJpeg* jpg = _IdDcmJpegRead(fp); // TODO : find a 'full' one.
267                                                // (We use the LibIDO one :-(
268             if(jpg == NULL) {
269                CloseFile();
270                return false;
271             }      
272             int * dataJpg = jpg->DataImg;
273             unsigned short *dest = (unsigned short *)destination;
274             switch (nBytes) {   
275                case 1:
276                {
277                   for (int i=0; i<taille; i++) {
278                      *((unsigned char *)dest+i) = *(dataJpg +i);   
279                   }
280                break;
281                }        
282          
283                case 2:
284                {
285                   for (int i=0; i<taille; i++) {        
286                      *((unsigned short *)dest+i) = *(dataJpg +i);    
287                   }
288                break;
289                }       
290            } 
291            _IdDcmJpegFree (jpg);
292            
293            res=1; // in order not to break the loop
294      
295          } // ------------------------------------- endif (IsJPEGLossless())
296                   
297          else  //               JPEG Lossy : call to IJG 6b
298             if  (GetBitsStored() == 8) {
299                 res = (bool)gdcm_read_JPEG_file (destination);  // Reading Fragment pixels         
300             } else {
301                 res = (bool)gdcm_read_JPEG_file12 (destination);// Reading Fragment pixels  
302             }       
303             
304          if (!res) break;
305                   
306          destination = (char *)destination + taille * nBytes; // location in user's memory 
307                                                               // for next fragment (if any) 
308          
309          fseek(fp,fragmentBegining,SEEK_SET); // To be sure we start 
310          fseek(fp,ln,SEEK_CUR);               // at the begining of next fragment
311          
312          ItemTagGr = ItemTagEl =0;
313          fread(&ItemTagGr,2,1,fp);  // Reading (fffe) : Item Tag Gr
314          fread(&ItemTagEl,2,1,fp);  // Reading (e000) : Item Tag El
315          if(GetSwapCode()) {
316             ItemTagGr=SwapShort(ItemTagGr); 
317             ItemTagEl=SwapShort(ItemTagEl);            
318          } 
319       
320       }     // endWhile parsing fragments until Sequence Delim. Tag found    
321                 
322       return res;
323 }   
324
325 /**
326  * \ingroup gdcmFile
327  * \brief   Allocates necessary memory, copies the pixel data
328  *          (image[s]/volume[s]) to newly allocated zone.
329  * @return  Pointer to newly allocated pixel data.
330  * \        NULL if alloc fails 
331  */
332 void * gdcmFile::GetImageData (void) {
333    PixelData = (void *) malloc(lgrTotale);
334    if (PixelData)
335       GetImageDataIntoVector(PixelData, lgrTotale);
336    return(PixelData);
337 }
338
339 /**
340  * \ingroup gdcmFile
341  * \brief   Copies at most MaxSize bytes of pixel data to caller's
342  *          memory space.
343  * @param   destination Address (in caller's memory space) at which the
344  *          pixel data should be copied
345  * @param   MaxSize Maximum number of bytes to be copied. When MaxSize
346  *          is not sufficient to hold the pixel data the copy is not
347  *          executed (i.e. no partial copy).
348  * @return  On success, the number of bytes actually copied. Zero on
349  *          failure e.g. MaxSize is lower than necessary.
350  */
351
352 size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
353
354    int nb, nbu, highBit, signe;
355    std::string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
356  
357    if ( lgrTotale > MaxSize ) {
358       dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: pixel data bigger"
359                      "than caller's expected MaxSize");
360       return (size_t)0; 
361    }
362         
363    (void)ReadPixelData(destination);
364                         
365         // Nombre de Bits Alloues pour le stockage d'un Pixel
366    str_nb = GetPubElValByNumber(0x0028,0x0100);
367    if (str_nb == GDCM_UNFOUND ) {
368       nb = 16;
369    } else {
370       nb = atoi(str_nb.c_str() );
371    }
372         
373         // Nombre de Bits Utilises
374    str_nbu=GetPubElValByNumber(0x0028,0x0101);
375    if (str_nbu == GDCM_UNFOUND ) {
376       nbu = nb;
377    } else {
378       nbu = atoi(str_nbu.c_str() );
379    }    
380         
381         // Position du Bit de Poids Fort
382    str_highBit=GetPubElValByNumber(0x0028,0x0102);
383    if (str_highBit == GDCM_UNFOUND ) {
384       highBit = nb - 1;
385    } else {
386       highBit = atoi(str_highBit.c_str() );
387    }
388                 
389         // Signe des Pixels 
390    str_signe=GetPubElValByNumber(0x0028,0x0103);
391    if (str_signe == GDCM_UNFOUND ) {
392       signe = 1;
393    } else {
394       signe = atoi(str_signe.c_str() );
395    }
396
397    // re arange bytes inside the integer
398    if (nb != 8)
399      SwapZone(destination, GetSwapCode(), lgrTotale, nb);
400  
401    // re arange bits inside the bytes
402    if (nbu != nb){
403       int l = (int)lgrTotale / (nb/8);
404       if (nb == 16) {
405          guint16 mask = 0xffff;
406          mask = mask >> (nb-nbu);
407          guint16 *deb = (guint16 *)destination;
408          for(int i = 0; i<l; i++) {
409             *deb = (*deb >> (nbu-highBit-1)) & mask;
410             deb ++;
411          }
412       } else if (nb == 32 ) {
413          guint32 mask = 0xffffffff;
414          mask = mask >> (nb-nbu);
415          guint32 *deb = (guint32 *)destination;
416          for(int i = 0; i<l; i++) {
417             *deb = (*deb >> (nbu-highBit-1)) & mask;
418             deb ++;
419          }
420       } else {
421          dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: wierd image");
422          return (size_t)0; 
423       }
424    } 
425
426 // Just to 'see' was was actually read on disk :-(
427 // Some troubles expected
428
429    // *Try* to deal with the color
430    // ----------------------------
431
432    // Planar configuration = 0 : Pixels are already RGB
433    // Planar configuration = 1 : 3 planes : R, G, B
434    // Planar configuration = 2 : 1 gray Plane + 3 LUT
435
436    // Well ... supposed to be !
437    // See US-PAL-8-10x-echo.dcm: PlanarConfiguration=0,PhotometricInterpretation=PALETTE COLOR
438    // and heuristic has to be found :-( 
439
440       std::string str_PhotometricInterpretation = gdcmHeader::GetPubElValByNumber(0x0028,0x0004);
441    
442       if ( (str_PhotometricInterpretation == "MONOCHROME1 ") 
443         || (str_PhotometricInterpretation == "MONOCHROME2 ") 
444         || (str_PhotometricInterpretation == "RGB")) {
445          return lgrTotale; 
446       }
447       int planConf=GetPlanarConfiguration();
448
449       // Whatever Planar Configuration is, "PALETTE COLOR " implies that we deal with the palette. 
450       if (str_PhotometricInterpretation == "PALETTE COLOR ")
451          planConf=2;
452
453       switch (planConf) {
454       case 0:                              
455          //       Pixels are already RGB
456          break;
457     
458       case 1:
459
460          {
461          if (str_PhotometricInterpretation == "YBR_FULL") { // Warning : YBR_FULL_422 acts as RGB (?!)
462
463          //       need to make RGB Pixels from Planes Y,cB,cR
464          // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
465          // for code optimisation
466
467             int l = GetXSize()*GetYSize();
468             int nbFrames = GetZSize();
469
470             unsigned char * newDest = (unsigned char*) malloc(lgrTotale);
471             unsigned char *x  = newDest;
472             unsigned char * a = (unsigned char *)destination;
473             unsigned char * b = a + l;
474             unsigned char * c = b + l;
475
476             double R,G,B;
477
478             // TODO : Replace by the 'well known' 
479             //        integer computation counterpart
480             for (int i=0;i<nbFrames;i++) {
481                for (int j=0;j<l; j++) {
482                   R= 1.164 *( *a-16) + 1.596 *( *c -128) + 0.5;
483                   G= 1.164 *( *a-16) - 0.813 *( *c -128) - 0.392 *(*b -128) + 0.5;
484                   B= 1.164 *( *a-16) + 2.017 *( *b -128) + 0.5;
485
486                   if (R<0.0)   R=0.0;
487                   if (G<0.0)   G=0.0;
488                   if (B<0.0)   B=0.0;
489                   if (R>255.0) R=255.0;
490                   if (G>255.0) G=255.0;
491                   if (B>255.0) B=255.0;
492
493                   *(x++) = (unsigned char)R;
494                   *(x++) = (unsigned char)G;
495                   *(x++) = (unsigned char)B;
496                   a++; b++; c++;  
497                }
498            }
499             memmove(destination,newDest,lgrTotale);
500             free(newDest);
501
502         } else {
503          
504          //       need to make RGB Pixels from Planes R,G,B
505
506             int l = GetXSize()*GetYSize();
507             int nbFrames = GetZSize();
508
509             char * newDest = (char*) malloc(lgrTotale);
510             char *x  = newDest;
511             char * a = (char *)destination;
512             char * b = a + l;
513             char * c = b + l;
514
515                // TODO :
516                // any trick not to have to allocate temporary buffer is welcome ...
517
518             for (int i=0;i<nbFrames;i++) {
519                for (int j=0;j<l; j++) {
520                   *(x++) = *(a++);
521                   *(x++) = *(b++);
522                   *(x++) = *(c++);  
523                }
524             }
525             memmove(destination,newDest,lgrTotale);
526             free(newDest);
527         }
528
529             // now, it's an RGB image
530             // Lets's write it in the Header
531          std::string spp = "3";
532          gdcmHeader::SetPubElValByNumber(spp,0x0028,0x0002);
533          std::string rgb="RGB";
534          gdcmHeader::SetPubElValByNumber(rgb,0x0028,0x0004);
535          break;
536        }
537      
538        case 2:                      
539          //       from Lut R + Lut G + Lut B
540        
541          // we no longer use gdcmHeader::GetLUTRGB
542          // since a lot of images have strange info 
543          // in the Lookup Table Descriptors (0028,1101),...
544          {
545          unsigned char * newDest = (unsigned char*) malloc(lgrTotale);
546          unsigned char * a = (unsigned char *)destination;
547
548          unsigned char *lutR =(unsigned char *)GetPubElValVoidAreaByNumber(0x0028,0x1201);
549          unsigned char *lutG =(unsigned char *)GetPubElValVoidAreaByNumber(0x0028,0x1202);
550          unsigned char *lutB =(unsigned char *)GetPubElValVoidAreaByNumber(0x0028,0x1203);
551
552          if (lutR && lutG && lutB ) { // need to make RGB Pixels 
553                                       // from grey Pixels 
554                                       // and Lut R,Lut G,Lut B
555
556             unsigned char * newDest = (unsigned char*) malloc(lgrTotale);
557             int l = lgrTotale/3;
558             memmove(newDest, destination, l);// move Gray pixels to temp area
559
560             unsigned char * x = newDest;
561
562             int j;
563                // See PS 3.3-2003 C.11.1.1.2 p 619
564                // 
565             int mult;
566             if ( GetLUTNbits()==16 && nb==8) mult=2; // See PS 3.3 
567             else mult=1;
568
569             // if we get a black image, let's just remove the '+1'
570             // and check again 
571             // if it works, we shall have to check the 3 Palettes
572             // to see which byte is ==0 (first one, on second one)        
573        
574             for (int i=0;i<l; i++) {
575                j=newDest[i]*mult +1;
576                *a++ = lutR[j]; 
577                *a++ = lutG[j];
578                *a++ = lutB[j];
579             }
580
581             free(newDest);
582         
583                // now, it's an RGB image      
584            std::string spp = "3";
585            gdcmHeader::SetPubElValByNumber(spp,0x0028,0x0002); 
586            std::string rgb="RGB";
587            gdcmHeader::SetPubElValByNumber(rgb,0x0028,0x0004);
588                
589          } else { // need to make RGB Pixels (?)
590                   // from grey Pixels (?!)
591                   // and Gray Lut  (!?!) 
592                unsigned char *lutGray =(unsigned char *)GetPubElValVoidAreaByNumber(0x0028,0x1200);
593                     // Well . I'll wait till I find such an image 
594          }
595          break;
596          }
597    } 
598     
599    return lgrTotale; 
600 }
601
602 //
603 // Je laisse le code integral, au cas ça puisse etre reutilise ailleurs
604 //
605
606 /**
607  * \ingroup gdcmFile
608  * \brief   Swap the bytes, according to swap code.
609  * \warning not end user intended
610  * @param   im area to deal with
611  * @param   swap swap code
612  * @param   lgr Area Length
613  * @param   nb Pixels Bit number 
614  */
615
616 void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) {
617 guint32 s32;
618 guint16 fort,faible;
619 int i;
620
621 if(nb == 16)  
622    switch(swap) {
623       case 0:
624       case 12:
625       case 1234:
626          break;
627                 
628       case 21:
629       case 3412:
630       case 2143:
631       case 4321:
632
633          for(i=0;i<lgr;i++)
634             ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
635                                         | ((((unsigned short int*)im)[i])<<8);
636          break;
637                         
638       default:
639          printf("valeur de SWAP (16 bits) not allowed : %d\n", swap);
640    } 
641  
642 if( nb == 32 )
643    switch (swap) {
644       case 0:
645       case 1234:
646          break;
647
648       case 4321:
649          for(i=0;i<lgr;i++) {
650             faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 4321 */
651             fort  =((unsigned long int*)im)[i]>>16;
652             fort=  (fort>>8)   | (fort<<8);
653             faible=(faible>>8) | (faible<<8);
654             s32=faible;
655             ((unsigned long int*)im)[i]=(s32<<16)|fort;
656          }
657          break;
658
659       case 2143:
660          for(i=0;i<lgr;i++) {
661             faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 2143 */
662             fort=((unsigned long int*)im)[i]>>16;
663             fort=  (fort>>8)   | (fort<<8);
664             faible=(faible>>8) | (faible<<8);
665             s32=fort; 
666             ((unsigned long int*)im)[i]=(s32<<16)|faible;
667          }
668          break;
669   
670       case 3412:
671          for(i=0;i<lgr;i++) {
672             faible=  ((unsigned long int*)im)[i]&0x0000ffff;    /* 3412 */
673             fort=((unsigned long int*)im)[i]>>16;                  
674             s32=faible; 
675             ((unsigned long int*)im)[i]=(s32<<16)|fort;
676          }                 
677          break; 
678                                 
679       default:
680          printf(" SWAP value (32 bits) not allowed : %d\n", swap);
681    } 
682 return;
683 }
684
685 /////////////////////////////////////////////////////////////////
686 /**
687  * \ingroup   gdcmFile
688  * \brief TODO JPR
689  * \warning doit-etre etre publique ?  
690  * TODO : y a-t-il un inconvenient à fusioner ces 2 fonctions
691  *
692  * @param inData 
693  * @param ExpectedSize 
694  *
695  * @return integer acts as a boolean    
696  */
697 int gdcmFile::SetImageData(void * inData, size_t ExpectedSize) {
698    SetImageDataSize(ExpectedSize);
699    PixelData = inData;
700    lgrTotale = ExpectedSize;
701    return(1);
702 }
703
704
705 /////////////////////////////////////////////////////////////////
706 /**
707  * \ingroup   gdcmFile
708  * \brief Sets the Pixel Area size in the Header
709  *        --> not-for-rats function
710  * 
711  * \warning WARNING doit-etre etre publique ? 
712  * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions
713  *
714  * @param ImageDataSize new Pixel Area Size
715  *        warning : nothing else is checked
716  */
717
718 void gdcmFile::SetImageDataSize(size_t ImageDataSize) {
719    std::string content1;
720    char car[20];        
721    // Assumes ElValue (0x7fe0, 0x0010) exists ...       
722    sprintf(car,"%d",ImageDataSize);
723  
724    gdcmElValue*a = GetElValueByNumber(0x7fe0, 0x0010);
725    a->SetLength(ImageDataSize);
726                 
727    ImageDataSize+=8;
728    sprintf(car,"%d",ImageDataSize);
729    content1=car;        
730    SetPubElValByNumber(content1, 0x7fe0, 0x0000);
731 }
732
733
734 /////////////////////////////////////////////////////////////////
735 /**
736  * \ingroup   gdcmFile
737  * \brief Ecrit sur disque les pixels d'UNE image
738  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
739  *        Ca sera à l'utilisateur d'appeler son Reader correctement
740  *        (Equivalent a IdImaWriteRawFile) 
741  *
742  * @param fileName 
743  * @return      
744  */
745
746 int gdcmFile::WriteRawData (std::string fileName) {
747    FILE * fp1;
748    fp1 = fopen(fileName.c_str(),"wb");
749    if (fp1 == NULL) {
750       printf("Echec ouverture (ecriture) Fichier [%s] \n",fileName.c_str());
751       return (0);
752    }    
753    fwrite (PixelData,lgrTotale, 1, fp1);
754    fclose (fp1);
755    return(1);
756 }
757
758 /////////////////////////////////////////////////////////////////
759 /**
760  * \ingroup   gdcmFile
761  * \brief Ecrit sur disque UNE image Dicom
762  *        Aucun test n'est fait sur l'"Endiannerie" du processeur.
763  *         Ca fonctionnera correctement (?) sur processeur Intel
764  *         (Equivalent a IdDcmWrite) 
765  *
766  * @param fileName 
767  * @return int acts as a boolean
768  */
769
770 int gdcmFile::WriteDcmImplVR (std::string fileName) {
771    return WriteBase(fileName, ImplicitVR);
772 }
773
774 /////////////////////////////////////////////////////////////////
775 /**
776  * \ingroup   gdcmFile
777  * \brief  
778  * @param  fileName 
779  * @return int acts as a boolean
780  */
781  
782 int gdcmFile::WriteDcmImplVR (const char* fileName) {
783    return WriteDcmImplVR (std::string (fileName));
784 }
785         
786 /////////////////////////////////////////////////////////////////
787 /**
788  * \ingroup   gdcmFile
789  * \brief  
790  * @param  fileName
791  * @return int acts as a boolean
792  */
793
794 int gdcmFile::WriteDcmExplVR (std::string fileName) {
795    return WriteBase(fileName, ExplicitVR);
796 }
797         
798 /////////////////////////////////////////////////////////////////
799 /**
800  * \ingroup   gdcmFile
801  * \brief  Ecrit au format ACR-NEMA sur disque l'entete et les pixels
802  *        (a l'attention des logiciels cliniques 
803  *        qui ne prennent en entrée QUE des images ACR ...
804  * \warning si un header DICOM est fourni en entree,
805  *        les groupes < 0x0008 et les groupes impairs sont ignores)
806  * \warning Aucun test n'est fait sur l'"Endiannerie" du processeur.
807  *        Ca fonctionnera correctement (?) sur processeur Intel
808  *        (Equivalent a IdDcmWrite) 
809  *
810  * @param fileName
811  * @return int acts as a boolean        
812  */
813
814 int gdcmFile::WriteAcr (std::string fileName) {
815    return WriteBase(fileName, ACR);
816 }
817
818 /////////////////////////////////////////////////////////////////
819 /**
820  * \ingroup   gdcmFile
821  *
822  * @param  FileName
823  * @param  type 
824  *
825  * @return int acts as a boolean
826  */
827 int gdcmFile::WriteBase (std::string FileName, FileType type) {
828
829    FILE * fp1;
830    fp1 = fopen(FileName.c_str(),"wb");
831    if (fp1 == NULL) {
832       printf("Echec ouverture (ecriture) Fichier [%s] \n",FileName.c_str());
833       return (0);
834    }
835
836    if ( (type == ImplicitVR) || (type == ExplicitVR) ) {
837       char * filePreamble;
838       // writing Dicom File Preamble
839       filePreamble=(char*)calloc(128,1);
840       fwrite(filePreamble,128,1,fp1);
841       fwrite("DICM",4,1,fp1);
842    }
843
844    // --------------------------------------------------------------
845    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
846    //
847    // if recognition code tells us we dealt with a LibIDO image
848    // we reproduce on disk the switch between lineNumber and columnNumber
849    // just before writting ...
850
851    std::string rows, columns; 
852    if ( filetype == ACR_LIBIDO){
853          rows    = GetPubElValByNumber(0x0028, 0x0010);
854          columns = GetPubElValByNumber(0x0028, 0x0011);
855          SetPubElValByNumber(columns,  0x0028, 0x0010);
856          SetPubElValByNumber(rows   ,  0x0028, 0x0011);
857    }    
858    // ----------------- End of Special Patch ----------------
859
860    gdcmHeader::Write(fp1, type);
861
862    // --------------------------------------------------------------
863    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
864    // 
865    // ...and we restore the Header to be Dicom Compliant again 
866    // just after writting
867
868    if (filetype == ACR_LIBIDO){
869          SetPubElValByNumber(rows   , 0x0028, 0x0010);
870          SetPubElValByNumber(columns, 0x0028, 0x0011);
871    }    
872    // ----------------- End of Special Patch ----------------
873
874    fwrite(PixelData, lgrTotale, 1, fp1);
875    fclose (fp1);
876    return(1);
877 }