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