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