]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
c5219ed2f919cbfc2001a8961aef4024931fe7c5
[gdcm.git] / src / gdcmFile.cxx
1   /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/11/24 10:23:47 $
7   Version:   $Revision: 1.160 $
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 "gdcmFile.h"
20 #include "gdcmDebug.h"
21 #include "gdcmUtil.h"
22 #include "gdcmBinEntry.h"
23 #include <fstream>
24
25 namespace gdcm 
26 {
27 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
28
29 //-------------------------------------------------------------------------
30 // Constructor / Destructor
31 /**
32  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
33  *        file (Header only deals with the ... header)
34  *        Opens (in read only and when possible) an existing file and checks
35  *        for DICOM compliance. Returns NULL on failure.
36  *        It will be up to the user to load the pixels into memory
37  *        (see GetImageData, GetImageDataRaw)
38  * \note  the in-memory representation of all available tags found in
39  *        the DICOM header is post-poned to first header information access.
40  *        This avoid a double parsing of public part of the header when
41  *        user sets an a posteriori shadow dictionary (efficiency can be
42  *        seen as a side effect).   
43  * @param header already built Header
44  */
45 File::File(Header *header)
46 {
47    HeaderInternal = header;
48    SelfHeader = false;
49    Initialise();
50 }
51
52 /**
53  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
54  *        file (Header only deals with the ... header)
55  *        Opens (in read only and when possible) an existing file and checks
56  *        for DICOM compliance. Returns NULL on failure.
57  *        It will be up to the user to load the pixels into memory
58  *        (see GetImageData, GetImageDataRaw)
59  * \note  the in-memory representation of all available tags found in
60  *        the DICOM header is post-poned to first header information access.
61  *        This avoid a double parsing of public part of the header when
62  *        one sets an a posteriori shadow dictionary (efficiency can be
63  *        seen as a side effect).   
64  * @param filename file to be opened for parsing
65  */
66 File::File(std::string const & filename )
67 {
68    HeaderInternal = new Header( filename );
69    SelfHeader = true;
70    Initialise();
71 }
72
73 /**
74  * \brief Factorization for various forms of constructors.
75  */
76 void File::Initialise()
77 {
78    WriteMode = WMODE_RGB;
79    WriteType = WTYPE_IMPL_VR;
80
81    PixelConverter = new PixelConvert;
82    Archive = new DocEntryArchive( HeaderInternal );
83
84    if ( HeaderInternal->IsReadable() )
85    {
86       ImageDataSizeRaw = ComputeDecompressedPixelDataSizeFromHeader();
87       if ( HeaderInternal->HasLUT() )
88       {
89          ImageDataSize = 3 * ImageDataSizeRaw;
90       }
91       else
92       {
93          ImageDataSize = ImageDataSizeRaw;
94       }
95
96       PixelConverter->GrabInformationsFromHeader( HeaderInternal );
97    }
98
99    SaveInitialValues();
100 }
101
102 /**
103  * \brief canonical destructor
104  * \note  If the Header was created by the File constructor,
105  *        it is destroyed by the File
106  */
107 File::~File()
108
109    if( PixelConverter )
110    {
111       delete PixelConverter;
112    }
113    if( Archive )
114    {
115       delete Archive;
116    }
117
118    if( SelfHeader )
119    {
120       delete HeaderInternal;
121    }
122    HeaderInternal = 0;
123 }
124
125 /**
126  * \brief Sets some initial values for the Constructor
127  * \warning not end user intended
128  */
129 void File::SaveInitialValues()
130
131    PixelRead  = -1; // no ImageData read yet.
132    Pixel_Data = 0;
133 }
134
135 //-----------------------------------------------------------------------------
136 // Print
137
138 //-----------------------------------------------------------------------------
139 // Public
140
141 /**
142  * \brief     computes the length (in bytes) we must ALLOCATE to receive the
143  *            image(s) pixels (multiframes taken into account) 
144  * \warning : it is NOT the group 7FE0 length
145  *          (no interest for compressed images).
146  */
147 int File::ComputeDecompressedPixelDataSizeFromHeader()
148 {
149    // see PS 3.3-2003 : C.7.6.3.2.1  
150    // 
151    //   MONOCHROME1
152    //   MONOCHROME2
153    //   PALETTE COLOR
154    //   RGB
155    //   HSV  (Retired)
156    //   ARGB (Retired)
157    //   CMYK (Retired)
158    //   YBR_FULL
159    //   YBR_FULL_422 (no LUT, no Palette)
160    //   YBR_PARTIAL_422
161    //   YBR_ICT
162    //   YBR_RCT
163
164    // LUT's
165    // ex : gdcm-US-ALOKA-16.dcm
166    // 0028|1221 [OW]   [Segmented Red Palette Color Lookup Table Data]
167    // 0028|1222 [OW]   [Segmented Green Palette Color Lookup Table Data]  
168    // 0028|1223 [OW]   [Segmented Blue Palette Color Lookup Table Data]
169
170    // ex  : OT-PAL-8-face.dcm
171    // 0028|1201 [US]   [Red Palette Color Lookup Table Data]
172    // 0028|1202 [US]   [Green Palette Color Lookup Table Data]
173    // 0028|1203 [US]   [Blue Palette Color Lookup Table Data]
174
175    int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
176    // Number of "Bits Allocated" is fixed to 16 when:
177    //  - it is not defined (i.e. it's value is 0)
178    //  - it's 12, since we will expand the image to 16 bits (see
179    //    PixelConvert::ConvertDecompress12BitsTo16Bits() )
180    if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
181    {
182       numberBitsAllocated = 16;
183    } 
184
185    int DecompressedSize = HeaderInternal->GetXSize()
186                         * HeaderInternal->GetYSize() 
187                         * HeaderInternal->GetZSize()
188                         * ( numberBitsAllocated / 8 )
189                         * HeaderInternal->GetSamplesPerPixel();
190    
191    return DecompressedSize;
192 }
193
194 /**
195  * \brief   - Allocates necessary memory, 
196  *          - Reads the pixels from disk (uncompress if necessary),
197  *          - Transforms YBR pixels, if any, into RGB pixels
198  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
199  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
200  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
201  * @return  Pointer to newly allocated pixel data.
202  *          NULL if alloc fails 
203  */
204 uint8_t* File::GetImageData()
205 {
206    if ( ! GetDecompressed() )
207    {
208       // If the decompression failed nothing can be done.
209       return 0;
210    }
211                                                                                 
212    uint8_t* pixelData;
213    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
214    {
215       pixelData = PixelConverter->GetRGB();
216    }
217    else
218    {
219       // When no LUT or LUT conversion fails, return the decompressed
220       pixelData = PixelConverter->GetDecompressed();
221    }
222
223 /*// PIXELCONVERT CLEANME
224    // Restore the header in a disk-consistent state
225    // (if user asks twice to get the pixels from disk)
226    if ( PixelRead != -1 ) // File was "read" before
227    {
228       RestoreInitialValues();
229    }
230    if ( PixelConverter->GetRGB() )
231    {
232       // now, it's an RGB image
233       // Lets's write it in the Header
234       std::string spp = "3";        // Samples Per Pixel
235       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
236       std::string rgb = "RGB ";     // Photometric Interpretation
237       HeaderInternal->SetEntryByNumber(rgb,0x0028,0x0004);
238       std::string planConfig = "0"; // Planar Configuration
239       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
240       PixelRead = 0; // no PixelRaw
241    }
242    else
243    {
244       if ( HeaderInternal->HasLUT() )
245       {
246          // The LUT interpretation failed
247          std::string photometricInterpretation = Util::DicomString("MONOCHROME1");
248          HeaderInternal->SetEntryByNumber( photometricInterpretation,
249                                            0x0028, 0x0004 );
250          PixelRead = 0; // no PixelRaw
251       }
252       else
253       {
254          if ( PixelConverter->IsDecompressedRGB() )
255          {
256             ///////////////////////////////////////////////////
257             // now, it's an RGB image
258             // Lets's write it in the Header
259             // Droping Palette Color out of the Header
260             // has been moved to the Write process.
261             // TODO : move 'values' modification to the write process
262             //      : save also (in order to be able to restore)
263             //      : 'high bit' -when not equal to 'bits stored' + 1
264             //      : 'bits allocated', when it's equal to 12 ?!
265             std::string spp = "3";            // Samples Per Pixel
266             std::string photInt = "RGB ";     // Photometric Interpretation
267             std::string planConfig = "0";     // Planar Configuration
268             HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
269             HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
270             HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
271          }
272          PixelRead = 1; // PixelRaw
273       } 
274    }
275
276    // We say the value *is* loaded.
277    SetPixelData(pixelData);
278 // END PIXELCONVERT CLEANME*/
279
280    return pixelData;
281 }
282
283 /**
284  * \brief
285  *          Read the pixels from disk (uncompress if necessary),
286  *          Transforms YBR pixels, if any, into RGB pixels
287  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
288  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
289  *          Copies at most MaxSize bytes of pixel data to caller allocated
290  *          memory space.
291  * \warning This function allows people that want to build a volume
292  *          from an image stack *not to* have, first to get the image pixels, 
293  *          and then move them to the volume area.
294  *          It's absolutely useless for any VTK user since vtk chooses 
295  *          to invert the lines of an image, that is the last line comes first
296  *          (for some axis related reasons?). Hence he will have 
297  *          to load the image line by line, starting from the end.
298  *          VTK users have to call GetImageData
299  *     
300  * @param   destination Address (in caller's memory space) at which the
301  *          pixel data should be copied
302  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
303  *          is not sufficient to hold the pixel data the copy is not
304  *          executed (i.e. no partial copy).
305  * @return  On success, the number of bytes actually copied. Zero on
306  *          failure e.g. MaxSize is lower than necessary.
307  */
308 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
309 {
310    if ( ! GetDecompressed() )
311    {
312       // If the decompression failed nothing can be done.
313       return 0;
314    }
315
316    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
317    {
318       if ( PixelConverter->GetRGBSize() > maxSize )
319       {
320          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
321                         "than caller's expected MaxSize");
322          return 0;
323       }
324       memcpy( destination,
325               (void*)PixelConverter->GetRGB(),
326               PixelConverter->GetRGBSize() );
327       return PixelConverter->GetRGBSize();
328    }
329
330    // Either no LUT conversion necessary or LUT conversion failed
331    if ( PixelConverter->GetDecompressedSize() > maxSize )
332    {
333       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
334                      "than caller's expected MaxSize");
335       return 0;
336    }
337    memcpy( destination,
338            (void*)PixelConverter->GetDecompressed(),
339            PixelConverter->GetDecompressedSize() );
340    return PixelConverter->GetDecompressedSize();
341 }
342
343 /**
344  * \brief   Allocates necessary memory, 
345  *          Transforms YBR pixels (if any) into RGB pixels
346  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
347  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
348  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
349  * @return  Pointer to newly allocated pixel data.
350  * \        NULL if alloc fails 
351  */
352 uint8_t* File::GetImageDataRaw ()
353 {
354    uint8_t* decompressed = GetDecompressed();
355    if ( ! decompressed )
356    {
357       return 0;
358    }
359
360 /*// PIXELCONVERT CLEANME
361    // Restore the header in a disk-consistent state
362    // (if user asks twice to get the pixels from disk)
363    if ( PixelRead != -1 ) // File was "read" before
364    {
365       RestoreInitialValues();
366    }
367    if ( PixelConverter->IsDecompressedRGB() )
368    {
369       ///////////////////////////////////////////////////
370       // now, it's an RGB image
371       // Lets's write it in the Header
372       // Droping Palette Color out of the Header
373       // has been moved to the Write process.
374       // TODO : move 'values' modification to the write process
375       //      : save also (in order to be able to restore)
376       //      : 'high bit' -when not equal to 'bits stored' + 1
377       //      : 'bits allocated', when it's equal to 12 ?!
378       std::string spp = "3";            // Samples Per Pixel
379       std::string photInt = "RGB ";     // Photometric Interpretation
380       std::string planConfig = "0";     // Planar Configuration
381       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
382       HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
383       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
384    }
385
386    // We say the value *is* loaded.
387    SetPixelData(decompressed);
388  
389    PixelRead = 1; // PixelRaw
390 // END PIXELCONVERT CLEANME*/
391
392    return decompressed;
393 }
394
395 uint8_t* File::GetDecompressed()
396 {
397    uint8_t* decompressed = PixelConverter->GetDecompressed();
398    if ( ! decompressed )
399    {
400       // The decompressed image migth not be loaded yet:
401       std::ifstream* fp = HeaderInternal->OpenFile();
402       PixelConverter->ReadAndDecompressPixelData( fp );
403       if(fp) HeaderInternal->CloseFile();
404       decompressed = PixelConverter->GetDecompressed();
405       if ( ! decompressed )
406       {
407         dbg.Verbose(0, "File::GetDecompressed: read/decompress of "
408                        "pixel data apparently went wrong.");
409          return 0;
410       }
411    }
412
413    return decompressed;
414 }
415
416 /**
417  * \brief   Points the internal Pixel_Data pointer to the callers inData
418  *          image representation, BUT WITHOUT COPYING THE DATA.
419  *          'image' Pixels are presented as C-like 2D arrays : line per line.
420  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
421  * \warning Since the pixels are not copied, it is the caller's responsability
422  *          not to deallocate it's data before gdcm uses them (e.g. with
423  *          the Write() method.
424  * @param inData user supplied pixel area
425  * @param expectedSize total image size, in Bytes
426  *
427  * @return boolean
428  */
429 bool File::SetImageData(uint8_t* inData, size_t expectedSize)
430 {
431    HeaderInternal->SetImageDataSize( expectedSize );
432 // FIXME : if already allocated, memory leak !
433    Pixel_Data     = inData;
434    ImageDataSize = ImageDataSizeRaw = expectedSize;
435    PixelRead     = 1;
436 // FIXME : 7fe0, 0010 IS NOT set ...
437    return true;
438 }
439
440 /**
441  * \brief Writes on disk A SINGLE Dicom file
442  *        NO test is performed on  processor "Endiannity".
443  *        It's up to the user to call his Reader properly
444  * @param fileName name of the file to be created
445  *                 (any already existing file is over written)
446  * @return false if write fails
447  */
448
449 bool File::WriteRawData(std::string const & fileName)
450 {
451   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
452    if (!fp1)
453    {
454       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
455       return false;
456    }
457    fp1.write((char*)Pixel_Data, ImageDataSize);
458    fp1.close();
459
460    return true;
461 }
462
463 /**
464  * \brief Writes on disk A SINGLE Dicom file, 
465  *        using the Implicit Value Representation convention
466  *        NO test is performed on  processor "Endiannity".
467  * @param fileName name of the file to be created
468  *                 (any already existing file is overwritten)
469  * @return false if write fails
470  */
471
472 bool File::WriteDcmImplVR (std::string const & fileName)
473 {
474    SetWriteTypeToDcmImplVR();
475    return Write(fileName);
476 }
477
478 /**
479 * \brief Writes on disk A SINGLE Dicom file, 
480  *        using the Explicit Value Representation convention
481  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
482  *                 (any already existing file is overwritten)
483  * @return false if write fails
484  */
485
486 bool File::WriteDcmExplVR (std::string const & fileName)
487 {
488    SetWriteTypeToDcmExplVR();
489    return Write(fileName);
490 }
491
492 /**
493  * \brief Writes on disk A SINGLE Dicom file, 
494  *        using the ACR-NEMA convention
495  *        NO test is performed on  processor "Endiannity".
496  *        (a l'attention des logiciels cliniques 
497  *        qui ne prennent en entrĂ©e QUE des images ACR ...
498  * \warning if a DICOM_V3 header is supplied,
499  *         groups < 0x0008 and shadow groups are ignored
500  * \warning NO TEST is performed on processor "Endiannity".
501  * @param fileName name of the file to be created
502  *                 (any already existing file is overwritten)
503  * @return false if write fails
504  */
505
506 bool File::WriteAcr (std::string const & fileName)
507 {
508    SetWriteTypeToAcr();
509    return Write(fileName);
510 }
511
512 bool File::Write(std::string const& fileName)
513 {
514    switch(WriteType)
515    {
516       case WTYPE_IMPL_VR:
517          return WriteBase(fileName,ImplicitVR);
518       case WTYPE_EXPL_VR:
519          return WriteBase(fileName,ExplicitVR);
520       case WTYPE_ACR:
521          return WriteBase(fileName,ACR);
522    }
523    return(false);
524 }
525
526 //-----------------------------------------------------------------------------
527 // Protected
528 /**
529  * \brief NOT a end user inteded function
530  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
531  * @param fileName name of the file to be created
532  *                 (any already existing file is overwritten)
533  * @param  type file type (ExplicitVR, ImplicitVR, ...)
534  * @return false if write fails
535  */
536 bool File::WriteBase (std::string const & fileName, FileType type)
537 {
538 /*   if ( PixelRead == -1 && type != ExplicitVR)
539    {
540       return false;
541    }*/
542
543    std::ofstream* fp1 = new std::ofstream(fileName.c_str(), 
544                               std::ios::out | std::ios::binary);
545    if (fp1 == NULL)
546    {
547       dbg.Verbose(2, "Failed to open (write) File: " , fileName.c_str());
548       return false;
549    }
550
551    if ( type == ImplicitVR || type == ExplicitVR )
552    {
553       // writing Dicom File Preamble
554       char filePreamble[128];
555       memset(filePreamble, 0, 128);
556       fp1->write(filePreamble, 128);
557       fp1->write("DICM", 4);
558    }
559
560    switch(WriteMode)
561    {
562       case WMODE_NATIVE :
563          SetWriteToNative();
564          break;
565       case WMODE_DECOMPRESSED :
566          SetWriteToDecompressed();
567          break;
568       case WMODE_RGB :
569          SetWriteToRGB();
570          break;
571    }
572
573    // --------------------------------------------------------------
574    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
575    //
576    // if recognition code tells us we dealt with a LibIDO image
577    // we reproduce on disk the switch between lineNumber and columnNumber
578    // just before writting ...
579    
580    /// \todo the best trick would be *change* the recognition code
581    ///       but pb expected if user deals with, e.g. COMPLEX images
582
583    std::string rows, columns; 
584    if ( HeaderInternal->GetFileType() == ACR_LIBIDO)
585    {
586       SetWriteToLibido();
587    }
588    // ----------------- End of Special Patch ----------------
589       
590 /*   uint16_t grPixel  = HeaderInternal->GetGrPixel();
591    uint16_t numPixel = HeaderInternal->GetNumPixel();;
592           
593    DocEntry* PixelElement = 
594       GetHeader()->GetDocEntryByNumber(grPixel, numPixel);  
595  
596    if ( PixelRead == 1 )
597    {
598       // we read pixel 'as is' (no tranformation LUT -> RGB)
599       PixelElement->SetLength( ImageDataSizeRaw );
600    }
601    else if ( PixelRead == 0 )
602    {
603       // we tranformed GrayLevel pixels + LUT into RGB Pixel
604       PixelElement->SetLength( ImageDataSize );
605    }*/
606  
607    HeaderInternal->Write(fp1, type);
608
609    // --------------------------------------------------------------
610    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
611    // 
612    // ...and we restore the Header to be Dicom Compliant again 
613    // just after writting
614
615    if ( HeaderInternal->GetFileType() == ACR_LIBIDO )
616    {
617       RestoreWriteFromLibido();
618    }
619    // ----------------- End of Special Patch ----------------
620
621    RestoreWrite();
622
623
624    fp1->close ();
625    delete fp1;
626
627    return true;
628 }
629
630 /**
631  * \brief Access to the underlying \ref PixelConverter RGBA LUT
632  */
633 uint8_t* File::GetLutRGBA()
634 {
635    return PixelConverter->GetLutRGBA();
636 }
637
638 //-----------------------------------------------------------------------------
639 // Private
640 /**
641  * \brief Set the pixel datas in the good entry of the Header
642  */
643 void File::SetPixelData(uint8_t* data)
644 {
645    GetHeader()->SetEntryByNumber( GDCM_BINLOADED,
646       GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
647
648    // Will be 7fe0, 0010 in standard case
649    DocEntry* currentEntry = GetHeader()->GetDocEntryByNumber(GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
650    if ( currentEntry )
651    {
652       if ( BinEntry* binEntry = dynamic_cast<BinEntry *>(currentEntry) )
653          // Flag is to false because datas are kept in the gdcmPixelConvert
654          binEntry->SetBinArea( data, false );
655    }
656 }
657
658 void File::SetWriteToNative()
659 {
660 // Nothing to do
661 }
662
663 void File::SetWriteToDecompressed()
664 {
665 //   if (( !HeaderInternal->HasLUT() ) || (!PixelConverter->BuildRGBImage()))
666    if(HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage())
667    {
668       SetWriteToRGB();
669    } 
670    else
671    {
672       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
673       photInt->SetValue("MONOCHROME1 ");
674       photInt->SetLength(12);
675
676       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
677       pixel->SetValue(GDCM_BINLOADED);
678       pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
679       pixel->SetLength(PixelConverter->GetDecompressedSize());
680
681       Archive->Push(photInt);
682       Archive->Push(pixel);
683    }
684 /*   else 
685    {
686       SetWriteToRGB();
687    } */
688 }
689
690 void File::SetWriteToRGB()
691 {
692    if(PixelConverter->BuildRGBImage())
693    {
694       ValEntry* spp = CopyValEntry(0x0028,0x0002);
695       spp->SetValue("3 ");
696       spp->SetLength(2);
697
698       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
699       photInt->SetValue("RGB ");
700       photInt->SetLength(4);
701
702       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
703       planConfig->SetValue("0 ");
704       planConfig->SetLength(2);
705
706       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
707       pixel->SetValue(GDCM_BINLOADED);
708       pixel->SetBinArea(PixelConverter->GetRGB(),false);
709       pixel->SetLength(PixelConverter->GetRGBSize());
710
711       Archive->Push(spp);
712       Archive->Push(photInt);
713       Archive->Push(planConfig);
714       Archive->Push(pixel);
715    }
716    else
717    {
718       SetWriteToDecompressed();
719    }
720 }
721
722 void File::RestoreWrite()
723 {
724    Archive->Restore(0x0028,0x0002);
725    Archive->Restore(0x0028,0x0004);
726    Archive->Restore(0x0028,0x0006);
727    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
728 }
729
730 void File::SetWriteToLibido()
731 {
732    ValEntry *oldRow = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
733    ValEntry *oldCol = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
734    
735    if( oldRow && oldCol )
736    {
737       std::string rows, columns; 
738
739       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
740       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
741
742       newRow->Copy(oldCol);
743       newCol->Copy(oldRow);
744
745       newRow->SetValue(oldCol->GetValue());
746       newCol->SetValue(oldRow->GetValue());
747
748       Archive->Push(newRow);
749       Archive->Push(newCol);
750    }
751 }
752
753 void File::RestoreWriteFromLibido()
754 {
755    Archive->Restore(0x0028,0x0010);
756    Archive->Restore(0x0028,0x0011);
757 }
758
759 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
760 {
761    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
762    ValEntry* newE;
763
764    if(oldE)
765    {
766       newE = new ValEntry(oldE->GetDictEntry());
767       newE->Copy(oldE);
768    }
769    else
770    {
771       newE = GetHeader()->NewValEntryByNumber(group,element);
772    }
773
774    return(newE);
775 }
776
777 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
778 {
779    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
780    BinEntry* newE;
781
782    if(oldE)
783    {
784       newE = new BinEntry(oldE->GetDictEntry());
785       newE->Copy(oldE);
786    }
787    else
788    {
789       newE = GetHeader()->NewBinEntryByNumber(group,element);
790    }
791
792
793    return(newE);
794 }
795
796 //-----------------------------------------------------------------------------
797 } // end namespace gdcm
798