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