]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* src/gdcmPixelWriteConvert.[h|cxx] : new class to write datas (and in the
[gdcm.git] / src / gdcmFile.cxx
1   /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/12/03 11:55:38 $
7   Version:   $Revision: 1.169 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmFile.h"
20 #include "gdcmDocument.h"
21 #include "gdcmDebug.h"
22 #include "gdcmUtil.h"
23 #include "gdcmBinEntry.h"
24 #include <fstream>
25
26 namespace gdcm 
27 {
28 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
29
30 //-------------------------------------------------------------------------
31 // Constructor / Destructor
32 /**
33  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
34  *        file (Header only deals with the ... header)
35  *        Opens (in read only and when possible) an existing file and checks
36  *        for DICOM compliance. Returns NULL on failure.
37  *        It will be up to the user to load the pixels into memory
38  *        (see GetImageData, GetImageDataRaw)
39  * \note  the in-memory representation of all available tags found in
40  *        the DICOM header is post-poned to first header information access.
41  *        This avoid a double parsing of public part of the header when
42  *        user sets an a posteriori shadow dictionary (efficiency can be
43  *        seen as a side effect).   
44  * @param header already built Header
45  */
46 File::File(Header *header)
47 {
48    HeaderInternal = header;
49    SelfHeader = false;
50    Initialise();
51 }
52
53 /**
54  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
55  *        file (Header only deals with the ... header)
56  *        Opens (in read only and when possible) an existing file and checks
57  *        for DICOM compliance. Returns NULL on failure.
58  *        It will be up to the user to load the pixels into memory
59  *        (see GetImageData, GetImageDataRaw)
60  * \note  the in-memory representation of all available tags found in
61  *        the DICOM header is post-poned to first header information access.
62  *        This avoid a double parsing of public part of the header when
63  *        one sets an a posteriori shadow dictionary (efficiency can be
64  *        seen as a side effect).   
65  * @param filename file to be opened for parsing
66  */
67 File::File(std::string const & filename )
68 {
69    HeaderInternal = new Header( filename );
70    SelfHeader = true;
71    Initialise();
72 }
73
74 /**
75  * \brief Factorization for various forms of constructors.
76  */
77 void File::Initialise()
78 {
79    WriteMode = WMODE_DECOMPRESSED;
80    WriteType = WTYPE_IMPL_VR;
81
82    PixelReadConverter = new PixelReadConvert;
83    PixelWriteConverter = new PixelWriteConvert;
84    Archive = new DocEntryArchive( HeaderInternal );
85
86    if ( HeaderInternal->IsReadable() )
87    {
88       PixelReadConverter->GrabInformationsFromHeader( HeaderInternal );
89    }
90 }
91
92 /**
93  * \brief canonical destructor
94  * \note  If the Header was created by the File constructor,
95  *        it is destroyed by the File
96  */
97 File::~File()
98
99    if( PixelReadConverter )
100    {
101       delete PixelReadConverter;
102    }
103    if( PixelWriteConverter )
104    {
105       delete PixelWriteConverter;
106    }
107    if( Archive )
108    {
109       delete Archive;
110    }
111
112    if( SelfHeader )
113    {
114       delete HeaderInternal;
115    }
116    HeaderInternal = 0;
117 }
118
119 //-----------------------------------------------------------------------------
120 // Print
121
122 //-----------------------------------------------------------------------------
123 // Public
124 /**
125  * \brief   Get the size of the image data
126  * 
127  *          If the image can be RGB (with a lut or by default), the size 
128  *          corresponds to the RGB image
129  * @return  The image size
130  */
131 size_t File::GetImageDataSize()
132 {
133    return PixelReadConverter->GetRGBSize();
134 }
135
136 /**
137  * \brief   Get the size of the image data
138  * 
139  *          If the image can be RGB by transformation in a LUT, this
140  *          transformation isn't considered
141  * @return  The raw image size
142  */
143 size_t File::GetImageDataRawSize()
144 {
145    return PixelReadConverter->GetDecompressedSize();
146 }
147
148 /**
149  * \brief   - Allocates necessary memory, 
150  *          - Reads the pixels from disk (uncompress if necessary),
151  *          - Transforms YBR pixels, if any, into RGB pixels
152  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
153  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
154  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
155  * @return  Pointer to newly allocated pixel data.
156  *          NULL if alloc fails 
157  */
158 uint8_t* File::GetImageData()
159 {
160    if ( ! GetDecompressed() )
161    {
162       // If the decompression failed nothing can be done.
163       return 0;
164    }
165
166    if ( HeaderInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
167    {
168       return PixelReadConverter->GetRGB();
169    }
170    else
171    {
172       // When no LUT or LUT conversion fails, return the decompressed
173       return PixelReadConverter->GetDecompressed();
174    }
175 }
176
177 /**
178  * \brief
179  *          Read the pixels from disk (uncompress if necessary),
180  *          Transforms YBR pixels, if any, into RGB pixels
181  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
182  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
183  *          Copies at most MaxSize bytes of pixel data to caller allocated
184  *          memory space.
185  * \warning This function allows people that want to build a volume
186  *          from an image stack *not to* have, first to get the image pixels, 
187  *          and then move them to the volume area.
188  *          It's absolutely useless for any VTK user since vtk chooses 
189  *          to invert the lines of an image, that is the last line comes first
190  *          (for some axis related reasons?). Hence he will have 
191  *          to load the image line by line, starting from the end.
192  *          VTK users have to call GetImageData
193  *     
194  * @param   destination Address (in caller's memory space) at which the
195  *          pixel data should be copied
196  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
197  *          is not sufficient to hold the pixel data the copy is not
198  *          executed (i.e. no partial copy).
199  * @return  On success, the number of bytes actually copied. Zero on
200  *          failure e.g. MaxSize is lower than necessary.
201  */
202 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
203 {
204    if ( ! GetDecompressed() )
205    {
206       // If the decompression failed nothing can be done.
207       return 0;
208    }
209
210    if ( HeaderInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
211    {
212       if ( PixelReadConverter->GetRGBSize() > maxSize )
213       {
214          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
215                         "than caller's expected MaxSize");
216          return 0;
217       }
218       memcpy( destination,
219               (void*)PixelReadConverter->GetRGB(),
220               PixelReadConverter->GetRGBSize() );
221       return PixelReadConverter->GetRGBSize();
222    }
223
224    // Either no LUT conversion necessary or LUT conversion failed
225    if ( PixelReadConverter->GetDecompressedSize() > maxSize )
226    {
227       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
228                      "than caller's expected MaxSize");
229       return 0;
230    }
231    memcpy( destination,
232            (void*)PixelReadConverter->GetDecompressed(),
233            PixelReadConverter->GetDecompressedSize() );
234    return PixelReadConverter->GetDecompressedSize();
235 }
236
237 /**
238  * \brief   Allocates necessary memory, 
239  *          Transforms YBR pixels (if any) into RGB pixels
240  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
241  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
242  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
243  * @return  Pointer to newly allocated pixel data.
244  * \        NULL if alloc fails 
245  */
246 uint8_t* File::GetImageDataRaw ()
247 {
248    return GetDecompressed();
249 }
250
251 uint8_t* File::GetDecompressed()
252 {
253    uint8_t* decompressed = PixelReadConverter->GetDecompressed();
254    if ( ! decompressed )
255    {
256       // The decompressed image migth not be loaded yet:
257       std::ifstream* fp = HeaderInternal->OpenFile();
258       PixelReadConverter->ReadAndDecompressPixelData( fp );
259       if(fp) 
260          HeaderInternal->CloseFile();
261
262       decompressed = PixelReadConverter->GetDecompressed();
263       if ( ! decompressed )
264       {
265          dbg.Verbose(0, "File::GetDecompressed: read/decompress of "
266                         "pixel data apparently went wrong.");
267          return 0;
268       }
269    }
270
271    return decompressed;
272 }
273
274 /**
275  * \brief   Points the internal pointer to the callers inData
276  *          image representation, BUT WITHOUT COPYING THE DATA.
277  *          'image' Pixels are presented as C-like 2D arrays : line per line.
278  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
279  * \warning Since the pixels are not copied, it is the caller's responsability
280  *          not to deallocate it's data before gdcm uses them (e.g. with
281  *          the Write() method.
282  * @param inData user supplied pixel area
283  * @param expectedSize total image size, in Bytes
284  *
285  * @return boolean
286  */
287 bool File::SetImageData(uint8_t* inData, size_t expectedSize)
288 {
289    PixelWriteConverter->SetUserData(inData,expectedSize);
290
291    return true;
292 }
293
294 /**
295  * \brief Writes on disk A SINGLE Dicom file
296  *        NO test is performed on  processor "Endiannity".
297  *        It's up to the user to call his Reader properly
298  * @param fileName name of the file to be created
299  *                 (any already existing file is over written)
300  * @return false if write fails
301  */
302
303 bool File::WriteRawData(std::string const & fileName)
304 {
305   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
306    if (!fp1)
307    {
308       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
309       return false;
310    }
311
312    if(PixelWriteConverter->GetUserData())
313       fp1.write((char*)PixelWriteConverter->GetUserData(), PixelWriteConverter->GetUserDataSize());
314    else if(PixelReadConverter->GetRGB())
315       fp1.write((char*)PixelReadConverter->GetRGB(), PixelReadConverter->GetRGBSize());
316    else if(PixelReadConverter->GetDecompressed())
317       fp1.write((char*)PixelReadConverter->GetDecompressed(), PixelReadConverter->GetDecompressedSize());
318
319    fp1.close();
320
321    return true;
322 }
323
324 /**
325  * \brief Writes on disk A SINGLE Dicom file, 
326  *        using the Implicit Value Representation convention
327  *        NO test is performed on  processor "Endiannity".
328  * @param fileName name of the file to be created
329  *                 (any already existing file is overwritten)
330  * @return false if write fails
331  */
332
333 bool File::WriteDcmImplVR (std::string const & fileName)
334 {
335    SetWriteTypeToDcmImplVR();
336    return Write(fileName);
337 }
338
339 /**
340 * \brief Writes on disk A SINGLE Dicom file, 
341  *        using the Explicit Value Representation convention
342  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
343  *                 (any already existing file is overwritten)
344  * @return false if write fails
345  */
346
347 bool File::WriteDcmExplVR (std::string const & fileName)
348 {
349    SetWriteTypeToDcmExplVR();
350    return Write(fileName);
351 }
352
353 /**
354  * \brief Writes on disk A SINGLE Dicom file, 
355  *        using the ACR-NEMA convention
356  *        NO test is performed on  processor "Endiannity".
357  *        (a l'attention des logiciels cliniques 
358  *        qui ne prennent en entrée QUE des images ACR ...
359  * \warning if a DICOM_V3 header is supplied,
360  *         groups < 0x0008 and shadow groups are ignored
361  * \warning NO TEST is performed on processor "Endiannity".
362  * @param fileName name of the file to be created
363  *                 (any already existing file is overwritten)
364  * @return false if write fails
365  */
366
367 bool File::WriteAcr (std::string const & fileName)
368 {
369    SetWriteTypeToAcr();
370    return Write(fileName);
371 }
372
373 bool File::Write(std::string const& fileName)
374 {
375    switch(WriteType)
376    {
377       case WTYPE_IMPL_VR:
378          return WriteBase(fileName,ImplicitVR);
379       case WTYPE_EXPL_VR:
380          return WriteBase(fileName,ExplicitVR);
381       case WTYPE_ACR:
382          return WriteBase(fileName,ACR);
383    }
384    return(false);
385 }
386
387 /**
388  * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
389  */
390 uint8_t* File::GetLutRGBA()
391 {
392    return PixelReadConverter->GetLutRGBA();
393 }
394
395 //-----------------------------------------------------------------------------
396 // Protected
397 /**
398  * \brief NOT a end user inteded function
399  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
400  * @param fileName name of the file to be created
401  *                 (any already existing file is overwritten)
402  * @param  type file type (ExplicitVR, ImplicitVR, ...)
403  * @return false if write fails
404  */
405 bool File::WriteBase (std::string const & fileName, FileType type)
406 {
407    switch(type)
408    {
409       case ImplicitVR:
410          SetWriteFileTypeToImplicitVR();
411          break;
412       case ExplicitVR:
413          SetWriteFileTypeToExplicitVR();
414          break;
415       case ACR:
416       case ACR_LIBIDO:
417          SetWriteFileTypeToACR();
418          break;
419       default:
420          SetWriteFileTypeToExplicitVR();
421    }
422
423    // --------------------------------------------------------------
424    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
425    //
426    // if recognition code tells us we dealt with a LibIDO image
427    // we reproduce on disk the switch between lineNumber and columnNumber
428    // just before writting ...
429    /// \todo the best trick would be *change* the recognition code
430    ///       but pb expected if user deals with, e.g. COMPLEX images
431    if( type == ACR_LIBIDO )
432    {
433       SetWriteToLibido();
434    }
435    else
436    {
437       SetWriteToNoLibido();
438    }
439    // ----------------- End of Special Patch ----------------
440   
441    switch(WriteMode)
442    {
443       case WMODE_DECOMPRESSED :
444          SetWriteToDecompressed();
445          break;
446       case WMODE_RGB :
447          SetWriteToRGB();
448          break;
449    }
450
451    bool check = CheckWriteIntegrity();
452    if(check)
453    {
454       check = HeaderInternal->Write(fileName,type);
455    }
456
457    RestoreWrite();
458    RestoreWriteFileType();
459
460    // --------------------------------------------------------------
461    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
462    // 
463    // ...and we restore the Header to be Dicom Compliant again 
464    // just after writting
465    RestoreWriteOfLibido();
466    // ----------------- End of Special Patch ----------------
467
468    return check;
469 }
470
471 /**
472  * \brief Check the write integrity
473  *
474  * The tests made are :
475  *  - verify the size of the image to write with the possible write
476  *    when the user set an image data
477  * @return true if the check successfulls
478  */
479 bool File::CheckWriteIntegrity()
480 {
481    if(PixelWriteConverter->GetUserData())
482    {
483       int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
484       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
485       {
486          numberBitsAllocated = 16;
487       }
488
489       size_t decSize = HeaderInternal->GetXSize()
490                     * HeaderInternal->GetYSize() 
491                     * HeaderInternal->GetZSize()
492                     * ( numberBitsAllocated / 8 )
493                     * HeaderInternal->GetSamplesPerPixel();
494       size_t rgbSize = decSize;
495       if( HeaderInternal->HasLUT() )
496          rgbSize = decSize * 3;
497
498       switch(WriteMode)
499       {
500          case WMODE_DECOMPRESSED :
501             if( decSize!=PixelWriteConverter->GetUserDataSize() )
502             {
503                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
504                return false;
505             }
506             break;
507          case WMODE_RGB :
508             if( rgbSize!=PixelWriteConverter->GetUserDataSize() )
509             {
510                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
511                return false;
512             }
513             break;
514       }
515    }
516    
517    return true;
518 }
519
520 void File::SetWriteToDecompressed()
521 {
522    if(HeaderInternal->GetNumberOfScalarComponents()==3 && !HeaderInternal->HasLUT())
523    {
524       SetWriteToRGB();
525    } 
526    else
527    {
528       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
529       if(HeaderInternal->HasLUT())
530       {
531          photInt->SetValue("PALETTE COLOR ");
532          photInt->SetLength(14);
533       }
534       else
535       {
536          photInt->SetValue("MONOCHROME1 ");
537          photInt->SetLength(12);
538       }
539
540       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
541       pixel->SetValue(GDCM_BINLOADED);
542       if(PixelWriteConverter->GetUserData())
543       {
544          pixel->SetBinArea(PixelWriteConverter->GetUserData(),false);
545          pixel->SetLength(PixelWriteConverter->GetUserDataSize());
546       }
547       else
548       {
549          pixel->SetBinArea(PixelReadConverter->GetDecompressed(),false);
550          pixel->SetLength(PixelReadConverter->GetDecompressedSize());
551       }
552
553       Archive->Push(photInt);
554       Archive->Push(pixel);
555    }
556 }
557
558 void File::SetWriteToRGB()
559 {
560    if(HeaderInternal->GetNumberOfScalarComponents()==3)
561    {
562       PixelReadConverter->BuildRGBImage();
563       
564       ValEntry* spp = CopyValEntry(0x0028,0x0002);
565       spp->SetValue("3 ");
566       spp->SetLength(2);
567
568       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
569       planConfig->SetValue("0 ");
570       planConfig->SetLength(2);
571
572       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
573       photInt->SetValue("RGB ");
574       photInt->SetLength(4);
575
576       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
577       pixel->SetValue(GDCM_BINLOADED);
578       if(PixelWriteConverter->GetUserData())
579       {
580          pixel->SetBinArea(PixelWriteConverter->GetUserData(),false);
581          pixel->SetLength(PixelWriteConverter->GetUserDataSize());
582       }
583       else if(PixelReadConverter->GetRGB())
584       {
585          pixel->SetBinArea(PixelReadConverter->GetRGB(),false);
586          pixel->SetLength(PixelReadConverter->GetRGBSize());
587       }
588       else // Decompressed data
589       {
590          pixel->SetBinArea(PixelReadConverter->GetDecompressed(),false);
591          pixel->SetLength(PixelReadConverter->GetDecompressedSize());
592       }
593
594       Archive->Push(spp);
595       Archive->Push(planConfig);
596       Archive->Push(photInt);
597       Archive->Push(pixel);
598
599       // Remove any LUT
600       Archive->Push(0x0028,0x1101);
601       Archive->Push(0x0028,0x1102);
602       Archive->Push(0x0028,0x1103);
603       Archive->Push(0x0028,0x1201);
604       Archive->Push(0x0028,0x1202);
605       Archive->Push(0x0028,0x1203);
606
607       // For old ACR-NEMA
608       // Thus, we have a RGB image and the bits allocated = 24 and 
609       // samples per pixels = 1 (in the read file)
610       if(HeaderInternal->GetBitsAllocated()==24) 
611       {
612          ValEntry* bitsAlloc = CopyValEntry(0x0028,0x0100);
613          bitsAlloc->SetValue("8 ");
614          bitsAlloc->SetLength(2);
615
616          ValEntry* bitsStored = CopyValEntry(0x0028,0x0101);
617          bitsStored->SetValue("8 ");
618          bitsStored->SetLength(2);
619
620          ValEntry* highBit = CopyValEntry(0x0028,0x0102);
621          highBit->SetValue("7 ");
622          highBit->SetLength(2);
623
624          Archive->Push(bitsAlloc);
625          Archive->Push(bitsStored);
626          Archive->Push(highBit);
627       }
628    }
629    else
630    {
631       SetWriteToDecompressed();
632    }
633 }
634
635 void File::RestoreWrite()
636 {
637    Archive->Restore(0x0028,0x0002);
638    Archive->Restore(0x0028,0x0004);
639    Archive->Restore(0x0028,0x0006);
640    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
641
642    // For old ACR-NEMA (24 bits problem)
643    Archive->Restore(0x0028,0x0100);
644    Archive->Restore(0x0028,0x0101);
645    Archive->Restore(0x0028,0x0102);
646
647    // For the LUT
648    Archive->Restore(0x0028,0x1101);
649    Archive->Restore(0x0028,0x1102);
650    Archive->Restore(0x0028,0x1103);
651    Archive->Restore(0x0028,0x1201);
652    Archive->Restore(0x0028,0x1202);
653    Archive->Restore(0x0028,0x1203);
654 }
655
656 void File::SetWriteFileTypeToACR()
657 {
658    Archive->Push(0x0002,0x0010);
659 }
660
661 void File::SetWriteFileTypeToExplicitVR()
662 {
663    std::string ts = Util::DicomString( 
664       Document::GetTransferSyntaxValue(ExplicitVRLittleEndian).c_str() );
665
666    ValEntry* tss = CopyValEntry(0x0002,0x0010);
667    tss->SetValue(ts);
668    tss->SetLength(ts.length());
669
670    Archive->Push(tss);
671 }
672
673 void File::SetWriteFileTypeToImplicitVR()
674 {
675    std::string ts = Util::DicomString(
676       Document::GetTransferSyntaxValue(ImplicitVRLittleEndian).c_str() );
677
678    ValEntry* tss = CopyValEntry(0x0002,0x0010);
679    tss->SetValue(ts);
680    tss->SetLength(ts.length());
681 }
682
683 void File::RestoreWriteFileType()
684 {
685    Archive->Restore(0x0002,0x0010);
686 }
687
688 void File::SetWriteToLibido()
689 {
690    ValEntry *oldRow = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
691    ValEntry *oldCol = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
692    
693    if( oldRow && oldCol )
694    {
695       std::string rows, columns; 
696
697       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
698       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
699
700       newRow->Copy(oldCol);
701       newCol->Copy(oldRow);
702
703       newRow->SetValue(oldCol->GetValue());
704       newCol->SetValue(oldRow->GetValue());
705
706       Archive->Push(newRow);
707       Archive->Push(newCol);
708    }
709
710    ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
711    libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
712    libidoCode->SetLength(10);
713    Archive->Push(libidoCode);
714 }
715
716 void File::SetWriteToNoLibido()
717 {
718    ValEntry *recCode = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0008,0x0010));
719    if( recCode )
720    {
721       if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
722       {
723          ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
724          libidoCode->SetValue("");
725          libidoCode->SetLength(0);
726          Archive->Push(libidoCode);
727       }
728    }
729 }
730
731 void File::RestoreWriteOfLibido()
732 {
733    Archive->Restore(0x0028,0x0010);
734    Archive->Restore(0x0028,0x0011);
735    Archive->Restore(0x0008,0x0010);
736 }
737
738 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
739 {
740    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
741    ValEntry* newE;
742
743    if(oldE)
744    {
745       newE = new ValEntry(oldE->GetDictEntry());
746       newE->Copy(oldE);
747    }
748    else
749    {
750       newE = GetHeader()->NewValEntryByNumber(group,element);
751    }
752
753    return(newE);
754 }
755
756 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
757 {
758    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
759    BinEntry* newE;
760
761    if(oldE)
762    {
763       newE = new BinEntry(oldE->GetDictEntry());
764       newE->Copy(oldE);
765    }
766    else
767    {
768       newE = GetHeader()->NewBinEntryByNumber(group,element);
769    }
770
771    return(newE);
772 }
773
774 //-----------------------------------------------------------------------------
775 // Private
776
777 //-----------------------------------------------------------------------------
778 } // end namespace gdcm
779