]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
666a8e96f5fdd0245ddfb14ec1d15cb82937732e
[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 11:17:47 $
7   Version:   $Revision: 1.161 $
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    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
213    {
214       return PixelConverter->GetRGB();
215    }
216    else
217    {
218       // When no LUT or LUT conversion fails, return the decompressed
219       return PixelConverter->GetDecompressed();
220    }
221    
222 /*   if ( ! GetDecompressed() )
223    {
224       // If the decompression failed nothing can be done.
225       return 0;
226    }
227                                                                                 
228    uint8_t* pixelData;
229    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
230    {
231       pixelData = PixelConverter->GetRGB();
232    }
233    else
234    {
235       // When no LUT or LUT conversion fails, return the decompressed
236       pixelData = PixelConverter->GetDecompressed();
237    }
238
239 // PIXELCONVERT CLEANME
240    // Restore the header in a disk-consistent state
241    // (if user asks twice to get the pixels from disk)
242    if ( PixelRead != -1 ) // File was "read" before
243    {
244       RestoreInitialValues();
245    }
246    if ( PixelConverter->GetRGB() )
247    {
248       // now, it's an RGB image
249       // Lets's write it in the Header
250       std::string spp = "3";        // Samples Per Pixel
251       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
252       std::string rgb = "RGB ";     // Photometric Interpretation
253       HeaderInternal->SetEntryByNumber(rgb,0x0028,0x0004);
254       std::string planConfig = "0"; // Planar Configuration
255       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
256       PixelRead = 0; // no PixelRaw
257    }
258    else
259    {
260       if ( HeaderInternal->HasLUT() )
261       {
262          // The LUT interpretation failed
263          std::string photometricInterpretation = Util::DicomString("MONOCHROME1");
264          HeaderInternal->SetEntryByNumber( photometricInterpretation,
265                                            0x0028, 0x0004 );
266          PixelRead = 0; // no PixelRaw
267       }
268       else
269       {
270          if ( PixelConverter->IsDecompressedRGB() )
271          {
272             ///////////////////////////////////////////////////
273             // now, it's an RGB image
274             // Lets's write it in the Header
275             // Droping Palette Color out of the Header
276             // has been moved to the Write process.
277             // TODO : move 'values' modification to the write process
278             //      : save also (in order to be able to restore)
279             //      : 'high bit' -when not equal to 'bits stored' + 1
280             //      : 'bits allocated', when it's equal to 12 ?!
281             std::string spp = "3";            // Samples Per Pixel
282             std::string photInt = "RGB ";     // Photometric Interpretation
283             std::string planConfig = "0";     // Planar Configuration
284             HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
285             HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
286             HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
287          }
288          PixelRead = 1; // PixelRaw
289       } 
290    }
291
292    // We say the value *is* loaded.
293    SetPixelData(pixelData);
294 // END PIXELCONVERT CLEANME
295
296    return pixelData;*/
297 }
298
299 /**
300  * \brief
301  *          Read the pixels from disk (uncompress if necessary),
302  *          Transforms YBR pixels, if any, into RGB pixels
303  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
304  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
305  *          Copies at most MaxSize bytes of pixel data to caller allocated
306  *          memory space.
307  * \warning This function allows people that want to build a volume
308  *          from an image stack *not to* have, first to get the image pixels, 
309  *          and then move them to the volume area.
310  *          It's absolutely useless for any VTK user since vtk chooses 
311  *          to invert the lines of an image, that is the last line comes first
312  *          (for some axis related reasons?). Hence he will have 
313  *          to load the image line by line, starting from the end.
314  *          VTK users have to call GetImageData
315  *     
316  * @param   destination Address (in caller's memory space) at which the
317  *          pixel data should be copied
318  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
319  *          is not sufficient to hold the pixel data the copy is not
320  *          executed (i.e. no partial copy).
321  * @return  On success, the number of bytes actually copied. Zero on
322  *          failure e.g. MaxSize is lower than necessary.
323  */
324 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
325 {
326    if ( ! GetDecompressed() )
327    {
328       // If the decompression failed nothing can be done.
329       return 0;
330    }
331
332    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
333    {
334       if ( PixelConverter->GetRGBSize() > maxSize )
335       {
336          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
337                         "than caller's expected MaxSize");
338          return 0;
339       }
340       memcpy( destination,
341               (void*)PixelConverter->GetRGB(),
342               PixelConverter->GetRGBSize() );
343       return PixelConverter->GetRGBSize();
344    }
345
346    // Either no LUT conversion necessary or LUT conversion failed
347    if ( PixelConverter->GetDecompressedSize() > maxSize )
348    {
349       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
350                      "than caller's expected MaxSize");
351       return 0;
352    }
353    memcpy( destination,
354            (void*)PixelConverter->GetDecompressed(),
355            PixelConverter->GetDecompressedSize() );
356    return PixelConverter->GetDecompressedSize();
357 }
358
359 /**
360  * \brief   Allocates necessary memory, 
361  *          Transforms YBR pixels (if any) into RGB pixels
362  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
363  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
364  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
365  * @return  Pointer to newly allocated pixel data.
366  * \        NULL if alloc fails 
367  */
368 uint8_t* File::GetImageDataRaw ()
369 {
370    return GetDecompressed();
371 /*   uint8_t* decompressed = GetDecompressed();
372    if ( ! decompressed )
373    {
374       return 0;
375    }
376
377 // PIXELCONVERT CLEANME
378    // Restore the header in a disk-consistent state
379    // (if user asks twice to get the pixels from disk)
380    if ( PixelRead != -1 ) // File was "read" before
381    {
382       RestoreInitialValues();
383    }
384    if ( PixelConverter->IsDecompressedRGB() )
385    {
386       ///////////////////////////////////////////////////
387       // now, it's an RGB image
388       // Lets's write it in the Header
389       // Droping Palette Color out of the Header
390       // has been moved to the Write process.
391       // TODO : move 'values' modification to the write process
392       //      : save also (in order to be able to restore)
393       //      : 'high bit' -when not equal to 'bits stored' + 1
394       //      : 'bits allocated', when it's equal to 12 ?!
395       std::string spp = "3";            // Samples Per Pixel
396       std::string photInt = "RGB ";     // Photometric Interpretation
397       std::string planConfig = "0";     // Planar Configuration
398       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
399       HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
400       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
401    }
402
403    // We say the value *is* loaded.
404    SetPixelData(decompressed);
405  
406    PixelRead = 1; // PixelRaw
407 // END PIXELCONVERT CLEANME
408
409    return decompressed;*/
410 }
411
412 uint8_t* File::GetDecompressed()
413 {
414    uint8_t* decompressed = PixelConverter->GetDecompressed();
415    if ( ! decompressed )
416    {
417       // The decompressed image migth not be loaded yet:
418       std::ifstream* fp = HeaderInternal->OpenFile();
419       PixelConverter->ReadAndDecompressPixelData( fp );
420       if(fp) HeaderInternal->CloseFile();
421       decompressed = PixelConverter->GetDecompressed();
422       if ( ! decompressed )
423       {
424         dbg.Verbose(0, "File::GetDecompressed: read/decompress of "
425                        "pixel data apparently went wrong.");
426          return 0;
427       }
428    }
429
430    return decompressed;
431 }
432
433 /**
434  * \brief   Points the internal Pixel_Data pointer to the callers inData
435  *          image representation, BUT WITHOUT COPYING THE DATA.
436  *          'image' Pixels are presented as C-like 2D arrays : line per line.
437  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
438  * \warning Since the pixels are not copied, it is the caller's responsability
439  *          not to deallocate it's data before gdcm uses them (e.g. with
440  *          the Write() method.
441  * @param inData user supplied pixel area
442  * @param expectedSize total image size, in Bytes
443  *
444  * @return boolean
445  */
446 bool File::SetImageData(uint8_t* inData, size_t expectedSize)
447 {
448    HeaderInternal->SetImageDataSize( expectedSize );
449 // FIXME : if already allocated, memory leak !
450    Pixel_Data     = inData;
451    ImageDataSize = ImageDataSizeRaw = expectedSize;
452    PixelRead     = 1;
453 // FIXME : 7fe0, 0010 IS NOT set ...
454    return true;
455 }
456
457 /**
458  * \brief Writes on disk A SINGLE Dicom file
459  *        NO test is performed on  processor "Endiannity".
460  *        It's up to the user to call his Reader properly
461  * @param fileName name of the file to be created
462  *                 (any already existing file is over written)
463  * @return false if write fails
464  */
465
466 bool File::WriteRawData(std::string const & fileName)
467 {
468   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
469    if (!fp1)
470    {
471       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
472       return false;
473    }
474    fp1.write((char*)Pixel_Data, ImageDataSize);
475    fp1.close();
476
477    return true;
478 }
479
480 /**
481  * \brief Writes on disk A SINGLE Dicom file, 
482  *        using the Implicit Value Representation convention
483  *        NO test is performed on  processor "Endiannity".
484  * @param fileName name of the file to be created
485  *                 (any already existing file is overwritten)
486  * @return false if write fails
487  */
488
489 bool File::WriteDcmImplVR (std::string const & fileName)
490 {
491    SetWriteTypeToDcmImplVR();
492    return Write(fileName);
493 }
494
495 /**
496 * \brief Writes on disk A SINGLE Dicom file, 
497  *        using the Explicit Value Representation convention
498  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
499  *                 (any already existing file is overwritten)
500  * @return false if write fails
501  */
502
503 bool File::WriteDcmExplVR (std::string const & fileName)
504 {
505    SetWriteTypeToDcmExplVR();
506    return Write(fileName);
507 }
508
509 /**
510  * \brief Writes on disk A SINGLE Dicom file, 
511  *        using the ACR-NEMA convention
512  *        NO test is performed on  processor "Endiannity".
513  *        (a l'attention des logiciels cliniques 
514  *        qui ne prennent en entrĂ©e QUE des images ACR ...
515  * \warning if a DICOM_V3 header is supplied,
516  *         groups < 0x0008 and shadow groups are ignored
517  * \warning NO TEST is performed on processor "Endiannity".
518  * @param fileName name of the file to be created
519  *                 (any already existing file is overwritten)
520  * @return false if write fails
521  */
522
523 bool File::WriteAcr (std::string const & fileName)
524 {
525    SetWriteTypeToAcr();
526    return Write(fileName);
527 }
528
529 bool File::Write(std::string const& fileName)
530 {
531    switch(WriteType)
532    {
533       case WTYPE_IMPL_VR:
534          return WriteBase(fileName,ImplicitVR);
535       case WTYPE_EXPL_VR:
536          return WriteBase(fileName,ExplicitVR);
537       case WTYPE_ACR:
538          return WriteBase(fileName,ACR);
539    }
540    return(false);
541 }
542
543 //-----------------------------------------------------------------------------
544 // Protected
545 /**
546  * \brief NOT a end user inteded function
547  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
548  * @param fileName name of the file to be created
549  *                 (any already existing file is overwritten)
550  * @param  type file type (ExplicitVR, ImplicitVR, ...)
551  * @return false if write fails
552  */
553 bool File::WriteBase (std::string const & fileName, FileType type)
554 {
555 /*   if ( PixelRead == -1 && type != ExplicitVR)
556    {
557       return false;
558    }*/
559
560    std::ofstream* fp1 = new std::ofstream(fileName.c_str(), 
561                               std::ios::out | std::ios::binary);
562    if (fp1 == NULL)
563    {
564       dbg.Verbose(2, "Failed to open (write) File: " , fileName.c_str());
565       return false;
566    }
567
568    if ( type == ImplicitVR || type == ExplicitVR )
569    {
570       // writing Dicom File Preamble
571       char filePreamble[128];
572       memset(filePreamble, 0, 128);
573       fp1->write(filePreamble, 128);
574       fp1->write("DICM", 4);
575    }
576
577    switch(WriteMode)
578    {
579       case WMODE_NATIVE :
580          SetWriteToNative();
581          break;
582       case WMODE_DECOMPRESSED :
583          SetWriteToDecompressed();
584          break;
585       case WMODE_RGB :
586          SetWriteToRGB();
587          break;
588    }
589
590    // --------------------------------------------------------------
591    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
592    //
593    // if recognition code tells us we dealt with a LibIDO image
594    // we reproduce on disk the switch between lineNumber and columnNumber
595    // just before writting ...
596    
597    /// \todo the best trick would be *change* the recognition code
598    ///       but pb expected if user deals with, e.g. COMPLEX images
599
600    std::string rows, columns; 
601    if ( HeaderInternal->GetFileType() == ACR_LIBIDO)
602    {
603       SetWriteToLibido();
604    }
605    // ----------------- End of Special Patch ----------------
606       
607 /*   uint16_t grPixel  = HeaderInternal->GetGrPixel();
608    uint16_t numPixel = HeaderInternal->GetNumPixel();;
609           
610    DocEntry* PixelElement = 
611       GetHeader()->GetDocEntryByNumber(grPixel, numPixel);  
612  
613    if ( PixelRead == 1 )
614    {
615       // we read pixel 'as is' (no tranformation LUT -> RGB)
616       PixelElement->SetLength( ImageDataSizeRaw );
617    }
618    else if ( PixelRead == 0 )
619    {
620       // we tranformed GrayLevel pixels + LUT into RGB Pixel
621       PixelElement->SetLength( ImageDataSize );
622    }*/
623  
624    HeaderInternal->Write(fp1, type);
625
626    // --------------------------------------------------------------
627    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
628    // 
629    // ...and we restore the Header to be Dicom Compliant again 
630    // just after writting
631
632    if ( HeaderInternal->GetFileType() == ACR_LIBIDO )
633    {
634       RestoreWriteFromLibido();
635    }
636    // ----------------- End of Special Patch ----------------
637
638    RestoreWrite();
639
640
641    fp1->close ();
642    delete fp1;
643
644    return true;
645 }
646
647 /**
648  * \brief Access to the underlying \ref PixelConverter RGBA LUT
649  */
650 uint8_t* File::GetLutRGBA()
651 {
652    return PixelConverter->GetLutRGBA();
653 }
654
655 //-----------------------------------------------------------------------------
656 // Private
657 /**
658  * \brief Set the pixel datas in the good entry of the Header
659  */
660 void File::SetPixelData(uint8_t* data)
661 {
662    GetHeader()->SetEntryByNumber( GDCM_BINLOADED,
663       GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
664
665    // Will be 7fe0, 0010 in standard case
666    DocEntry* currentEntry = GetHeader()->GetDocEntryByNumber(GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
667    if ( currentEntry )
668    {
669       if ( BinEntry* binEntry = dynamic_cast<BinEntry *>(currentEntry) )
670          // Flag is to false because datas are kept in the gdcmPixelConvert
671          binEntry->SetBinArea( data, false );
672    }
673 }
674
675 void File::SetWriteToNative()
676 {
677 // Nothing to do
678 }
679
680 void File::SetWriteToDecompressed()
681 {
682 //   if (( !HeaderInternal->HasLUT() ) || (!PixelConverter->BuildRGBImage()))
683    if(HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage())
684    {
685       SetWriteToRGB();
686    } 
687    else
688    {
689       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
690       photInt->SetValue("MONOCHROME1 ");
691       photInt->SetLength(12);
692
693       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
694       pixel->SetValue(GDCM_BINLOADED);
695       pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
696       pixel->SetLength(PixelConverter->GetDecompressedSize());
697
698       Archive->Push(photInt);
699       Archive->Push(pixel);
700    }
701 /*   else 
702    {
703       SetWriteToRGB();
704    } */
705 }
706
707 void File::SetWriteToRGB()
708 {
709    if(PixelConverter->BuildRGBImage())
710    {
711       ValEntry* spp = CopyValEntry(0x0028,0x0002);
712       spp->SetValue("3 ");
713       spp->SetLength(2);
714
715       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
716       photInt->SetValue("RGB ");
717       photInt->SetLength(4);
718
719       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
720       planConfig->SetValue("0 ");
721       planConfig->SetLength(2);
722
723       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
724       pixel->SetValue(GDCM_BINLOADED);
725       pixel->SetBinArea(PixelConverter->GetRGB(),false);
726       pixel->SetLength(PixelConverter->GetRGBSize());
727
728       Archive->Push(spp);
729       Archive->Push(photInt);
730       Archive->Push(planConfig);
731       Archive->Push(pixel);
732    }
733    else
734    {
735       SetWriteToDecompressed();
736    }
737 }
738
739 void File::RestoreWrite()
740 {
741    Archive->Restore(0x0028,0x0002);
742    Archive->Restore(0x0028,0x0004);
743    Archive->Restore(0x0028,0x0006);
744    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
745 }
746
747 void File::SetWriteToLibido()
748 {
749    ValEntry *oldRow = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
750    ValEntry *oldCol = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
751    
752    if( oldRow && oldCol )
753    {
754       std::string rows, columns; 
755
756       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
757       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
758
759       newRow->Copy(oldCol);
760       newCol->Copy(oldRow);
761
762       newRow->SetValue(oldCol->GetValue());
763       newCol->SetValue(oldRow->GetValue());
764
765       Archive->Push(newRow);
766       Archive->Push(newCol);
767    }
768 }
769
770 void File::RestoreWriteFromLibido()
771 {
772    Archive->Restore(0x0028,0x0010);
773    Archive->Restore(0x0028,0x0011);
774 }
775
776 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
777 {
778    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
779    ValEntry* newE;
780
781    if(oldE)
782    {
783       newE = new ValEntry(oldE->GetDictEntry());
784       newE->Copy(oldE);
785    }
786    else
787    {
788       newE = GetHeader()->NewValEntryByNumber(group,element);
789    }
790
791    return(newE);
792 }
793
794 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
795 {
796    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
797    BinEntry* newE;
798
799    if(oldE)
800    {
801       newE = new BinEntry(oldE->GetDictEntry());
802       newE->Copy(oldE);
803    }
804    else
805    {
806       newE = GetHeader()->NewBinEntryByNumber(group,element);
807    }
808
809
810    return(newE);
811 }
812
813 //-----------------------------------------------------------------------------
814 } // end namespace gdcm
815