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