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