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