]> Creatis software - gdcm.git/blob - src/gdcmFileHelper.cxx
Stage 2 of names normalization :
[gdcm.git] / src / gdcmFileHelper.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFileHelper.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/21 11:40:55 $
7   Version:   $Revision: 1.2 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmFileHelper.h"
20 #include "gdcmGlobal.h"
21 #include "gdcmTS.h"
22 #include "gdcmDocument.h"
23 #include "gdcmDebug.h"
24 #include "gdcmUtil.h"
25 #include "gdcmBinEntry.h"
26 #include "gdcmFile.h"
27 #include "gdcmPixelReadConvert.h"
28 #include "gdcmPixelWriteConvert.h"
29 #include "gdcmDocEntryArchive.h"
30
31 #include <fstream>
32
33 namespace gdcm 
34 {
35 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
36
37 //-------------------------------------------------------------------------
38 // Constructor / Destructor
39 /**
40  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
41  *        file (gdcm::File only deals with the ... header)
42  *        Opens (in read only and when possible) an existing file and checks
43  *        for DICOM compliance. Returns NULL on failure.
44  *        It will be up to the user to load the pixels into memory
45  * \note  the in-memory representation of all available tags found in
46  *        the DICOM header is post-poned to first header information access.
47  *        This avoid a double parsing of public part of the header when
48  *        one sets an a posteriori shadow dictionary (efficiency can be
49  *        seen as a side effect).   
50  */
51 FileHelper::FileHelper( )
52 {
53    FileInternal = new File( );
54    SelfHeader = true;
55    Initialize();
56 }
57
58 /**
59  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
60  *        file (File only deals with the ... header)
61  *        Opens (in read only and when possible) an existing file and checks
62  *        for DICOM compliance. Returns NULL on failure.
63  *        It will be up to the user to load the pixels into memory
64  * \note  the in-memory representation of all available tags found in
65  *        the DICOM header is post-poned to first header information access.
66  *        This avoid a double parsing of public part of the header when
67  *        user sets an a posteriori shadow dictionary (efficiency can be
68  *        seen as a side effect).   
69  * @param header already built Header
70  */
71 FileHelper::FileHelper(File *header)
72 {
73    FileInternal = header;
74    SelfHeader = false;
75    Initialize();
76 }
77
78 /**
79  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
80  *        file (gdcm::File only deals with the ... header)
81  *        Opens (in read only and when possible) an existing file and checks
82  *        for DICOM compliance. Returns NULL on failure.
83  *        It will be up to the user to load the pixels into memory
84  * \note  the in-memory representation of all available tags found in
85  *        the DICOM header is post-poned to first header information access.
86  *        This avoid a double parsing of public part of the header when
87  *        one sets an a posteriori shadow dictionary (efficiency can be
88  *        seen as a side effect).   
89  * @param filename file to be opened for parsing
90  */
91 FileHelper::FileHelper(std::string const & filename )
92 {
93    FileInternal = new File( filename );
94    SelfHeader = true;
95    Initialize();
96 }
97
98 /**
99  * \brief canonical destructor
100  * \note  If the header (gdcm::File) was created by the FileHelper constructor,
101  *        it is destroyed by the FileHelper
102  */
103 FileHelper::~FileHelper()
104
105    if( PixelReadConverter )
106    {
107       delete PixelReadConverter;
108    }
109    if( PixelWriteConverter )
110    {
111       delete PixelWriteConverter;
112    }
113    if( Archive )
114    {
115       delete Archive;
116    }
117
118    if( SelfHeader )
119    {
120       delete FileInternal;
121    }
122    FileInternal = 0;
123 }
124
125 //-----------------------------------------------------------------------------
126 // Print
127 void FileHelper::Print(std::ostream &os, std::string const &)
128 {
129    FileInternal->SetPrintLevel(PrintLevel);
130    FileInternal->Print(os);
131
132    PixelReadConverter->SetPrintLevel(PrintLevel);
133    PixelReadConverter->Print(os);
134 }
135
136 //-----------------------------------------------------------------------------
137 // Public
138 /**
139  * \brief   Get the size of the image data
140  *          If the image can be RGB (with a lut or by default), the size 
141  *          corresponds to the RGB image
142  *         (use GetImageDataRawSize if you want to be sure to get *only*
143  *          the size of the pixels)
144  * @return  The image size
145  */
146 size_t FileHelper::GetImageDataSize()
147 {
148    if ( PixelWriteConverter->GetUserData() )
149    {
150       return PixelWriteConverter->GetUserDataSize();
151    }
152
153    return PixelReadConverter->GetRGBSize();
154 }
155
156 /**
157  * \brief   Get the size of the image data
158  *          If the image could be converted to RGB using a LUT, 
159  *          this transformation is not taken into account by GetImageDataRawSize
160  *          (use GetImageDataSize if you wish)
161  * @return  The raw image size
162  */
163 size_t FileHelper::GetImageDataRawSize()
164 {
165    if ( PixelWriteConverter->GetUserData() )
166    {
167       return PixelWriteConverter->GetUserDataSize();
168    }
169
170    return PixelReadConverter->GetRawSize();
171 }
172
173 /**
174  * \brief   - Allocates necessary memory, 
175  *          - Reads the pixels from disk (uncompress if necessary),
176  *          - Transforms YBR pixels, if any, into RGB pixels
177  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
178  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
179  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
180  * @return  Pointer to newly allocated pixel data.
181  *          NULL if alloc fails 
182  */
183 uint8_t *FileHelper::GetImageData()
184 {
185    if ( PixelWriteConverter->GetUserData() )
186    {
187       return PixelWriteConverter->GetUserData();
188    }
189
190    if ( ! GetRaw() )
191    {
192       // If the decompression failed nothing can be done.
193       return 0;
194    }
195
196    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
197    {
198       return PixelReadConverter->GetRGB();
199    }
200    else
201    {
202       // When no LUT or LUT conversion fails, return the Raw
203       return PixelReadConverter->GetRaw();
204    }
205 }
206
207 /**
208  * \brief   Allocates necessary memory, 
209  *          Transforms YBR pixels (if any) into RGB pixels
210  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
211  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
212  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
213  * @return  Pointer to newly allocated pixel data.
214  * \        NULL if alloc fails 
215  */
216 uint8_t *FileHelper::GetImageDataRaw ()
217 {
218    return GetRaw();
219 }
220
221 /**
222  * \brief
223  *          Read the pixels from disk (uncompress if necessary),
224  *          Transforms YBR pixels, if any, into RGB pixels
225  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
226  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
227  *          Copies at most MaxSize bytes of pixel data to caller allocated
228  *          memory space.
229  * \warning This function allows people that want to build a volume
230  *          from an image stack *not to* have, first to get the image pixels, 
231  *          and then move them to the volume area.
232  *          It's absolutely useless for any VTK user since vtk chooses 
233  *          to invert the lines of an image, that is the last line comes first
234  *          (for some axis related reasons?). Hence he will have 
235  *          to load the image line by line, starting from the end.
236  *          VTK users have to call GetImageData
237  *     
238  * @param   destination Address (in caller's memory space) at which the
239  *          pixel data should be copied
240  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
241  *          is not sufficient to hold the pixel data the copy is not
242  *          executed (i.e. no partial copy).
243  * @return  On success, the number of bytes actually copied. Zero on
244  *          failure e.g. MaxSize is lower than necessary.
245  */
246 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
247 {
248    if ( ! GetRaw() )
249    {
250       // If the decompression failed nothing can be done.
251       return 0;
252    }
253
254    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
255    {
256       if ( PixelReadConverter->GetRGBSize() > maxSize )
257       {
258          gdcmVerboseMacro( "Pixel data bigger than caller's expected MaxSize");
259          return 0;
260       }
261       memcpy( destination,
262               (void*)PixelReadConverter->GetRGB(),
263               PixelReadConverter->GetRGBSize() );
264       return PixelReadConverter->GetRGBSize();
265    }
266
267    // Either no LUT conversion necessary or LUT conversion failed
268    if ( PixelReadConverter->GetRawSize() > maxSize )
269    {
270       gdcmVerboseMacro( "Pixel data bigger than caller's expected MaxSize");
271       return 0;
272    }
273    memcpy( destination,
274            (void*)PixelReadConverter->GetRaw(),
275            PixelReadConverter->GetRawSize() );
276    return PixelReadConverter->GetRawSize();
277 }
278
279 /**
280  * \brief   Points the internal pointer to the callers inData
281  *          image representation, BUT WITHOUT COPYING THE DATA.
282  *          'image' Pixels are presented as C-like 2D arrays : line per line.
283  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
284  * \warning Since the pixels are not copied, it is the caller's responsability
285  *          not to deallocate it's data before gdcm uses them (e.g. with
286  *          the Write() method.
287  * @param inData user supplied pixel area
288  * @param expectedSize total image size, in Bytes
289  *
290  * @return boolean
291  */
292 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
293 {
294    SetUserData(inData,expectedSize);
295 }
296
297 /**
298  * \brief   Set the image datas defined by the user
299  * \warning When writting the file, this datas are get as default datas to write
300  */
301 void FileHelper::SetUserData(uint8_t *data, size_t expectedSize)
302 {
303    PixelWriteConverter->SetUserData(data,expectedSize);
304 }
305
306 /**
307  * \brief   Get the image datas defined by the user
308  * \warning When writting the file, this datas are get as default data to write
309  */
310 uint8_t *FileHelper::GetUserData()
311 {
312    return PixelWriteConverter->GetUserData();
313 }
314
315 /**
316  * \brief   Get the image data size defined by the user
317  * \warning When writting the file, this datas are get as default data to write
318  */
319 size_t FileHelper::GetUserDataSize()
320 {
321    return PixelWriteConverter->GetUserDataSize();
322 }
323
324 /**
325  * \brief   Get the image datas from the file.
326  *          If a LUT is found, the data are expanded to be RGB
327  */
328 uint8_t *FileHelper::GetRGBData()
329 {
330    return PixelReadConverter->GetRGB();
331 }
332
333 /**
334  * \brief   Get the image data size from the file.
335  *          If a LUT is found, the data are expanded to be RGB
336  */
337 size_t FileHelper::GetRGBDataSize()
338 {
339    return PixelReadConverter->GetRGBSize();
340 }
341
342 /**
343  * \brief   Get the image datas from the file.
344  *          If a LUT is found, the datas are not expanded !
345  */
346 uint8_t *FileHelper::GetRawData()
347 {
348    return PixelReadConverter->GetRaw();
349 }
350
351 /**
352  * \brief   Get the image data size from the file.
353  *          If a LUT is found, the data are not expanded !
354  */
355 size_t FileHelper::GetRawDataSize()
356 {
357    return PixelReadConverter->GetRawSize();
358 }
359
360 /**
361  * \brief Writes on disk A SINGLE Dicom file
362  *        NO test is performed on  processor "Endiannity".
363  *        It's up to the user to call his Reader properly
364  * @param fileName name of the file to be created
365  *                 (any already existing file is over written)
366  * @return false if write fails
367  */
368
369 bool FileHelper::WriteRawData(std::string const &fileName)
370 {
371   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
372    if (!fp1)
373    {
374       gdcmVerboseMacro( "Fail to open (write) file:" << fileName.c_str());
375       return false;
376    }
377
378    if( PixelWriteConverter->GetUserData() )
379    {
380       fp1.write( (char*)PixelWriteConverter->GetUserData(), 
381                  PixelWriteConverter->GetUserDataSize() );
382    }
383    else if ( PixelReadConverter->GetRGB() )
384    {
385       fp1.write( (char*)PixelReadConverter->GetRGB(), 
386                  PixelReadConverter->GetRGBSize());
387    }
388    else if ( PixelReadConverter->GetRaw() )
389    {
390       fp1.write( (char*)PixelReadConverter->GetRaw(), 
391                  PixelReadConverter->GetRawSize());
392    }
393    else
394    {
395       gdcmErrorMacro( "Nothing written." );
396    }
397
398    fp1.close();
399
400    return true;
401 }
402
403 /**
404  * \brief Writes on disk A SINGLE Dicom file, 
405  *        using the Implicit Value Representation convention
406  *        NO test is performed on  processor "Endiannity".
407  * @param fileName name of the file to be created
408  *                 (any already existing file is overwritten)
409  * @return false if write fails
410  */
411
412 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
413 {
414    SetWriteTypeToDcmImplVR();
415    return Write(fileName);
416 }
417
418 /**
419 * \brief Writes on disk A SINGLE Dicom file, 
420  *        using the Explicit Value Representation convention
421  *        NO test is performed on  processor "Endiannity". 
422  * @param fileName name of the file to be created
423  *                 (any already existing file is overwritten)
424  * @return false if write fails
425  */
426
427 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
428 {
429    SetWriteTypeToDcmExplVR();
430    return Write(fileName);
431 }
432
433 /**
434  * \brief Writes on disk A SINGLE Dicom file, 
435  *        using the ACR-NEMA convention
436  *        NO test is performed on  processor "Endiannity".
437  *        (a l'attention des logiciels cliniques 
438  *        qui ne prennent en entrée QUE des images ACR ...
439  * \warning if a DICOM_V3 header is supplied,
440  *         groups < 0x0008 and shadow groups are ignored
441  * \warning NO TEST is performed on processor "Endiannity".
442  * @param fileName name of the file to be created
443  *                 (any already existing file is overwritten)
444  * @return false if write fails
445  */
446
447 bool FileHelper::WriteAcr (std::string const &fileName)
448 {
449    SetWriteTypeToAcr();
450    return Write(fileName);
451 }
452
453 /**
454  * \brief Writes on disk A SINGLE Dicom file, 
455  * @param fileName name of the file to be created
456  *                 (any already existing file is overwritten)
457  * @return false if write fails
458  */
459 bool FileHelper::Write(std::string const &fileName)
460 {
461    switch(WriteType)
462    {
463       case ImplicitVR:
464          SetWriteFileTypeToImplicitVR();
465          break;
466       case ExplicitVR:
467          SetWriteFileTypeToExplicitVR();
468          break;
469       case ACR:
470       case ACR_LIBIDO:
471          SetWriteFileTypeToACR();
472          break;
473       default:
474          SetWriteFileTypeToExplicitVR();
475    }
476
477    // --------------------------------------------------------------
478    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
479    //
480    // if recognition code tells us we dealt with a LibIDO image
481    // we reproduce on disk the switch between lineNumber and columnNumber
482    // just before writting ...
483    /// \todo the best trick would be *change* the recognition code
484    ///       but pb expected if user deals with, e.g. COMPLEX images
485    if( WriteType == ACR_LIBIDO )
486    {
487       SetWriteToLibido();
488    }
489    else
490    {
491       SetWriteToNoLibido();
492    }
493    // ----------------- End of Special Patch ----------------
494   
495    switch(WriteMode)
496    {
497       case WMODE_RAW :
498          SetWriteToRaw();
499          break;
500       case WMODE_RGB :
501          SetWriteToRGB();
502          break;
503    }
504
505    bool check = CheckWriteIntegrity();
506    if(check)
507    {
508       check = FileInternal->Write(fileName,WriteType);
509    }
510
511    RestoreWrite();
512    RestoreWriteFileType();
513
514    // --------------------------------------------------------------
515    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
516    // 
517    // ...and we restore the header to be Dicom Compliant again 
518    // just after writting
519    RestoreWriteOfLibido();
520    // ----------------- End of Special Patch ----------------
521
522    return check;
523 }
524
525 /**
526  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
527  *          through it's (group, element) and modifies it's content with
528  *          the given value.
529  * @param   content new value (string) to substitute with
530  * @param   group     group number of the Dicom Element to modify
531  * @param   elem element number of the Dicom Element to modify
532  */
533 bool FileHelper::SetEntry(std::string const &content,
534                     uint16_t group, uint16_t elem)
535
536    return FileInternal->SetEntry(content,group,elem);
537 }
538
539
540 /**
541  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
542  *          through it's (group, element) and modifies it's content with
543  *          the given value.
544  * @param   content new value (void*  -> uint8_t*) to substitute with
545  * @param   lgth new value length
546  * @param   group     group number of the Dicom Element to modify
547  * @param   elem element number of the Dicom Element to modify
548  */
549 bool FileHelper::SetEntry(uint8_t *content, int lgth,
550                     uint16_t group, uint16_t elem)
551 {
552    return FileInternal->SetEntry(content,lgth,group,elem);
553 }
554
555 /**
556  * \brief   Modifies the value of a given DocEntry (Dicom entry)
557  *          when it exists. Create it with the given value when unexistant.
558  * @param   content (string) Value to be set
559  * @param   group   Group number of the Entry 
560  * @param   elem  Element number of the Entry
561  * \return  pointer to the modified/created Dicom entry (NULL when creation
562  *          failed).
563  */ 
564 bool FileHelper::ReplaceOrCreate(std::string const &content,
565                            uint16_t group, uint16_t elem)
566 {
567    return FileInternal->ReplaceOrCreate(content,group,elem) != NULL;
568 }
569
570 /*
571  * \brief   Modifies the value of a given DocEntry (Dicom entry)
572  *          when it exists. Create it with the given value when unexistant.
573  *          A copy of the binArea is made to be kept in the Document.
574  * @param   binArea (binary) value to be set
575  * @param   group   Group number of the Entry 
576  * @param   elem  Element number of the Entry
577  * \return  pointer to the modified/created Dicom entry (NULL when creation
578  *          failed).
579  */
580 bool FileHelper::ReplaceOrCreate(uint8_t *binArea, int lgth,
581                            uint16_t group, uint16_t elem)
582 {
583    return FileInternal->ReplaceOrCreate(binArea,lgth,group,elem) != NULL;
584 }
585
586 /**
587  * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
588  */
589 uint8_t* FileHelper::GetLutRGBA()
590 {
591    return PixelReadConverter->GetLutRGBA();
592 }
593
594 //-----------------------------------------------------------------------------
595 // Protected
596
597 /**
598  * \brief Check the write integrity
599  *
600  * The tests made are :
601  *  - verify the size of the image to write with the possible write
602  *    when the user set an image data
603  * @return true if the check successfulls
604  */
605 bool FileHelper::CheckWriteIntegrity()
606 {
607    if(PixelWriteConverter->GetUserData())
608    {
609       int numberBitsAllocated = FileInternal->GetBitsAllocated();
610       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
611       {
612          numberBitsAllocated = 16;
613       }
614
615       size_t decSize = FileInternal->GetXSize()
616                     * FileInternal->GetYSize() 
617                     * FileInternal->GetZSize()
618                     * ( numberBitsAllocated / 8 )
619                     * FileInternal->GetSamplesPerPixel();
620       size_t rgbSize = decSize;
621       if( FileInternal->HasLUT() )
622          rgbSize = decSize * 3;
623
624       switch(WriteMode)
625       {
626          case WMODE_RAW :
627             if( decSize!=PixelWriteConverter->GetUserDataSize() )
628             {
629                gdcmVerboseMacro( "Data size is incorrect (Raw)" << decSize 
630                     << " / " << PixelWriteConverter->GetUserDataSize() );
631                return false;
632             }
633             break;
634          case WMODE_RGB :
635             if( rgbSize!=PixelWriteConverter->GetUserDataSize() )
636             {
637                gdcmVerboseMacro( "Data size is incorrect (RGB)" << decSize
638                    << " / " << PixelWriteConverter->GetUserDataSize() );
639                return false;
640             }
641             break;
642       }
643    }
644    
645    return true;
646 }
647
648 /**
649  * \brief   
650  */ 
651 void FileHelper::SetWriteToRaw()
652 {
653    if( FileInternal->GetNumberOfScalarComponents() == 3 
654     && !FileInternal->HasLUT())
655    {
656       SetWriteToRGB();
657    } 
658    else
659    {
660       ValEntry *photInt = CopyValEntry(0x0028,0x0004);
661       if(FileInternal->HasLUT())
662       {
663          photInt->SetValue("PALETTE COLOR ");
664       }
665       else
666       {
667          photInt->SetValue("MONOCHROME1 ");
668       }
669
670       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
671                                        PixelReadConverter->GetRawSize());
672
673       BinEntry *pixel = 
674          CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
675       pixel->SetValue(GDCM_BINLOADED);
676       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
677       pixel->SetLength(PixelWriteConverter->GetDataSize());
678
679       Archive->Push(photInt);
680       Archive->Push(pixel);
681    }
682 }
683
684 /**
685  * \brief   
686  */ 
687 void FileHelper::SetWriteToRGB()
688 {
689    if(FileInternal->GetNumberOfScalarComponents()==3)
690    {
691       PixelReadConverter->BuildRGBImage();
692       
693       ValEntry *spp = CopyValEntry(0x0028,0x0002);
694       spp->SetValue("3 ");
695
696       ValEntry *planConfig = CopyValEntry(0x0028,0x0006);
697       planConfig->SetValue("0 ");
698
699       ValEntry *photInt = CopyValEntry(0x0028,0x0004);
700       photInt->SetValue("RGB ");
701
702       if(PixelReadConverter->GetRGB())
703       {
704          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
705                                           PixelReadConverter->GetRGBSize());
706       }
707       else // Raw data
708       {
709          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
710                                           PixelReadConverter->GetRawSize());
711       }
712
713       BinEntry *pixel = 
714          CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
715       pixel->SetValue(GDCM_BINLOADED);
716       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
717       pixel->SetLength(PixelWriteConverter->GetDataSize());
718
719       Archive->Push(spp);
720       Archive->Push(planConfig);
721       Archive->Push(photInt);
722       Archive->Push(pixel);
723
724       // Remove any LUT
725       Archive->Push(0x0028,0x1101);
726       Archive->Push(0x0028,0x1102);
727       Archive->Push(0x0028,0x1103);
728       Archive->Push(0x0028,0x1201);
729       Archive->Push(0x0028,0x1202);
730       Archive->Push(0x0028,0x1203);
731
732       // For old ACR-NEMA
733       // Thus, we have a RGB image and the bits allocated = 24 and 
734       // samples per pixels = 1 (in the read file)
735       if(FileInternal->GetBitsAllocated()==24) 
736       {
737          ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100);
738          bitsAlloc->SetValue("8 ");
739
740          ValEntry *bitsStored = CopyValEntry(0x0028,0x0101);
741          bitsStored->SetValue("8 ");
742
743          ValEntry *highBit = CopyValEntry(0x0028,0x0102);
744          highBit->SetValue("7 ");
745
746          Archive->Push(bitsAlloc);
747          Archive->Push(bitsStored);
748          Archive->Push(highBit);
749       }
750    }
751    else
752    {
753       SetWriteToRaw();
754    }
755 }
756
757 /**
758  * \brief   
759  */ 
760 void FileHelper::RestoreWrite()
761 {
762    Archive->Restore(0x0028,0x0002);
763    Archive->Restore(0x0028,0x0004);
764    Archive->Restore(0x0028,0x0006);
765    Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
766
767    // For old ACR-NEMA (24 bits problem)
768    Archive->Restore(0x0028,0x0100);
769    Archive->Restore(0x0028,0x0101);
770    Archive->Restore(0x0028,0x0102);
771
772    // For the LUT
773    Archive->Restore(0x0028,0x1101);
774    Archive->Restore(0x0028,0x1102);
775    Archive->Restore(0x0028,0x1103);
776    Archive->Restore(0x0028,0x1201);
777    Archive->Restore(0x0028,0x1202);
778    Archive->Restore(0x0028,0x1203);
779 }
780
781 /**
782  * \brief   
783  */ 
784 void FileHelper::SetWriteFileTypeToACR()
785 {
786    Archive->Push(0x0002,0x0010);
787 }
788
789 /**
790  * \brief   
791  */ 
792 void FileHelper::SetWriteFileTypeToExplicitVR()
793 {
794    std::string ts = Util::DicomString( 
795       Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
796
797    ValEntry *tss = CopyValEntry(0x0002,0x0010);
798    tss->SetValue(ts);
799
800    Archive->Push(tss);
801 }
802
803 /**
804  * \brief   
805  */ 
806 void FileHelper::SetWriteFileTypeToImplicitVR()
807 {
808    std::string ts = Util::DicomString(
809       Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
810
811    ValEntry *tss = CopyValEntry(0x0002,0x0010);
812    tss->SetValue(ts);
813
814    Archive->Push(tss);
815 }
816
817
818 /**
819  * \brief   
820  */ 
821 void FileHelper::RestoreWriteFileType()
822 {
823    Archive->Restore(0x0002,0x0010);
824 }
825
826 void FileHelper::SetWriteToLibido()
827 {
828    ValEntry *oldRow = dynamic_cast<ValEntry *>
829                 (FileInternal->GetDocEntry(0x0028, 0x0010));
830    ValEntry *oldCol = dynamic_cast<ValEntry *>
831                 (FileInternal->GetDocEntry(0x0028, 0x0011));
832    
833    if( oldRow && oldCol )
834    {
835       std::string rows, columns; 
836
837       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
838       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
839
840       newRow->Copy(oldCol);
841       newCol->Copy(oldRow);
842
843       newRow->SetValue(oldCol->GetValue());
844       newCol->SetValue(oldRow->GetValue());
845
846       Archive->Push(newRow);
847       Archive->Push(newCol);
848    }
849
850    ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
851    libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
852    Archive->Push(libidoCode);
853 }
854
855 /**
856  * \brief   
857  */ 
858 void FileHelper::SetWriteToNoLibido()
859 {
860    ValEntry *recCode = dynamic_cast<ValEntry *>
861                 (FileInternal->GetDocEntry(0x0008,0x0010));
862    if( recCode )
863    {
864       if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
865       {
866          ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
867          libidoCode->SetValue("");
868          Archive->Push(libidoCode);
869       }
870    }
871 }
872
873 /**
874  * \brief   
875  */ 
876 void FileHelper::RestoreWriteOfLibido()
877 {
878    Archive->Restore(0x0028,0x0010);
879    Archive->Restore(0x0028,0x0011);
880    Archive->Restore(0x0008,0x0010);
881 }
882
883 ValEntry *FileHelper::CopyValEntry(uint16_t group,uint16_t elem)
884 {
885    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
886    ValEntry *newE;
887
888    if(oldE)
889    {
890       newE = new ValEntry(oldE->GetDictEntry());
891       newE->Copy(oldE);
892    }
893    else
894    {
895       newE = GetFile()->NewValEntry(group,elem);
896    }
897
898    return newE;
899 }
900
901 /**
902  * \brief   Modifies the value of a given Bin Entry (Dicom Element)
903  *          when it exists. Create it with the given value when unexistant.
904  * @param   content (string) Value to be set
905  * @param   group   Group number of the Entry 
906  * @param   elem  Element number of the Entry
907  * \return  pointer to the modified/created Bin Entry (NULL when creation
908  *          failed).
909  */ 
910 BinEntry *FileHelper::CopyBinEntry(uint16_t group,uint16_t elem)
911 {
912    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
913    BinEntry *newE;
914
915    if(oldE)
916    {
917       newE = new BinEntry(oldE->GetDictEntry());
918       newE->Copy(oldE);
919    }
920    else
921    {
922       newE = GetFile()->NewBinEntry(group,elem);
923    }
924
925    return newE;
926 }
927
928 //-----------------------------------------------------------------------------
929 // Protected
930 /**
931  * \brief Factorization for various forms of constructors.
932  */
933 void FileHelper::Initialize()
934 {
935    WriteMode = WMODE_RAW;
936    WriteType = ExplicitVR;
937
938    PixelReadConverter = new PixelReadConvert;
939    PixelWriteConverter = new PixelWriteConvert;
940    Archive = new DocEntryArchive( FileInternal );
941
942    if ( FileInternal->IsReadable() )
943    {
944       PixelReadConverter->GrabInformationsFromHeader( FileInternal );
945    }
946 }
947
948 /**
949  * \brief   
950  */ 
951 uint8_t *FileHelper::GetRaw()
952 {
953    uint8_t *raw = PixelReadConverter->GetRaw();
954    if ( ! raw )
955    {
956       // The Raw image migth not be loaded yet:
957       std::ifstream *fp = FileInternal->OpenFile();
958       PixelReadConverter->ReadAndDecompressPixelData( fp );
959       if(fp) 
960          FileInternal->CloseFile();
961
962       raw = PixelReadConverter->GetRaw();
963       if ( ! raw )
964       {
965          gdcmVerboseMacro( "Read/decompress of pixel data apparently went wrong.");
966          return 0;
967       }
968    }
969
970    return raw;
971 }
972
973 //-----------------------------------------------------------------------------
974 // Private
975
976 //-----------------------------------------------------------------------------
977 } // end namespace gdcm
978