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