]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* FIX : now, the DocEntries are all deleted in the gdcmElementSet.
[gdcm.git] / src / gdcmFile.cxx
1   /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/11/16 16:20:23 $
7   Version:   $Revision: 1.157 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmFile.h"
20 #include "gdcmDebug.h"
21 #include "gdcmUtil.h"
22 #include "gdcmBinEntry.h"
23 #include <fstream>
24
25 namespace gdcm 
26 {
27 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
28
29 //-------------------------------------------------------------------------
30 // Constructor / Destructor
31 /**
32  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
33  *        file (Header only deals with the ... header)
34  *        Opens (in read only and when possible) an existing file and checks
35  *        for DICOM compliance. Returns NULL on failure.
36  *        It will be up to the user to load the pixels into memory
37  *        (see GetImageData, GetImageDataRaw)
38  * \note  the in-memory representation of all available tags found in
39  *        the DICOM header is post-poned to first header information access.
40  *        This avoid a double parsing of public part of the header when
41  *        user sets an a posteriori shadow dictionary (efficiency can be
42  *        seen as a side effect).   
43  * @param header already built Header
44  */
45 File::File(Header *header)
46 {
47    HeaderInternal = header;
48    SelfHeader = false;
49    Initialise();
50 }
51
52 /**
53  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
54  *        file (Header only deals with the ... header)
55  *        Opens (in read only and when possible) an existing file and checks
56  *        for DICOM compliance. Returns NULL on failure.
57  *        It will be up to the user to load the pixels into memory
58  *        (see GetImageData, GetImageDataRaw)
59  * \note  the in-memory representation of all available tags found in
60  *        the DICOM header is post-poned to first header information access.
61  *        This avoid a double parsing of public part of the header when
62  *        one sets an a posteriori shadow dictionary (efficiency can be
63  *        seen as a side effect).   
64  * @param filename file to be opened for parsing
65  */
66 File::File(std::string const & filename )
67 {
68    HeaderInternal = new Header( filename );
69    SelfHeader = true;
70    Initialise();
71 }
72
73 /**
74  * \brief Factorization for various forms of constructors.
75  */
76 void File::Initialise()
77 {
78    PixelConverter = NULL; //just in case
79    if ( HeaderInternal->IsReadable() )
80    {
81       ImageDataSizeRaw = ComputeDecompressedPixelDataSizeFromHeader();
82       if ( HeaderInternal->HasLUT() )
83       {
84          ImageDataSize = 3 * ImageDataSizeRaw;
85       }
86       else
87       {
88          ImageDataSize = ImageDataSizeRaw;
89       }
90
91       PixelConverter = new PixelConvert;
92       PixelConverter->GrabInformationsFromHeader( HeaderInternal );
93    }
94    SaveInitialValues();
95 }
96
97 /**
98  * \brief canonical destructor
99  * \note  If the Header was created by the File constructor,
100  *        it is destroyed by the File
101  */
102 File::~File()
103
104    if( SelfHeader )
105    {
106       delete HeaderInternal;
107    }
108    HeaderInternal = 0;
109
110    DeleteInitialValues();
111    if( PixelConverter )
112    {
113       delete PixelConverter;
114    }
115 }
116
117 /**
118  * \brief Sets some initial values for the Constructor
119  * \warning not end user intended
120  */
121 void File::SaveInitialValues()
122
123
124    PixelRead  = -1; // no ImageData read yet.
125    LastAllocatedPixelDataLength = 0;
126    Pixel_Data = 0;
127
128    InitialSpp = "";     
129    InitialPhotInt = "";
130    InitialPlanConfig = "";
131    InitialBitsAllocated = "";
132    InitialHighBit = "";
133   
134    InitialRedLUTDescr   = 0;
135    InitialGreenLUTDescr = 0;
136    InitialBlueLUTDescr  = 0;
137    InitialRedLUTData    = 0;
138    InitialGreenLUTData  = 0;
139    InitialBlueLUTData   = 0; 
140
141    if ( HeaderInternal->IsReadable() )
142    {
143       // the following values *may* be modified 
144       // by File::GetImageDataIntoVectorRaw
145       // we save their initial value.
146       InitialSpp           = HeaderInternal->GetEntryByNumber(0x0028,0x0002);
147       InitialPhotInt       = HeaderInternal->GetEntryByNumber(0x0028,0x0004);
148       InitialPlanConfig    = HeaderInternal->GetEntryByNumber(0x0028,0x0006);
149       
150       InitialBitsAllocated = HeaderInternal->GetEntryByNumber(0x0028,0x0100);
151       InitialHighBit       = HeaderInternal->GetEntryByNumber(0x0028,0x0102);
152
153       // the following entries *may* be removed from the H table
154       // (NOT deleted ...) by File::GetImageDataIntoVectorRaw  
155       // we keep a pointer on them.
156       InitialRedLUTDescr   = HeaderInternal->GetDocEntryByNumber(0x0028,0x1101);
157       InitialGreenLUTDescr = HeaderInternal->GetDocEntryByNumber(0x0028,0x1102);
158       InitialBlueLUTDescr  = HeaderInternal->GetDocEntryByNumber(0x0028,0x1103);
159
160       InitialRedLUTData    = HeaderInternal->GetDocEntryByNumber(0x0028,0x1201);
161       InitialGreenLUTData  = HeaderInternal->GetDocEntryByNumber(0x0028,0x1202);
162       InitialBlueLUTData   = HeaderInternal->GetDocEntryByNumber(0x0028,0x1203); 
163    }
164 }
165
166 /**
167  * \brief restores some initial values
168  * \warning not end user intended
169  */
170 void File::RestoreInitialValues()
171 {   
172    if ( HeaderInternal->IsReadable() )
173    {      
174       // the following values *may* have been modified 
175       // by File::GetImageDataIntoVectorRaw
176       // we restore their initial value.
177       if ( InitialSpp != "")
178          HeaderInternal->SetEntryByNumber(InitialSpp,0x0028,0x0002);
179       if ( InitialPhotInt != "")
180          HeaderInternal->SetEntryByNumber(InitialPhotInt,0x0028,0x0004);
181       if ( InitialPlanConfig != "")
182
183          HeaderInternal->SetEntryByNumber(InitialPlanConfig,0x0028,0x0006);
184       if ( InitialBitsAllocated != "")
185           HeaderInternal->SetEntryByNumber(InitialBitsAllocated,0x0028,0x0100);
186       if ( InitialHighBit != "")
187           HeaderInternal->SetEntryByNumber(InitialHighBit,0x0028,0x0102);
188                
189       // the following entries *may* be have been removed from the H table
190       // (NOT deleted ...) by File::GetImageDataIntoVectorRaw  
191       // we restore them.
192
193       if (InitialRedLUTDescr)
194          HeaderInternal->AddEntry(InitialRedLUTDescr);
195       if (InitialGreenLUTDescr)
196          HeaderInternal->AddEntry(InitialGreenLUTDescr);
197       if (InitialBlueLUTDescr)
198          HeaderInternal->AddEntry(InitialBlueLUTDescr);
199
200       if (InitialRedLUTData)
201          HeaderInternal->AddEntry(InitialBlueLUTDescr);
202       if (InitialGreenLUTData)
203          HeaderInternal->AddEntry(InitialGreenLUTData);
204       if (InitialBlueLUTData)
205          HeaderInternal->AddEntry(InitialBlueLUTData);
206    }
207 }
208
209 /**
210  * \brief delete initial values (il they were saved)
211  *        of InitialLutDescriptors and InitialLutData
212  */
213 void File::DeleteInitialValues()
214
215 // InitialLutDescriptors and InitialLutData
216 // will have to be deleted if the don't belong any longer
217 // to the Header H table when the header is deleted...
218
219 // FIXME 
220 // We don't know if the InitialLutData are still in the header or not !
221 /*   if ( InitialRedLUTDescr )
222       delete InitialRedLUTDescr;
223   
224    if ( InitialGreenLUTDescr )
225       delete InitialGreenLUTDescr;
226       
227    if ( InitialBlueLUTDescr )
228       delete InitialBlueLUTDescr;
229        
230    if ( InitialRedLUTData )
231       delete InitialRedLUTData;
232    
233    if ( InitialGreenLUTData )
234       delete InitialGreenLUTData;
235       
236    if ( InitialBlueLUTData )
237       delete InitialBlueLUTData;*/
238 }
239
240 //-----------------------------------------------------------------------------
241 // Print
242
243 //-----------------------------------------------------------------------------
244 // Public
245
246 /**
247  * \brief     computes the length (in bytes) we must ALLOCATE to receive the
248  *            image(s) pixels (multiframes taken into account) 
249  * \warning : it is NOT the group 7FE0 length
250  *          (no interest for compressed images).
251  */
252 int File::ComputeDecompressedPixelDataSizeFromHeader()
253 {
254    // see PS 3.3-2003 : C.7.6.3.2.1  
255    // 
256    //   MONOCHROME1
257    //   MONOCHROME2
258    //   PALETTE COLOR
259    //   RGB
260    //   HSV  (Retired)
261    //   ARGB (Retired)
262    //   CMYK (Retired)
263    //   YBR_FULL
264    //   YBR_FULL_422 (no LUT, no Palette)
265    //   YBR_PARTIAL_422
266    //   YBR_ICT
267    //   YBR_RCT
268
269    // LUT's
270    // ex : gdcm-US-ALOKA-16.dcm
271    // 0028|1221 [OW]   [Segmented Red Palette Color Lookup Table Data]
272    // 0028|1222 [OW]   [Segmented Green Palette Color Lookup Table Data]  
273    // 0028|1223 [OW]   [Segmented Blue Palette Color Lookup Table Data]
274
275    // ex  : OT-PAL-8-face.dcm
276    // 0028|1201 [US]   [Red Palette Color Lookup Table Data]
277    // 0028|1202 [US]   [Green Palette Color Lookup Table Data]
278    // 0028|1203 [US]   [Blue Palette Color Lookup Table Data]
279
280    int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
281    // Number of "Bits Allocated" is fixed to 16 when:
282    //  - it is not defined (i.e. it's value is 0)
283    //  - it's 12, since we will expand the image to 16 bits (see
284    //    PixelConvert::ConvertDecompress12BitsTo16Bits() )
285    if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
286    {
287       numberBitsAllocated = 16;
288    } 
289
290    int DecompressedSize = HeaderInternal->GetXSize()
291                         * HeaderInternal->GetYSize() 
292                         * HeaderInternal->GetZSize()
293                         * ( numberBitsAllocated / 8 )
294                         * HeaderInternal->GetSamplesPerPixel();
295    
296    return DecompressedSize;
297 }
298
299 /**
300  * \brief   - Allocates necessary memory, 
301  *          - Reads the pixels from disk (uncompress if necessary),
302  *          - Transforms YBR pixels, if any, into RGB pixels
303  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
304  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
305  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
306  * @return  Pointer to newly allocated pixel data.
307  *          NULL if alloc fails 
308  */
309 uint8_t* File::GetImageData()
310 {
311    if ( ! GetDecompressed() )
312    {
313       // If the decompression failed nothing can be done.
314       return 0;
315    }
316                                                                                 
317    uint8_t* pixelData;
318    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
319    {
320       pixelData = PixelConverter->GetRGB();
321    }
322    else
323    {
324       // When no LUT or LUT conversion fails, return the decompressed
325       pixelData = PixelConverter->GetDecompressed();
326    }
327
328 // PIXELCONVERT CLEANME
329    // Restore the header in a disk-consistent state
330    // (if user asks twice to get the pixels from disk)
331    if ( PixelRead != -1 ) // File was "read" before
332    {
333       RestoreInitialValues();
334    }
335    if ( PixelConverter->GetRGB() )
336    {
337       // now, it's an RGB image
338       // Lets's write it in the Header
339       std::string spp = "3";        // Samples Per Pixel
340       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
341       std::string rgb = "RGB ";     // Photometric Interpretation
342       HeaderInternal->SetEntryByNumber(rgb,0x0028,0x0004);
343       std::string planConfig = "0"; // Planar Configuration
344       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
345       PixelRead = 0; // no PixelRaw
346    }
347    else
348    {
349       if ( HeaderInternal->HasLUT() )
350       {
351          // The LUT interpretation failed
352          std::string photometricInterpretation = Util::DicomString("MONOCHROME1");
353          HeaderInternal->SetEntryByNumber( photometricInterpretation,
354                                            0x0028, 0x0004 );
355          PixelRead = 0; // no PixelRaw
356       }
357       else
358       {
359          if ( PixelConverter->IsDecompressedRGB() )
360          {
361             ///////////////////////////////////////////////////
362             // now, it's an RGB image
363             // Lets's write it in the Header
364             // Droping Palette Color out of the Header
365             // has been moved to the Write process.
366             // TODO : move 'values' modification to the write process
367             //      : save also (in order to be able to restore)
368             //      : 'high bit' -when not equal to 'bits stored' + 1
369             //      : 'bits allocated', when it's equal to 12 ?!
370             std::string spp = "3";            // Samples Per Pixel
371             std::string photInt = "RGB ";     // Photometric Interpretation
372             std::string planConfig = "0";     // Planar Configuration
373             HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
374             HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
375             HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
376          }
377          PixelRead = 1; // PixelRaw
378       } 
379    }
380
381    // We say the value *is* loaded.
382    SetPixelData(pixelData);
383 // END PIXELCONVERT CLEANME
384
385    return pixelData;
386 }
387
388 /**
389  * \brief
390  *          Read the pixels from disk (uncompress if necessary),
391  *          Transforms YBR pixels, if any, into RGB pixels
392  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
393  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
394  *          Copies at most MaxSize bytes of pixel data to caller allocated
395  *          memory space.
396  * \warning This function allows people that want to build a volume
397  *          from an image stack *not to* have, first to get the image pixels, 
398  *          and then move them to the volume area.
399  *          It's absolutely useless for any VTK user since vtk chooses 
400  *          to invert the lines of an image, that is the last line comes first
401  *          (for some axis related reasons?). Hence he will have 
402  *          to load the image line by line, starting from the end.
403  *          VTK users have to call GetImageData
404  *     
405  * @param   destination Address (in caller's memory space) at which the
406  *          pixel data should be copied
407  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
408  *          is not sufficient to hold the pixel data the copy is not
409  *          executed (i.e. no partial copy).
410  * @return  On success, the number of bytes actually copied. Zero on
411  *          failure e.g. MaxSize is lower than necessary.
412  */
413 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
414 {
415    if ( ! GetDecompressed() )
416    {
417       // If the decompression failed nothing can be done.
418       return 0;
419    }
420
421    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
422    {
423       if ( PixelConverter->GetRGBSize() > maxSize )
424       {
425          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
426                         "than caller's expected MaxSize");
427          return 0;
428       }
429       memcpy( destination,
430               (void*)PixelConverter->GetRGB(),
431               PixelConverter->GetRGBSize() );
432       return PixelConverter->GetRGBSize();
433    }
434
435    // Either no LUT conversion necessary or LUT conversion failed
436    if ( PixelConverter->GetDecompressedSize() > maxSize )
437    {
438       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
439                      "than caller's expected MaxSize");
440       return 0;
441    }
442    memcpy( destination,
443            (void*)PixelConverter->GetDecompressed(),
444            PixelConverter->GetDecompressedSize() );
445    return PixelConverter->GetDecompressedSize();
446 }
447
448 /**
449  * \brief   Allocates necessary memory, 
450  *          Transforms YBR pixels (if any) into RGB pixels
451  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
452  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
453  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
454  * @return  Pointer to newly allocated pixel data.
455  * \        NULL if alloc fails 
456  */
457 uint8_t* File::GetImageDataRaw ()
458 {
459    uint8_t* decompressed = GetDecompressed();
460    if ( ! decompressed )
461    {
462       return 0;
463    }
464
465 // PIXELCONVERT CLEANME
466    // Restore the header in a disk-consistent state
467    // (if user asks twice to get the pixels from disk)
468    if ( PixelRead != -1 ) // File was "read" before
469    {
470       RestoreInitialValues();
471    }
472    if ( PixelConverter->IsDecompressedRGB() )
473    {
474       ///////////////////////////////////////////////////
475       // now, it's an RGB image
476       // Lets's write it in the Header
477       // Droping Palette Color out of the Header
478       // has been moved to the Write process.
479       // TODO : move 'values' modification to the write process
480       //      : save also (in order to be able to restore)
481       //      : 'high bit' -when not equal to 'bits stored' + 1
482       //      : 'bits allocated', when it's equal to 12 ?!
483       std::string spp = "3";            // Samples Per Pixel
484       std::string photInt = "RGB ";     // Photometric Interpretation
485       std::string planConfig = "0";     // Planar Configuration
486       HeaderInternal->SetEntryByNumber(spp,0x0028,0x0002);
487       HeaderInternal->SetEntryByNumber(photInt,0x0028,0x0004);
488       HeaderInternal->SetEntryByNumber(planConfig,0x0028,0x0006);
489    }
490
491    // We say the value *is* loaded.
492 /*   GetHeader()->SetEntryByNumber( GDCM_BINLOADED,
493    GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
494  
495    // will be 7fe0, 0010 in standard cases
496    GetHeader()->SetEntryBinAreaByNumber( decompressed,
497    GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());*/
498    SetPixelData(decompressed);
499  
500    PixelRead = 1; // PixelRaw
501 // END PIXELCONVERT CLEANME
502
503    return decompressed;
504 }
505
506 uint8_t* File::GetDecompressed()
507 {
508    uint8_t* decompressed = PixelConverter->GetDecompressed();
509    if ( ! decompressed )
510    {
511       // The decompressed image migth not be loaded yet:
512       std::ifstream* fp = HeaderInternal->OpenFile();
513       PixelConverter->ReadAndDecompressPixelData( fp );
514       if(fp) HeaderInternal->CloseFile();
515       decompressed = PixelConverter->GetDecompressed();
516       if ( ! decompressed )
517       {
518         dbg.Verbose(0, "File::GetDecompressed: read/decompress of "
519                        "pixel data apparently went wrong.");
520          return 0;
521       }
522    }
523
524    return decompressed;
525 }
526
527 /**
528  * \brief   Points the internal Pixel_Data pointer to the callers inData
529  *          image representation, BUT WITHOUT COPYING THE DATA.
530  *          'image' Pixels are presented as C-like 2D arrays : line per line.
531  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
532  * \warning Since the pixels are not copied, it is the caller's responsability
533  *          not to deallocate it's data before gdcm uses them (e.g. with
534  *          the Write() method.
535  * @param inData user supplied pixel area
536  * @param expectedSize total image size, in Bytes
537  *
538  * @return boolean
539  */
540 bool File::SetImageData(uint8_t* inData, size_t expectedSize)
541 {
542    HeaderInternal->SetImageDataSize( expectedSize );
543 // FIXME : if already allocated, memory leak !
544    Pixel_Data     = inData;
545    ImageDataSize = ImageDataSizeRaw = expectedSize;
546    PixelRead     = 1;
547 // FIXME : 7fe0, 0010 IS NOT set ...
548    return true;
549 }
550
551 /**
552  * \brief Writes on disk A SINGLE Dicom file
553  *        NO test is performed on  processor "Endiannity".
554  *        It's up to the user to call his Reader properly
555  * @param fileName name of the file to be created
556  *                 (any already existing file is over written)
557  * @return false if write fails
558  */
559
560 bool File::WriteRawData(std::string const & fileName)
561 {
562   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
563    if (!fp1)
564    {
565       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
566       return false;
567    }
568    fp1.write((char*)Pixel_Data, ImageDataSize);
569    fp1.close();
570
571    return true;
572 }
573
574 /**
575  * \brief Writes on disk A SINGLE Dicom file, 
576  *        using the Implicit Value Representation convention
577  *        NO test is performed on  processor "Endiannity".
578  * @param fileName name of the file to be created
579  *                 (any already existing file is overwritten)
580  * @return false if write fails
581  */
582
583 bool File::WriteDcmImplVR (std::string const & fileName)
584 {
585    return WriteBase(fileName, ImplicitVR);
586 }
587
588 /**
589 * \brief Writes on disk A SINGLE Dicom file, 
590  *        using the Explicit Value Representation convention
591  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
592  *                 (any already existing file is overwritten)
593  * @return false if write fails
594  */
595
596 bool File::WriteDcmExplVR (std::string const & fileName)
597 {
598    return WriteBase(fileName, ExplicitVR);
599 }
600
601 /**
602  * \brief Writes on disk A SINGLE Dicom file, 
603  *        using the ACR-NEMA convention
604  *        NO test is performed on  processor "Endiannity".
605  *        (a l'attention des logiciels cliniques 
606  *        qui ne prennent en entrĂ©e QUE des images ACR ...
607  * \warning if a DICOM_V3 header is supplied,
608  *         groups < 0x0008 and shadow groups are ignored
609  * \warning NO TEST is performed on processor "Endiannity".
610  * @param fileName name of the file to be created
611  *                 (any already existing file is overwritten)
612  * @return false if write fails
613  */
614
615 bool File::WriteAcr (std::string const & fileName)
616 {
617    return WriteBase(fileName, ACR);
618 }
619
620 //-----------------------------------------------------------------------------
621 // Protected
622 /**
623  * \brief NOT a end user inteded function
624  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
625  * @param fileName name of the file to be created
626  *                 (any already existing file is overwritten)
627  * @param  type file type (ExplicitVR, ImplicitVR, ...)
628  * @return false if write fails
629  */
630 bool File::WriteBase (std::string const & fileName, FileType type)
631 {
632    if ( PixelRead == -1 && type != ExplicitVR)
633    {
634       return false;
635    }
636
637    std::ofstream* fp1 = new std::ofstream(fileName.c_str(), 
638                               std::ios::out | std::ios::binary);
639    if (fp1 == NULL)
640    {
641       dbg.Verbose(2, "Failed to open (write) File: " , fileName.c_str());
642       return false;
643    }
644
645    if ( type == ImplicitVR || type == ExplicitVR )
646    {
647       // writing Dicom File Preamble
648       char filePreamble[128];
649       memset(filePreamble, 0, 128);
650       fp1->write(filePreamble, 128);
651       fp1->write("DICM", 4);
652    }
653
654    // --------------------------------------------------------------
655    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
656    //
657    // if recognition code tells us we dealt with a LibIDO image
658    // we reproduce on disk the switch between lineNumber and columnNumber
659    // just before writting ...
660    
661    /// \todo the best trick would be *change* the recognition code
662    ///       but pb expected if user deals with, e.g. COMPLEX images
663
664    std::string rows, columns; 
665    if ( HeaderInternal->GetFileType() == ACR_LIBIDO)
666    {
667       rows    = HeaderInternal->GetEntryByNumber(0x0028, 0x0010);
668       columns = HeaderInternal->GetEntryByNumber(0x0028, 0x0011);
669
670       HeaderInternal->SetEntryByNumber(columns,  0x0028, 0x0010);
671       HeaderInternal->SetEntryByNumber(rows   ,  0x0028, 0x0011);
672    }
673    // ----------------- End of Special Patch ----------------
674       
675    uint16_t grPixel  = HeaderInternal->GetGrPixel();
676    uint16_t numPixel = HeaderInternal->GetNumPixel();;
677           
678    DocEntry* PixelElement = 
679       GetHeader()->GetDocEntryByNumber(grPixel, numPixel);  
680  
681    if ( PixelRead == 1 )
682    {
683       // we read pixel 'as is' (no tranformation LUT -> RGB)
684       PixelElement->SetLength( ImageDataSizeRaw );
685    }
686    else if ( PixelRead == 0 )
687    {
688       // we tranformed GrayLevel pixels + LUT into RGB Pixel
689       PixelElement->SetLength( ImageDataSize );
690    }
691  
692    HeaderInternal->Write(fp1, type);
693
694    // --------------------------------------------------------------
695    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
696    // 
697    // ...and we restore the Header to be Dicom Compliant again 
698    // just after writting
699
700    if ( HeaderInternal->GetFileType() == ACR_LIBIDO )
701    {
702       HeaderInternal->SetEntryByNumber(rows   , 0x0028, 0x0010);
703       HeaderInternal->SetEntryByNumber(columns, 0x0028, 0x0011);
704    }
705    // ----------------- End of Special Patch ----------------
706    fp1->close ();
707    delete fp1;
708
709    return true;
710 }
711
712 /**
713  * \brief Access to the underlying \ref PixelConverter RGBA LUT
714  */
715 uint8_t* File::GetLutRGBA()
716 {
717    return PixelConverter->GetLutRGBA();
718 }
719
720 //-----------------------------------------------------------------------------
721 // Private
722 void File::SetPixelData(uint8_t* data)
723 {
724    GetHeader()->SetEntryByNumber( GDCM_BINLOADED,
725       GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
726
727    // Will be 7fe0, 0010 in standard case
728    DocEntry* currentEntry = GetHeader()->GetDocEntryByNumber(GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel());
729    if ( currentEntry )
730    {
731       if ( BinEntry* binEntry = dynamic_cast<BinEntry *>(currentEntry) )
732          // Flag is to false because datas are kept in the gdcmPixelConvert
733          binEntry->SetBinArea( data, false );
734    }
735 }
736
737 //-----------------------------------------------------------------------------
738 } // end namespace gdcm
739