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