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