]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* src/gdcmFile.[h|cxx] : add the Print method
[gdcm.git] / src / gdcmFile.cxx
1   /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/12/16 11:37:03 $
7   Version:   $Revision: 1.178 $
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 "gdcmDocument.h"
21 #include "gdcmDebug.h"
22 #include "gdcmUtil.h"
23 #include "gdcmBinEntry.h"
24 #include "gdcmHeader.h"
25 #include "gdcmPixelReadConvert.h"
26 #include "gdcmPixelWriteConvert.h"
27 #include "gdcmDocEntryArchive.h"
28
29 #include <fstream>
30
31 namespace gdcm 
32 {
33 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
34
35 //-------------------------------------------------------------------------
36 // Constructor / Destructor
37 /**
38  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
39  *        file (Header only deals with the ... header)
40  *        Opens (in read only and when possible) an existing file and checks
41  *        for DICOM compliance. Returns NULL on failure.
42  *        It will be up to the user to load the pixels into memory
43  *        (see GetImageData, GetImageDataRaw)
44  * \note  the in-memory representation of all available tags found in
45  *        the DICOM header is post-poned to first header information access.
46  *        This avoid a double parsing of public part of the header when
47  *        one sets an a posteriori shadow dictionary (efficiency can be
48  *        seen as a side effect).   
49  */
50 File::File( )
51 {
52    HeaderInternal = new Header( );
53    SelfHeader = true;
54    Initialise();
55 }
56
57 /**
58  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
59  *        file (Header only deals with the ... header)
60  *        Opens (in read only and when possible) an existing file and checks
61  *        for DICOM compliance. Returns NULL on failure.
62  *        It will be up to the user to load the pixels into memory
63  *        (see GetImageData, GetImageDataRaw)
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 File::File(Header *header)
72 {
73    HeaderInternal = header;
74    SelfHeader = false;
75    Initialise();
76 }
77
78 /**
79  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
80  *        file (Header 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  *        (see GetImageData, GetImageDataRaw)
85  * \note  the in-memory representation of all available tags found in
86  *        the DICOM header is post-poned to first header information access.
87  *        This avoid a double parsing of public part of the header when
88  *        one sets an a posteriori shadow dictionary (efficiency can be
89  *        seen as a side effect).   
90  * @param filename file to be opened for parsing
91  */
92 File::File(std::string const & filename )
93 {
94    HeaderInternal = new Header( filename );
95    SelfHeader = true;
96    Initialise();
97 }
98
99 /**
100  * \brief canonical destructor
101  * \note  If the Header was created by the File constructor,
102  *        it is destroyed by the File
103  */
104 File::~File()
105
106    if( PixelReadConverter )
107    {
108       delete PixelReadConverter;
109    }
110    if( PixelWriteConverter )
111    {
112       delete PixelWriteConverter;
113    }
114    if( Archive )
115    {
116       delete Archive;
117    }
118
119    if( SelfHeader )
120    {
121       delete HeaderInternal;
122    }
123    HeaderInternal = 0;
124 }
125
126 //-----------------------------------------------------------------------------
127 // Print
128 void File::Print(std::ostream &os)
129 {
130    HeaderInternal->SetPrintLevel(PrintLevel);
131    HeaderInternal->Print(os);
132    PixelReadConverter->Print(os);
133 }
134
135 //-----------------------------------------------------------------------------
136 // Public
137 /**
138  * \brief   Get the size of the image data
139  * 
140  *          If the image can be RGB (with a lut or by default), the size 
141  *          corresponds to the RGB image
142  * @return  The image size
143  */
144 size_t File::GetImageDataSize()
145 {
146    if ( PixelWriteConverter->GetUserData() )
147    {
148       return PixelWriteConverter->GetUserDataSize();
149    }
150
151    return PixelReadConverter->GetRGBSize();
152 }
153
154 /**
155  * \brief   Get the size of the image data
156  * 
157  *          If the image can be RGB by transformation in a LUT, this
158  *          transformation isn't considered
159  * @return  The raw image size
160  */
161 size_t File::GetImageDataRawSize()
162 {
163    if ( PixelWriteConverter->GetUserData() )
164    {
165       return PixelWriteConverter->GetUserDataSize();
166    }
167
168    return PixelReadConverter->GetRawSize();
169 }
170
171 /**
172  * \brief   - Allocates necessary memory, 
173  *          - Reads the pixels from disk (uncompress if necessary),
174  *          - Transforms YBR pixels, if any, into RGB pixels
175  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
176  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
177  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
178  * @return  Pointer to newly allocated pixel data.
179  *          NULL if alloc fails 
180  */
181 uint8_t* File::GetImageData()
182 {
183    if ( PixelWriteConverter->GetUserData() )
184    {
185       return PixelWriteConverter->GetUserData();
186    }
187
188    if ( ! GetRaw() )
189    {
190       // If the decompression failed nothing can be done.
191       return 0;
192    }
193
194    if ( HeaderInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
195    {
196       return PixelReadConverter->GetRGB();
197    }
198    else
199    {
200       // When no LUT or LUT conversion fails, return the Raw
201       return PixelReadConverter->GetRaw();
202    }
203 }
204
205 /**
206  * \brief   Allocates necessary memory, 
207  *          Transforms YBR pixels (if any) into RGB pixels
208  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
209  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
210  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
211  * @return  Pointer to newly allocated pixel data.
212  * \        NULL if alloc fails 
213  */
214 uint8_t* File::GetImageDataRaw ()
215 {
216    return GetRaw();
217 }
218
219 /**
220  * \brief
221  *          Read the pixels from disk (uncompress if necessary),
222  *          Transforms YBR pixels, if any, into RGB pixels
223  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
224  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
225  *          Copies at most MaxSize bytes of pixel data to caller allocated
226  *          memory space.
227  * \warning This function allows people that want to build a volume
228  *          from an image stack *not to* have, first to get the image pixels, 
229  *          and then move them to the volume area.
230  *          It's absolutely useless for any VTK user since vtk chooses 
231  *          to invert the lines of an image, that is the last line comes first
232  *          (for some axis related reasons?). Hence he will have 
233  *          to load the image line by line, starting from the end.
234  *          VTK users have to call GetImageData
235  *     
236  * @param   destination Address (in caller's memory space) at which the
237  *          pixel data should be copied
238  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
239  *          is not sufficient to hold the pixel data the copy is not
240  *          executed (i.e. no partial copy).
241  * @return  On success, the number of bytes actually copied. Zero on
242  *          failure e.g. MaxSize is lower than necessary.
243  */
244 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
245 {
246    if ( ! GetRaw() )
247    {
248       // If the decompression failed nothing can be done.
249       return 0;
250    }
251
252    if ( HeaderInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
253    {
254       if ( PixelReadConverter->GetRGBSize() > maxSize )
255       {
256          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
257                         "than caller's expected MaxSize");
258          return 0;
259       }
260       memcpy( destination,
261               (void*)PixelReadConverter->GetRGB(),
262               PixelReadConverter->GetRGBSize() );
263       return PixelReadConverter->GetRGBSize();
264    }
265
266    // Either no LUT conversion necessary or LUT conversion failed
267    if ( PixelReadConverter->GetRawSize() > maxSize )
268    {
269       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
270                      "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 File::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 File::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 datas to write
309  */
310 uint8_t* File::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 datas to write
318  */
319 size_t File::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 datas are expanded to be RGB
327  */
328 uint8_t* File::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 datas are expanded to be RGB
336  */
337 size_t File::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* File::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 datas are not expanded !
354  */
355 size_t File::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 File::WriteRawData(std::string const & fileName)
370 {
371   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
372    if (!fp1)
373    {
374       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
375       return false;
376    }
377
378    if(PixelWriteConverter->GetUserData())
379       fp1.write((char*)PixelWriteConverter->GetUserData(), PixelWriteConverter->GetUserDataSize());
380    else if(PixelReadConverter->GetRGB())
381       fp1.write((char*)PixelReadConverter->GetRGB(), PixelReadConverter->GetRGBSize());
382    else if(PixelReadConverter->GetRaw())
383       fp1.write((char*)PixelReadConverter->GetRaw(), PixelReadConverter->GetRawSize());
384
385    fp1.close();
386
387    return true;
388 }
389
390 /**
391  * \brief Writes on disk A SINGLE Dicom file, 
392  *        using the Implicit Value Representation convention
393  *        NO test is performed on  processor "Endiannity".
394  * @param fileName name of the file to be created
395  *                 (any already existing file is overwritten)
396  * @return false if write fails
397  */
398
399 bool File::WriteDcmImplVR (std::string const & fileName)
400 {
401    SetWriteTypeToDcmImplVR();
402    return Write(fileName);
403 }
404
405 /**
406 * \brief Writes on disk A SINGLE Dicom file, 
407  *        using the Explicit Value Representation convention
408  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
409  *                 (any already existing file is overwritten)
410  * @return false if write fails
411  */
412
413 bool File::WriteDcmExplVR (std::string const & fileName)
414 {
415    SetWriteTypeToDcmExplVR();
416    return Write(fileName);
417 }
418
419 /**
420  * \brief Writes on disk A SINGLE Dicom file, 
421  *        using the ACR-NEMA convention
422  *        NO test is performed on  processor "Endiannity".
423  *        (a l'attention des logiciels cliniques 
424  *        qui ne prennent en entrée QUE des images ACR ...
425  * \warning if a DICOM_V3 header is supplied,
426  *         groups < 0x0008 and shadow groups are ignored
427  * \warning NO TEST is performed on processor "Endiannity".
428  * @param fileName name of the file to be created
429  *                 (any already existing file is overwritten)
430  * @return false if write fails
431  */
432
433 bool File::WriteAcr (std::string const & fileName)
434 {
435    SetWriteTypeToAcr();
436    return Write(fileName);
437 }
438
439 bool File::Write(std::string const& fileName)
440 {
441    return WriteBase(fileName);
442 }
443
444 bool File::SetEntryByNumber(std::string const& content,
445                             uint16_t group, uint16_t element)
446
447    return HeaderInternal->SetEntryByNumber(content,group,element);
448 }
449
450 bool File::SetEntryByNumber(uint8_t* content, int lgth,
451                             uint16_t group, uint16_t element)
452 {
453    return HeaderInternal->SetEntryByNumber(content,lgth,group,element);
454 }
455
456 bool File::ReplaceOrCreateByNumber(std::string const& content,
457                                    uint16_t group, uint16_t element)
458 {
459    return HeaderInternal->ReplaceOrCreateByNumber(content,group,element) != NULL;
460 }
461
462 bool File::ReplaceOrCreateByNumber(uint8_t* binArea, int lgth,
463                                    uint16_t group, uint16_t element)
464 {
465    return HeaderInternal->ReplaceOrCreateByNumber(binArea,lgth,group,element) != NULL;
466 }
467
468 /**
469  * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
470  */
471 uint8_t* File::GetLutRGBA()
472 {
473    return PixelReadConverter->GetLutRGBA();
474 }
475
476 //-----------------------------------------------------------------------------
477 // Protected
478 /**
479  * \brief NOT a end user inteded function
480  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
481  * @param fileName name of the file to be created
482  *                 (any already existing file is overwritten)
483  * @param  type file type (ExplicitVR, ImplicitVR, ...)
484  * @return false if write fails
485  */
486 bool File::WriteBase (std::string const & fileName)
487 {
488    switch(WriteType)
489    {
490       case ImplicitVR:
491          SetWriteFileTypeToImplicitVR();
492          break;
493       case ExplicitVR:
494          SetWriteFileTypeToExplicitVR();
495          break;
496       case ACR:
497       case ACR_LIBIDO:
498          SetWriteFileTypeToACR();
499          break;
500       default:
501          SetWriteFileTypeToExplicitVR();
502    }
503
504    // --------------------------------------------------------------
505    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
506    //
507    // if recognition code tells us we dealt with a LibIDO image
508    // we reproduce on disk the switch between lineNumber and columnNumber
509    // just before writting ...
510    /// \todo the best trick would be *change* the recognition code
511    ///       but pb expected if user deals with, e.g. COMPLEX images
512    if( WriteType == ACR_LIBIDO )
513    {
514       SetWriteToLibido();
515    }
516    else
517    {
518       SetWriteToNoLibido();
519    }
520    // ----------------- End of Special Patch ----------------
521   
522    switch(WriteMode)
523    {
524       case WMODE_RAW :
525          SetWriteToRaw();
526          break;
527       case WMODE_RGB :
528          SetWriteToRGB();
529          break;
530    }
531
532    bool check = CheckWriteIntegrity();
533    if(check)
534    {
535       check = HeaderInternal->Write(fileName,WriteType);
536    }
537
538    RestoreWrite();
539    RestoreWriteFileType();
540
541    // --------------------------------------------------------------
542    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
543    // 
544    // ...and we restore the Header to be Dicom Compliant again 
545    // just after writting
546    RestoreWriteOfLibido();
547    // ----------------- End of Special Patch ----------------
548
549    return check;
550 }
551
552 /**
553  * \brief Check the write integrity
554  *
555  * The tests made are :
556  *  - verify the size of the image to write with the possible write
557  *    when the user set an image data
558  * @return true if the check successfulls
559  */
560 bool File::CheckWriteIntegrity()
561 {
562    if(PixelWriteConverter->GetUserData())
563    {
564       int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
565       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
566       {
567          numberBitsAllocated = 16;
568       }
569
570       size_t decSize = HeaderInternal->GetXSize()
571                     * HeaderInternal->GetYSize() 
572                     * HeaderInternal->GetZSize()
573                     * ( numberBitsAllocated / 8 )
574                     * HeaderInternal->GetSamplesPerPixel();
575       size_t rgbSize = decSize;
576       if( HeaderInternal->HasLUT() )
577          rgbSize = decSize * 3;
578
579       switch(WriteMode)
580       {
581          case WMODE_RAW :
582             if( decSize!=PixelWriteConverter->GetUserDataSize() )
583             {
584                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect (Raw)");
585                //std::cerr << "File::CheckWriteIntegrity: Data size is incorrect (Raw)\n"
586                //          << decSize << " / " << PixelWriteConverter->GetUserDataSize() << "\n";
587                return false;
588             }
589             break;
590          case WMODE_RGB :
591             if( rgbSize!=PixelWriteConverter->GetUserDataSize() )
592             {
593                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect (RGB)");
594                //std::cerr << "File::CheckWriteIntegrity: Data size is incorrect (RGB)\n"
595                //          << decSize << " / " << PixelWriteConverter->GetUserDataSize() << "\n";
596                return false;
597             }
598             break;
599       }
600    }
601    
602    return true;
603 }
604
605 void File::SetWriteToRaw()
606 {
607    if(HeaderInternal->GetNumberOfScalarComponents()==3 && !HeaderInternal->HasLUT())
608    {
609       SetWriteToRGB();
610    } 
611    else
612    {
613       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
614       if(HeaderInternal->HasLUT())
615       {
616          photInt->SetValue("PALETTE COLOR ");
617       }
618       else
619       {
620          photInt->SetValue("MONOCHROME1 ");
621       }
622
623       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
624                                        PixelReadConverter->GetRawSize());
625
626       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
627       pixel->SetValue(GDCM_BINLOADED);
628       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
629       pixel->SetLength(PixelWriteConverter->GetDataSize());
630
631       Archive->Push(photInt);
632       Archive->Push(pixel);
633    }
634 }
635
636 void File::SetWriteToRGB()
637 {
638    if(HeaderInternal->GetNumberOfScalarComponents()==3)
639    {
640       PixelReadConverter->BuildRGBImage();
641       
642       ValEntry* spp = CopyValEntry(0x0028,0x0002);
643       spp->SetValue("3 ");
644
645       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
646       planConfig->SetValue("0 ");
647
648       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
649       photInt->SetValue("RGB ");
650
651       if(PixelReadConverter->GetRGB())
652       {
653          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
654                                           PixelReadConverter->GetRGBSize());
655       }
656       else // Raw data
657       {
658          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
659                                           PixelReadConverter->GetRawSize());
660       }
661
662       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
663       pixel->SetValue(GDCM_BINLOADED);
664       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
665       pixel->SetLength(PixelWriteConverter->GetDataSize());
666
667       Archive->Push(spp);
668       Archive->Push(planConfig);
669       Archive->Push(photInt);
670       Archive->Push(pixel);
671
672       // Remove any LUT
673       Archive->Push(0x0028,0x1101);
674       Archive->Push(0x0028,0x1102);
675       Archive->Push(0x0028,0x1103);
676       Archive->Push(0x0028,0x1201);
677       Archive->Push(0x0028,0x1202);
678       Archive->Push(0x0028,0x1203);
679
680       // For old ACR-NEMA
681       // Thus, we have a RGB image and the bits allocated = 24 and 
682       // samples per pixels = 1 (in the read file)
683       if(HeaderInternal->GetBitsAllocated()==24) 
684       {
685          ValEntry* bitsAlloc = CopyValEntry(0x0028,0x0100);
686          bitsAlloc->SetValue("8 ");
687
688          ValEntry* bitsStored = CopyValEntry(0x0028,0x0101);
689          bitsStored->SetValue("8 ");
690
691          ValEntry* highBit = CopyValEntry(0x0028,0x0102);
692          highBit->SetValue("7 ");
693
694          Archive->Push(bitsAlloc);
695          Archive->Push(bitsStored);
696          Archive->Push(highBit);
697       }
698    }
699    else
700    {
701       SetWriteToRaw();
702    }
703 }
704
705 void File::RestoreWrite()
706 {
707    Archive->Restore(0x0028,0x0002);
708    Archive->Restore(0x0028,0x0004);
709    Archive->Restore(0x0028,0x0006);
710    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
711
712    // For old ACR-NEMA (24 bits problem)
713    Archive->Restore(0x0028,0x0100);
714    Archive->Restore(0x0028,0x0101);
715    Archive->Restore(0x0028,0x0102);
716
717    // For the LUT
718    Archive->Restore(0x0028,0x1101);
719    Archive->Restore(0x0028,0x1102);
720    Archive->Restore(0x0028,0x1103);
721    Archive->Restore(0x0028,0x1201);
722    Archive->Restore(0x0028,0x1202);
723    Archive->Restore(0x0028,0x1203);
724 }
725
726 void File::SetWriteFileTypeToACR()
727 {
728    Archive->Push(0x0002,0x0010);
729 }
730
731 void File::SetWriteFileTypeToExplicitVR()
732 {
733    std::string ts = Util::DicomString( 
734       Document::GetTransferSyntaxValue(ExplicitVRLittleEndian).c_str() );
735
736    ValEntry* tss = CopyValEntry(0x0002,0x0010);
737    tss->SetValue(ts);
738
739    Archive->Push(tss);
740 }
741
742 void File::SetWriteFileTypeToImplicitVR()
743 {
744    std::string ts = Util::DicomString(
745       Document::GetTransferSyntaxValue(ImplicitVRLittleEndian).c_str() );
746
747    ValEntry* tss = CopyValEntry(0x0002,0x0010);
748    tss->SetValue(ts);
749
750    Archive->Push(tss);
751 }
752
753 void File::RestoreWriteFileType()
754 {
755    Archive->Restore(0x0002,0x0010);
756 }
757
758 void File::SetWriteToLibido()
759 {
760    ValEntry *oldRow = dynamic_cast<ValEntry *>
761                 (HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
762    ValEntry *oldCol = dynamic_cast<ValEntry *>
763                 (HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
764    
765    if( oldRow && oldCol )
766    {
767       std::string rows, columns; 
768
769       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
770       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
771
772       newRow->Copy(oldCol);
773       newCol->Copy(oldRow);
774
775       newRow->SetValue(oldCol->GetValue());
776       newCol->SetValue(oldRow->GetValue());
777
778       Archive->Push(newRow);
779       Archive->Push(newCol);
780    }
781
782    ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
783    libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
784    Archive->Push(libidoCode);
785 }
786
787 void File::SetWriteToNoLibido()
788 {
789    ValEntry *recCode = dynamic_cast<ValEntry *>
790                 (HeaderInternal->GetDocEntryByNumber(0x0008,0x0010));
791    if( recCode )
792    {
793       if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
794       {
795          ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
796          libidoCode->SetValue("");
797          Archive->Push(libidoCode);
798       }
799    }
800 }
801
802 void File::RestoreWriteOfLibido()
803 {
804    Archive->Restore(0x0028,0x0010);
805    Archive->Restore(0x0028,0x0011);
806    Archive->Restore(0x0008,0x0010);
807 }
808
809 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
810 {
811    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
812    ValEntry* newE;
813
814    if(oldE)
815    {
816       newE = new ValEntry(oldE->GetDictEntry());
817       newE->Copy(oldE);
818    }
819    else
820    {
821       newE = GetHeader()->NewValEntryByNumber(group,element);
822    }
823
824    return(newE);
825 }
826
827 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
828 {
829    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
830    BinEntry* newE;
831
832    if(oldE)
833    {
834       newE = new BinEntry(oldE->GetDictEntry());
835       newE->Copy(oldE);
836    }
837    else
838    {
839       newE = GetHeader()->NewBinEntryByNumber(group,element);
840    }
841
842    return(newE);
843 }
844
845 //-----------------------------------------------------------------------------
846 // Protected
847 /**
848  * \brief Factorization for various forms of constructors.
849  */
850 void File::Initialise()
851 {
852    WriteMode = WMODE_RAW;
853    WriteType = ExplicitVR;
854
855    PixelReadConverter = new PixelReadConvert;
856    PixelWriteConverter = new PixelWriteConvert;
857    Archive = new DocEntryArchive( HeaderInternal );
858
859    if ( HeaderInternal->IsReadable() )
860    {
861       PixelReadConverter->GrabInformationsFromHeader( HeaderInternal );
862    }
863 }
864
865 uint8_t* File::GetRaw()
866 {
867    uint8_t* raw = PixelReadConverter->GetRaw();
868    if ( ! raw )
869    {
870       // The Raw image migth not be loaded yet:
871       std::ifstream* fp = HeaderInternal->OpenFile();
872       PixelReadConverter->ReadAndDecompressPixelData( fp );
873       if(fp) 
874          HeaderInternal->CloseFile();
875
876       raw = PixelReadConverter->GetRaw();
877       if ( ! raw )
878       {
879          dbg.Verbose(0, "File::GetRaw: read/decompress of "
880                         "pixel data apparently went wrong.");
881          return 0;
882       }
883    }
884
885    return raw;
886 }
887
888 //-----------------------------------------------------------------------------
889 // Private
890
891 //-----------------------------------------------------------------------------
892 } // end namespace gdcm
893