]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* src/gdcmFile.cxx : Add the code of ReplaceOrCreateByNumber to not have
[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 10:51:49 $
7   Version:   $Revision: 1.177 $
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 bool File::ReplaceOrCreateByNumber(uint8_t* binArea, int lgth,
457                                    uint16_t group, uint16_t element)
458 {
459    return HeaderInternal->ReplaceOrCreateByNumber(binArea,lgth,group,element) != NULL;
460 }
461
462 /**
463  * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
464  */
465 uint8_t* File::GetLutRGBA()
466 {
467    return PixelReadConverter->GetLutRGBA();
468 }
469
470 //-----------------------------------------------------------------------------
471 // Protected
472 /**
473  * \brief NOT a end user inteded function
474  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
475  * @param fileName name of the file to be created
476  *                 (any already existing file is overwritten)
477  * @param  type file type (ExplicitVR, ImplicitVR, ...)
478  * @return false if write fails
479  */
480 bool File::WriteBase (std::string const & fileName)
481 {
482    switch(WriteType)
483    {
484       case ImplicitVR:
485          SetWriteFileTypeToImplicitVR();
486          break;
487       case ExplicitVR:
488          SetWriteFileTypeToExplicitVR();
489          break;
490       case ACR:
491       case ACR_LIBIDO:
492          SetWriteFileTypeToACR();
493          break;
494       default:
495          SetWriteFileTypeToExplicitVR();
496    }
497
498    // --------------------------------------------------------------
499    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
500    //
501    // if recognition code tells us we dealt with a LibIDO image
502    // we reproduce on disk the switch between lineNumber and columnNumber
503    // just before writting ...
504    /// \todo the best trick would be *change* the recognition code
505    ///       but pb expected if user deals with, e.g. COMPLEX images
506    if( WriteType == ACR_LIBIDO )
507    {
508       SetWriteToLibido();
509    }
510    else
511    {
512       SetWriteToNoLibido();
513    }
514    // ----------------- End of Special Patch ----------------
515   
516    switch(WriteMode)
517    {
518       case WMODE_RAW :
519          SetWriteToRaw();
520          break;
521       case WMODE_RGB :
522          SetWriteToRGB();
523          break;
524    }
525
526    bool check = CheckWriteIntegrity();
527    if(check)
528    {
529       check = HeaderInternal->Write(fileName,WriteType);
530    }
531
532    RestoreWrite();
533    RestoreWriteFileType();
534
535    // --------------------------------------------------------------
536    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
537    // 
538    // ...and we restore the Header to be Dicom Compliant again 
539    // just after writting
540    RestoreWriteOfLibido();
541    // ----------------- End of Special Patch ----------------
542
543    return check;
544 }
545
546 /**
547  * \brief Check the write integrity
548  *
549  * The tests made are :
550  *  - verify the size of the image to write with the possible write
551  *    when the user set an image data
552  * @return true if the check successfulls
553  */
554 bool File::CheckWriteIntegrity()
555 {
556    if(PixelWriteConverter->GetUserData())
557    {
558       int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
559       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
560       {
561          numberBitsAllocated = 16;
562       }
563
564       size_t decSize = HeaderInternal->GetXSize()
565                     * HeaderInternal->GetYSize() 
566                     * HeaderInternal->GetZSize()
567                     * ( numberBitsAllocated / 8 )
568                     * HeaderInternal->GetSamplesPerPixel();
569       size_t rgbSize = decSize;
570       if( HeaderInternal->HasLUT() )
571          rgbSize = decSize * 3;
572
573       switch(WriteMode)
574       {
575          case WMODE_RAW :
576             if( decSize!=PixelWriteConverter->GetUserDataSize() )
577             {
578                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect (Raw)");
579                //std::cerr << "File::CheckWriteIntegrity: Data size is incorrect (Raw)\n"
580                //          << decSize << " / " << PixelWriteConverter->GetUserDataSize() << "\n";
581                return false;
582             }
583             break;
584          case WMODE_RGB :
585             if( rgbSize!=PixelWriteConverter->GetUserDataSize() )
586             {
587                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect (RGB)");
588                //std::cerr << "File::CheckWriteIntegrity: Data size is incorrect (RGB)\n"
589                //          << decSize << " / " << PixelWriteConverter->GetUserDataSize() << "\n";
590                return false;
591             }
592             break;
593       }
594    }
595    
596    return true;
597 }
598
599 void File::SetWriteToRaw()
600 {
601    if(HeaderInternal->GetNumberOfScalarComponents()==3 && !HeaderInternal->HasLUT())
602    {
603       SetWriteToRGB();
604    } 
605    else
606    {
607       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
608       if(HeaderInternal->HasLUT())
609       {
610          photInt->SetValue("PALETTE COLOR ");
611       }
612       else
613       {
614          photInt->SetValue("MONOCHROME1 ");
615       }
616
617       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
618                                        PixelReadConverter->GetRawSize());
619
620       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
621       pixel->SetValue(GDCM_BINLOADED);
622       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
623       pixel->SetLength(PixelWriteConverter->GetDataSize());
624
625       Archive->Push(photInt);
626       Archive->Push(pixel);
627    }
628 }
629
630 void File::SetWriteToRGB()
631 {
632    if(HeaderInternal->GetNumberOfScalarComponents()==3)
633    {
634       PixelReadConverter->BuildRGBImage();
635       
636       ValEntry* spp = CopyValEntry(0x0028,0x0002);
637       spp->SetValue("3 ");
638
639       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
640       planConfig->SetValue("0 ");
641
642       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
643       photInt->SetValue("RGB ");
644
645       if(PixelReadConverter->GetRGB())
646       {
647          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
648                                           PixelReadConverter->GetRGBSize());
649       }
650       else // Raw data
651       {
652          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
653                                           PixelReadConverter->GetRawSize());
654       }
655
656       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
657       pixel->SetValue(GDCM_BINLOADED);
658       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
659       pixel->SetLength(PixelWriteConverter->GetDataSize());
660
661       Archive->Push(spp);
662       Archive->Push(planConfig);
663       Archive->Push(photInt);
664       Archive->Push(pixel);
665
666       // Remove any LUT
667       Archive->Push(0x0028,0x1101);
668       Archive->Push(0x0028,0x1102);
669       Archive->Push(0x0028,0x1103);
670       Archive->Push(0x0028,0x1201);
671       Archive->Push(0x0028,0x1202);
672       Archive->Push(0x0028,0x1203);
673
674       // For old ACR-NEMA
675       // Thus, we have a RGB image and the bits allocated = 24 and 
676       // samples per pixels = 1 (in the read file)
677       if(HeaderInternal->GetBitsAllocated()==24) 
678       {
679          ValEntry* bitsAlloc = CopyValEntry(0x0028,0x0100);
680          bitsAlloc->SetValue("8 ");
681
682          ValEntry* bitsStored = CopyValEntry(0x0028,0x0101);
683          bitsStored->SetValue("8 ");
684
685          ValEntry* highBit = CopyValEntry(0x0028,0x0102);
686          highBit->SetValue("7 ");
687
688          Archive->Push(bitsAlloc);
689          Archive->Push(bitsStored);
690          Archive->Push(highBit);
691       }
692    }
693    else
694    {
695       SetWriteToRaw();
696    }
697 }
698
699 void File::RestoreWrite()
700 {
701    Archive->Restore(0x0028,0x0002);
702    Archive->Restore(0x0028,0x0004);
703    Archive->Restore(0x0028,0x0006);
704    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
705
706    // For old ACR-NEMA (24 bits problem)
707    Archive->Restore(0x0028,0x0100);
708    Archive->Restore(0x0028,0x0101);
709    Archive->Restore(0x0028,0x0102);
710
711    // For the LUT
712    Archive->Restore(0x0028,0x1101);
713    Archive->Restore(0x0028,0x1102);
714    Archive->Restore(0x0028,0x1103);
715    Archive->Restore(0x0028,0x1201);
716    Archive->Restore(0x0028,0x1202);
717    Archive->Restore(0x0028,0x1203);
718 }
719
720 void File::SetWriteFileTypeToACR()
721 {
722    Archive->Push(0x0002,0x0010);
723 }
724
725 void File::SetWriteFileTypeToExplicitVR()
726 {
727    std::string ts = Util::DicomString( 
728       Document::GetTransferSyntaxValue(ExplicitVRLittleEndian).c_str() );
729
730    ValEntry* tss = CopyValEntry(0x0002,0x0010);
731    tss->SetValue(ts);
732
733    Archive->Push(tss);
734 }
735
736 void File::SetWriteFileTypeToImplicitVR()
737 {
738    std::string ts = Util::DicomString(
739       Document::GetTransferSyntaxValue(ImplicitVRLittleEndian).c_str() );
740
741    ValEntry* tss = CopyValEntry(0x0002,0x0010);
742    tss->SetValue(ts);
743
744    Archive->Push(tss);
745 }
746
747 void File::RestoreWriteFileType()
748 {
749    Archive->Restore(0x0002,0x0010);
750 }
751
752 void File::SetWriteToLibido()
753 {
754    ValEntry *oldRow = dynamic_cast<ValEntry *>
755                 (HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
756    ValEntry *oldCol = dynamic_cast<ValEntry *>
757                 (HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
758    
759    if( oldRow && oldCol )
760    {
761       std::string rows, columns; 
762
763       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
764       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
765
766       newRow->Copy(oldCol);
767       newCol->Copy(oldRow);
768
769       newRow->SetValue(oldCol->GetValue());
770       newCol->SetValue(oldRow->GetValue());
771
772       Archive->Push(newRow);
773       Archive->Push(newCol);
774    }
775
776    ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
777    libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
778    Archive->Push(libidoCode);
779 }
780
781 void File::SetWriteToNoLibido()
782 {
783    ValEntry *recCode = dynamic_cast<ValEntry *>
784                 (HeaderInternal->GetDocEntryByNumber(0x0008,0x0010));
785    if( recCode )
786    {
787       if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
788       {
789          ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
790          libidoCode->SetValue("");
791          Archive->Push(libidoCode);
792       }
793    }
794 }
795
796 void File::RestoreWriteOfLibido()
797 {
798    Archive->Restore(0x0028,0x0010);
799    Archive->Restore(0x0028,0x0011);
800    Archive->Restore(0x0008,0x0010);
801 }
802
803 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
804 {
805    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
806    ValEntry* newE;
807
808    if(oldE)
809    {
810       newE = new ValEntry(oldE->GetDictEntry());
811       newE->Copy(oldE);
812    }
813    else
814    {
815       newE = GetHeader()->NewValEntryByNumber(group,element);
816    }
817
818    return(newE);
819 }
820
821 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
822 {
823    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
824    BinEntry* newE;
825
826    if(oldE)
827    {
828       newE = new BinEntry(oldE->GetDictEntry());
829       newE->Copy(oldE);
830    }
831    else
832    {
833       newE = GetHeader()->NewBinEntryByNumber(group,element);
834    }
835
836    return(newE);
837 }
838
839 //-----------------------------------------------------------------------------
840 // Protected
841 /**
842  * \brief Factorization for various forms of constructors.
843  */
844 void File::Initialise()
845 {
846    WriteMode = WMODE_RAW;
847    WriteType = ExplicitVR;
848
849    PixelReadConverter = new PixelReadConvert;
850    PixelWriteConverter = new PixelWriteConvert;
851    Archive = new DocEntryArchive( HeaderInternal );
852
853    if ( HeaderInternal->IsReadable() )
854    {
855       PixelReadConverter->GrabInformationsFromHeader( HeaderInternal );
856    }
857 }
858
859 uint8_t* File::GetRaw()
860 {
861    uint8_t* raw = PixelReadConverter->GetRaw();
862    if ( ! raw )
863    {
864       // The Raw image migth not be loaded yet:
865       std::ifstream* fp = HeaderInternal->OpenFile();
866       PixelReadConverter->ReadAndDecompressPixelData( fp );
867       if(fp) 
868          HeaderInternal->CloseFile();
869
870       raw = PixelReadConverter->GetRaw();
871       if ( ! raw )
872       {
873          dbg.Verbose(0, "File::GetRaw: read/decompress of "
874                         "pixel data apparently went wrong.");
875          return 0;
876       }
877    }
878
879    return raw;
880 }
881
882 //-----------------------------------------------------------------------------
883 // Private
884
885 //-----------------------------------------------------------------------------
886 } // end namespace gdcm
887