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