]> Creatis software - gdcm.git/blob - src/gdcmFileHelper.cxx
* src/*.cxx : first parss to normalize file organisation
[gdcm.git] / src / gdcmFileHelper.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFileHelper.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/02/01 10:29:55 $
7   Version:   $Revision: 1.9 $
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   Get the size of the image data
129  *          If the image can be RGB (with a lut or by default), the size 
130  *          corresponds to the RGB image
131  *         (use GetImageDataRawSize if you want to be sure to get *only*
132  *          the size of the pixels)
133  * @return  The image size
134  */
135 size_t FileHelper::GetImageDataSize()
136 {
137    if ( PixelWriteConverter->GetUserData() )
138    {
139       return PixelWriteConverter->GetUserDataSize();
140    }
141
142    return PixelReadConverter->GetRGBSize();
143 }
144
145 /**
146  * \brief   Get the size of the image data
147  *          If the image could be converted to RGB using a LUT, 
148  *          this transformation is not taken into account by GetImageDataRawSize
149  *          (use GetImageDataSize if you wish)
150  * @return  The raw image size
151  */
152 size_t FileHelper::GetImageDataRawSize()
153 {
154    if ( PixelWriteConverter->GetUserData() )
155    {
156       return PixelWriteConverter->GetUserDataSize();
157    }
158
159    return PixelReadConverter->GetRawSize();
160 }
161
162 /**
163  * \brief   - Allocates necessary memory, 
164  *          - Reads the pixels from disk (uncompress if necessary),
165  *          - Transforms YBR pixels, if any, into RGB pixels
166  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
167  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
168  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
169  * @return  Pointer to newly allocated pixel data.
170  *          NULL if alloc fails 
171  */
172 uint8_t *FileHelper::GetImageData()
173 {
174    if ( PixelWriteConverter->GetUserData() )
175    {
176       return PixelWriteConverter->GetUserData();
177    }
178
179    if ( ! GetRaw() )
180    {
181       // If the decompression failed nothing can be done.
182       return 0;
183    }
184
185    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
186    {
187       return PixelReadConverter->GetRGB();
188    }
189    else
190    {
191       // When no LUT or LUT conversion fails, return the Raw
192       return PixelReadConverter->GetRaw();
193    }
194 }
195
196 /**
197  * \brief   Allocates necessary memory, 
198  *          Transforms YBR pixels (if any) into RGB pixels
199  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
200  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
201  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
202  * @return  Pointer to newly allocated pixel data.
203  * \        NULL if alloc fails 
204  */
205 uint8_t *FileHelper::GetImageDataRaw ()
206 {
207    return GetRaw();
208 }
209
210 /**
211  * \brief
212  *          Read the pixels from disk (uncompress if necessary),
213  *          Transforms YBR pixels, if any, into RGB pixels
214  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
215  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
216  *          Copies at most MaxSize bytes of pixel data to caller allocated
217  *          memory space.
218  * \warning This function allows people that want to build a volume
219  *          from an image stack *not to* have, first to get the image pixels, 
220  *          and then move them to the volume area.
221  *          It's absolutely useless for any VTK user since vtk chooses 
222  *          to invert the lines of an image, that is the last line comes first
223  *          (for some axis related reasons?). Hence he will have 
224  *          to load the image line by line, starting from the end.
225  *          VTK users have to call GetImageData
226  *     
227  * @param   destination Address (in caller's memory space) at which the
228  *          pixel data should be copied
229  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
230  *          is not sufficient to hold the pixel data the copy is not
231  *          executed (i.e. no partial copy).
232  * @return  On success, the number of bytes actually copied. Zero on
233  *          failure e.g. MaxSize is lower than necessary.
234  */
235 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
236 {
237    if ( ! GetRaw() )
238    {
239       // If the decompression failed nothing can be done.
240       return 0;
241    }
242
243    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
244    {
245       if ( PixelReadConverter->GetRGBSize() > maxSize )
246       {
247          gdcmVerboseMacro( "Pixel data bigger than caller's expected MaxSize");
248          return 0;
249       }
250       memcpy( destination,
251               (void*)PixelReadConverter->GetRGB(),
252               PixelReadConverter->GetRGBSize() );
253       return PixelReadConverter->GetRGBSize();
254    }
255
256    // Either no LUT conversion necessary or LUT conversion failed
257    if ( PixelReadConverter->GetRawSize() > maxSize )
258    {
259       gdcmVerboseMacro( "Pixel data bigger than caller's expected MaxSize");
260       return 0;
261    }
262    memcpy( destination,
263            (void*)PixelReadConverter->GetRaw(),
264            PixelReadConverter->GetRawSize() );
265    return PixelReadConverter->GetRawSize();
266 }
267
268 /**
269  * \brief   Points the internal pointer to the callers inData
270  *          image representation, BUT WITHOUT COPYING THE DATA.
271  *          'image' Pixels are presented as C-like 2D arrays : line per line.
272  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
273  * \warning Since the pixels are not copied, it is the caller's responsability
274  *          not to deallocate its data before gdcm uses them (e.g. with
275  *          the Write() method.
276  * @param inData user supplied pixel area
277  * @param expectedSize total image size, in Bytes
278  *
279  * @return boolean
280  */
281 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
282 {
283    SetUserData(inData,expectedSize);
284 }
285
286 /**
287  * \brief   Set the image data defined by the user
288  * \warning When writting the file, this data are get as default data to write
289  */
290 void FileHelper::SetUserData(uint8_t *data, size_t expectedSize)
291 {
292    PixelWriteConverter->SetUserData(data,expectedSize);
293 }
294
295 /**
296  * \brief   Get the image data defined by the user
297  * \warning When writting the file, this data are get as default data to write
298  */
299 uint8_t *FileHelper::GetUserData()
300 {
301    return PixelWriteConverter->GetUserData();
302 }
303
304 /**
305  * \brief   Get the image data size defined by the user
306  * \warning When writting the file, this data are get as default data to write
307  */
308 size_t FileHelper::GetUserDataSize()
309 {
310    return PixelWriteConverter->GetUserDataSize();
311 }
312
313 /**
314  * \brief   Get the image data from the file.
315  *          If a LUT is found, the data are expanded to be RGB
316  */
317 uint8_t *FileHelper::GetRGBData()
318 {
319    return PixelReadConverter->GetRGB();
320 }
321
322 /**
323  * \brief   Get the image data size from the file.
324  *          If a LUT is found, the data are expanded to be RGB
325  */
326 size_t FileHelper::GetRGBDataSize()
327 {
328    return PixelReadConverter->GetRGBSize();
329 }
330
331 /**
332  * \brief   Get the image data from the file.
333  *          If a LUT is found, the data are not expanded !
334  */
335 uint8_t *FileHelper::GetRawData()
336 {
337    return PixelReadConverter->GetRaw();
338 }
339
340 /**
341  * \brief   Get the image data size from the file.
342  *          If a LUT is found, the data are not expanded !
343  */
344 size_t FileHelper::GetRawDataSize()
345 {
346    return PixelReadConverter->GetRawSize();
347 }
348
349 /**
350  * \brief Writes on disk A SINGLE Dicom file
351  *        NO test is performed on  processor "Endiannity".
352  *        It's up to the user to call his Reader properly
353  * @param fileName name of the file to be created
354  *                 (any already existing file is over written)
355  * @return false if write fails
356  */
357
358 bool FileHelper::WriteRawData(std::string const &fileName)
359 {
360   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
361    if (!fp1)
362    {
363       gdcmVerboseMacro( "Fail to open (write) file:" << fileName.c_str());
364       return false;
365    }
366
367    if( PixelWriteConverter->GetUserData() )
368    {
369       fp1.write( (char*)PixelWriteConverter->GetUserData(), 
370                  PixelWriteConverter->GetUserDataSize() );
371    }
372    else if ( PixelReadConverter->GetRGB() )
373    {
374       fp1.write( (char*)PixelReadConverter->GetRGB(), 
375                  PixelReadConverter->GetRGBSize());
376    }
377    else if ( PixelReadConverter->GetRaw() )
378    {
379       fp1.write( (char*)PixelReadConverter->GetRaw(), 
380                  PixelReadConverter->GetRawSize());
381    }
382    else
383    {
384       gdcmErrorMacro( "Nothing written." );
385    }
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 FileHelper::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 FileHelper::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 FileHelper::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 FileHelper::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 = FileInternal->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   elem element number of the Dicom Element to modify
521  */
522 bool FileHelper::SetValEntry(std::string const &content,
523                     uint16_t group, uint16_t elem)
524
525    return FileInternal->SetValEntry(content,group,elem);
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   elem element number of the Dicom Element to modify
537  */
538 bool FileHelper::SetBinEntry(uint8_t *content, int lgth,
539                                  uint16_t group, uint16_t elem)
540 {
541    return FileInternal->SetBinEntry(content,lgth,group,elem);
542 }
543
544 /**
545  * \brief   Modifies the value of a given DocEntry (Dicom entry)
546  *          when it exists. Create it with the given value when unexistant.
547  * @param   content (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 Dicom entry (NULL when creation
551  *          failed).
552  */ 
553 ValEntry *FileHelper::InsertValEntry(std::string const &content,
554                                 uint16_t group, uint16_t elem)
555 {
556    return FileInternal->InsertValEntry(content,group,elem);
557 }
558
559 /*
560  * \brief   Modifies the value of a given DocEntry (Dicom entry)
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 Dicom entry (NULL when creation
567  *          failed).
568  */
569 BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth,
570                                 uint16_t group, uint16_t elem)
571 {
572    return FileInternal->InsertBinEntry(binArea,lgth,group,elem);
573 }
574
575 /*
576  * \brief   Modifies the value of a given DocEntry (Dicom entry)
577  *          when it exists. Create it with the given value when unexistant.
578  *          A copy of the binArea is made to be kept in the Document.
579  * @param   group   Group number of the Entry 
580  * @param   elem  Element number of the Entry
581  * \return  pointer to the modified/created Dicom entry (NULL when creation
582  *          failed).
583  */
584 SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
585 {
586    return FileInternal->InsertSeqEntry(group,elem);
587 }
588
589 /**
590  * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
591  */
592 uint8_t* FileHelper::GetLutRGBA()
593 {
594    return PixelReadConverter->GetLutRGBA();
595 }
596
597 //-----------------------------------------------------------------------------
598 // Protected
599 /**
600  * \brief Check the write integrity
601  *
602  * The tests made are :
603  *  - verify the size of the image to write with the possible write
604  *    when the user set an image data
605  * @return true if check is successfull
606  */
607 bool FileHelper::CheckWriteIntegrity()
608 {
609    if(PixelWriteConverter->GetUserData())
610    {
611       int numberBitsAllocated = FileInternal->GetBitsAllocated();
612       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
613       {
614          numberBitsAllocated = 16;
615       }
616
617       size_t decSize = FileInternal->GetXSize()
618                     * FileInternal->GetYSize() 
619                     * FileInternal->GetZSize()
620                     * ( numberBitsAllocated / 8 )
621                     * FileInternal->GetSamplesPerPixel();
622       size_t rgbSize = decSize;
623       if( FileInternal->HasLUT() )
624          rgbSize = decSize * 3;
625
626       switch(WriteMode)
627       {
628          case WMODE_RAW :
629             if( decSize!=PixelWriteConverter->GetUserDataSize() )
630             {
631                gdcmVerboseMacro( "Data size (Raw) is incorrect. Should be " 
632                            << decSize << " / Found :" 
633                            << PixelWriteConverter->GetUserDataSize() );
634                return false;
635             }
636             break;
637          case WMODE_RGB :
638             if( rgbSize!=PixelWriteConverter->GetUserDataSize() )
639             {
640                gdcmVerboseMacro( "Data size (RGB) is incorrect. Should be " 
641                           << decSize << " / Found " 
642                           << PixelWriteConverter->GetUserDataSize() );
643                return false;
644             }
645             break;
646       }
647    }
648    
649    return true;
650 }
651
652 /**
653  * \brief   
654  */ 
655 void FileHelper::SetWriteToRaw()
656 {
657    if( FileInternal->GetNumberOfScalarComponents() == 3 
658     && !FileInternal->HasLUT())
659    {
660       SetWriteToRGB();
661    } 
662    else
663    {
664       ValEntry *photInt = CopyValEntry(0x0028,0x0004);
665       if(FileInternal->HasLUT())
666       {
667          photInt->SetValue("PALETTE COLOR ");
668       }
669       else
670       {
671          photInt->SetValue("MONOCHROME1 ");
672       }
673
674       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
675                                        PixelReadConverter->GetRawSize());
676
677       BinEntry *pixel = 
678          CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
679       pixel->SetValue(GDCM_BINLOADED);
680       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
681       pixel->SetLength(PixelWriteConverter->GetDataSize());
682
683       Archive->Push(photInt);
684       Archive->Push(pixel);
685    }
686 }
687
688 /**
689  * \brief   
690  */ 
691 void FileHelper::SetWriteToRGB()
692 {
693    if(FileInternal->GetNumberOfScalarComponents()==3)
694    {
695       PixelReadConverter->BuildRGBImage();
696       
697       ValEntry *spp = CopyValEntry(0x0028,0x0002);
698       spp->SetValue("3 ");
699
700       ValEntry *planConfig = CopyValEntry(0x0028,0x0006);
701       planConfig->SetValue("0 ");
702
703       ValEntry *photInt = CopyValEntry(0x0028,0x0004);
704       photInt->SetValue("RGB ");
705
706       if(PixelReadConverter->GetRGB())
707       {
708          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
709                                           PixelReadConverter->GetRGBSize());
710       }
711       else // Raw data
712       {
713          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
714                                           PixelReadConverter->GetRawSize());
715       }
716
717       BinEntry *pixel = 
718          CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
719       pixel->SetValue(GDCM_BINLOADED);
720       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
721       pixel->SetLength(PixelWriteConverter->GetDataSize());
722
723       Archive->Push(spp);
724       Archive->Push(planConfig);
725       Archive->Push(photInt);
726       Archive->Push(pixel);
727
728       // Remove any LUT
729       Archive->Push(0x0028,0x1101);
730       Archive->Push(0x0028,0x1102);
731       Archive->Push(0x0028,0x1103);
732       Archive->Push(0x0028,0x1201);
733       Archive->Push(0x0028,0x1202);
734       Archive->Push(0x0028,0x1203);
735
736       // For old ACR-NEMA
737       // Thus, we have a RGB image and the bits allocated = 24 and 
738       // samples per pixels = 1 (in the read file)
739       if(FileInternal->GetBitsAllocated()==24) 
740       {
741          ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100);
742          bitsAlloc->SetValue("8 ");
743
744          ValEntry *bitsStored = CopyValEntry(0x0028,0x0101);
745          bitsStored->SetValue("8 ");
746
747          ValEntry *highBit = CopyValEntry(0x0028,0x0102);
748          highBit->SetValue("7 ");
749
750          Archive->Push(bitsAlloc);
751          Archive->Push(bitsStored);
752          Archive->Push(highBit);
753       }
754    }
755    else
756    {
757       SetWriteToRaw();
758    }
759 }
760
761 /**
762  * \brief   
763  */ 
764 void FileHelper::RestoreWrite()
765 {
766    Archive->Restore(0x0028,0x0002);
767    Archive->Restore(0x0028,0x0004);
768    Archive->Restore(0x0028,0x0006);
769    Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
770
771    // For old ACR-NEMA (24 bits problem)
772    Archive->Restore(0x0028,0x0100);
773    Archive->Restore(0x0028,0x0101);
774    Archive->Restore(0x0028,0x0102);
775
776    // For the LUT
777    Archive->Restore(0x0028,0x1101);
778    Archive->Restore(0x0028,0x1102);
779    Archive->Restore(0x0028,0x1103);
780    Archive->Restore(0x0028,0x1201);
781    Archive->Restore(0x0028,0x1202);
782    Archive->Restore(0x0028,0x1203);
783 }
784
785 /**
786  * \brief   
787  */ 
788 void FileHelper::SetWriteFileTypeToACR()
789 {
790    Archive->Push(0x0002,0x0010);
791 }
792
793 /**
794  * \brief   
795  */ 
796 void FileHelper::SetWriteFileTypeToExplicitVR()
797 {
798    std::string ts = Util::DicomString( 
799       Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
800
801    ValEntry *tss = CopyValEntry(0x0002,0x0010);
802    tss->SetValue(ts);
803
804    Archive->Push(tss);
805 }
806
807 /**
808  * \brief   
809  */ 
810 void FileHelper::SetWriteFileTypeToImplicitVR()
811 {
812    std::string ts = Util::DicomString(
813       Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
814
815    ValEntry *tss = CopyValEntry(0x0002,0x0010);
816    tss->SetValue(ts);
817
818    Archive->Push(tss);
819 }
820
821
822 /**
823  * \brief   
824  */ 
825 void FileHelper::RestoreWriteFileType()
826 {
827    Archive->Restore(0x0002,0x0010);
828 }
829
830 void FileHelper::SetWriteToLibido()
831 {
832    ValEntry *oldRow = dynamic_cast<ValEntry *>
833                 (FileInternal->GetDocEntry(0x0028, 0x0010));
834    ValEntry *oldCol = dynamic_cast<ValEntry *>
835                 (FileInternal->GetDocEntry(0x0028, 0x0011));
836    
837    if( oldRow && oldCol )
838    {
839       std::string rows, columns; 
840
841       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
842       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
843
844       newRow->Copy(oldCol);
845       newCol->Copy(oldRow);
846
847       newRow->SetValue(oldCol->GetValue());
848       newCol->SetValue(oldRow->GetValue());
849
850       Archive->Push(newRow);
851       Archive->Push(newCol);
852    }
853
854    ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
855    libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
856    Archive->Push(libidoCode);
857 }
858
859 /**
860  * \brief   
861  */ 
862 void FileHelper::SetWriteToNoLibido()
863 {
864    ValEntry *recCode = dynamic_cast<ValEntry *>
865                 (FileInternal->GetDocEntry(0x0008,0x0010));
866    if( recCode )
867    {
868       if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
869       {
870          ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
871          libidoCode->SetValue("");
872          Archive->Push(libidoCode);
873       }
874    }
875 }
876
877 /**
878  * \brief   
879  */ 
880 void FileHelper::RestoreWriteOfLibido()
881 {
882    Archive->Restore(0x0028,0x0010);
883    Archive->Restore(0x0028,0x0011);
884    Archive->Restore(0x0008,0x0010);
885 }
886
887 ValEntry *FileHelper::CopyValEntry(uint16_t group,uint16_t elem)
888 {
889    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
890    ValEntry *newE;
891
892    if(oldE)
893    {
894       newE = new ValEntry(oldE->GetDictEntry());
895       newE->Copy(oldE);
896    }
897    else
898    {
899       newE = GetFile()->NewValEntry(group,elem);
900    }
901
902    return newE;
903 }
904
905 /**
906  * \brief   Modifies the value of a given Bin Entry (Dicom Element)
907  *          when it exists. Create it with the given value when unexistant.
908  * @param   group   Group number of the Entry 
909  * @param   elem  Element number of the Entry
910  * \return  pointer to the modified/created Bin Entry (NULL when creation
911  *          failed).
912  */ 
913 BinEntry *FileHelper::CopyBinEntry(uint16_t group,uint16_t elem)
914 {
915    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
916    BinEntry *newE;
917
918    if(oldE)
919    {
920       newE = new BinEntry(oldE->GetDictEntry());
921       newE->Copy(oldE);
922    }
923    else
924    {
925       newE = GetFile()->NewBinEntry(group,elem);
926    }
927
928    return newE;
929 }
930
931 //-----------------------------------------------------------------------------
932 // Private
933 /**
934  * \brief Factorization for various forms of constructors.
935  */
936 void FileHelper::Initialize()
937 {
938    WriteMode = WMODE_RAW;
939    WriteType = ExplicitVR;
940
941    PixelReadConverter = new PixelReadConvert;
942    PixelWriteConverter = new PixelWriteConvert;
943    Archive = new DocEntryArchive( FileInternal );
944
945    if ( FileInternal->IsReadable() )
946    {
947       PixelReadConverter->GrabInformationsFromFile( FileInternal );
948    }
949 }
950
951 /**
952  * \brief   
953  */ 
954 uint8_t *FileHelper::GetRaw()
955 {
956    uint8_t *raw = PixelReadConverter->GetRaw();
957    if ( ! raw )
958    {
959       // The Raw image migth not be loaded yet:
960       std::ifstream *fp = FileInternal->OpenFile();
961       PixelReadConverter->ReadAndDecompressPixelData( fp );
962       if(fp) 
963          FileInternal->CloseFile();
964
965       raw = PixelReadConverter->GetRaw();
966       if ( ! raw )
967       {
968          gdcmVerboseMacro( "Read/decompress of pixel data apparently went wrong.");
969          return 0;
970       }
971    }
972
973    return raw;
974 }
975
976 //-----------------------------------------------------------------------------
977 // Print
978 void FileHelper::Print(std::ostream &os, std::string const &)
979 {
980    FileInternal->SetPrintLevel(PrintLevel);
981    FileInternal->Print(os);
982
983    PixelReadConverter->SetPrintLevel(PrintLevel);
984    PixelReadConverter->Print(os);
985 }
986
987 //-----------------------------------------------------------------------------
988 } // end namespace gdcm