1 /*=========================================================================
4 Module: $RCSfile: gdcmFileHelper.cxx,v $
7 Date: $Date: 2005/08/20 09:04:50 $
8 Version: $Revision: 1.53 $
10 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
11 l'Image). All rights reserved. See Doc/License.txt or
12 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
14 This software is distributed WITHOUT ANY WARRANTY; without even
15 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the above copyright notices for more information.
18 =========================================================================*/
20 #include "gdcmFileHelper.h"
21 #include "gdcmGlobal.h"
23 #include "gdcmDocument.h"
24 #include "gdcmDebug.h"
26 #include "gdcmBinEntry.h"
27 #include "gdcmValEntry.h"
28 #include "gdcmSeqEntry.h"
29 #include "gdcmSQItem.h"
30 #include "gdcmContentEntry.h"
32 #include "gdcmPixelReadConvert.h"
33 #include "gdcmPixelWriteConvert.h"
34 #include "gdcmDocEntryArchive.h"
35 #include "gdcmDictSet.h"
40 // ----------------------------- WARNING -------------------------
42 These lines will be moved to the document-to-be 'User's Guide'
44 // To read an image, user needs a gdcm::File
45 gdcm::File *f = new gdcm::File(fileName);
47 // user may also decide he doesn't want to load some parts of the header
48 gdcm::File *f = new gdcm::File();
49 f->SetFileName(fileName);
50 f->SetLoadMode(NO_SEQ); // or
51 f->SetLoadMode(NO_SHADOW); // or
52 f->SetLoadMode(NO_SEQ | NO_SHADOW); // or
53 f->SetLoadMode(NO_SHADOWSEQ);
56 // user can now check some values
57 std::string v = f->GetEntryValue(groupNb,ElementNb);
59 // to get the pixels, user needs a gdcm::FileHelper
60 gdcm::FileHelper *fh = new gdcm::FileHelper(f);
61 // user may ask not to convert Palette to RGB
62 uint8_t *pixels = fh->GetImageDataRaw();
63 int imageLength = fh->GetImageDataRawSize();
64 // He can now use the pixels, create a new image, ...
65 uint8_t *userPixels = ...
67 To re-write the image, user re-uses the gdcm::FileHelper
69 fh->SetImageData( userPixels, userPixelsLength);
70 fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB
73 fh->SetWriteTypeToDcmExpl(); // he wants Explicit Value Representation
74 // Little Endian is the default
75 // no other value is allowed
76 (-->SetWriteType(ExplicitVR);)
77 -->WriteType = ExplicitVR;
78 fh->Write(newFileName); // overwrites the file, if any
81 fh->WriteDcmExplVR(newFileName);
84 // ----------------------------- WARNING -------------------------
86 These lines will be moved to the document-to-be 'Developer's Guide'
88 WriteMode : WMODE_RAW / WMODE_RGB
89 WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO
91 fh1->Write(newFileName);
92 SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR();
93 (modifies TransferSyntax)
94 SetWriteToRaw(); / SetWriteToRGB();
95 (modifies, when necessary : photochromatic interpretation,
96 samples per pixel, Planar configuration,
97 bits allocated, bits stored, high bit -ACR 24 bits-
98 Pixels element VR, pushes out the LUT )
99 CheckWriteIntegrity();
100 (checks user given pixels length)
101 FileInternal->Write(fileName,WriteType)
102 fp = opens file(fileName);
103 ComputeGroup0002Length(writetype);
105 RemoveEntryNoDestroy(palettes, etc)
106 Document::WriteContent(fp, writetype);
108 (moves back to the File all the archived elements)
109 RestoreWriteFileType();
110 (pushes back group 0002, with TransferSyntax)
118 //-------------------------------------------------------------------------
119 // Constructor / Destructor
121 * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
122 * file (gdcm::File only deals with the ... header)
123 * Opens (in read only and when possible) an existing file and checks
124 * for DICOM compliance. Returns NULL on failure.
125 * It will be up to the user to load the pixels into memory
126 * ( GetImageDataSize() + GetImageData() methods)
127 * \note the in-memory representation of all available tags found in
128 * the DICOM header is post-poned to first header information access.
129 * This avoid a double parsing of public part of the header when
130 * one sets an a posteriori shadow dictionary (efficiency can be
131 * seen as a side effect).
133 FileHelper::FileHelper( )
135 FileInternal = new File( );
141 * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
142 * file (File only deals with the ... header)
143 * Opens (in read only and when possible) an existing file and checks
144 * for DICOM compliance. Returns NULL on failure.
145 * It will be up to the user to load the pixels into memory
146 * ( GetImageDataSize() + GetImageData() methods)
147 * \note the in-memory representation of all available tags found in
148 * the DICOM header is post-poned to first header information access.
149 * This avoid a double parsing of public part of the header when
150 * user sets an a posteriori shadow dictionary (efficiency can be
151 * seen as a side effect).
152 * @param header already built Header
154 FileHelper::FileHelper(File *header)
156 FileInternal = header;
159 if ( FileInternal->IsReadable() )
161 PixelReadConverter->GrabInformationsFromFile( FileInternal );
165 #ifndef GDCM_LEGACY_REMOVE
167 * \brief DEPRECATED : use SetFilename() + SetLoadMode() + Load() methods
168 * Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
169 * file (gdcm::File only deals with the ... header)
170 * Opens (in read only and when possible) an existing file and checks
171 * for DICOM compliance. Returns NULL on failure.
172 * It will be up to the user to load the pixels into memory
173 * \note the in-memory representation of all available tags found in
174 * the DICOM header is post-poned to first header information access.
175 * This avoid a double parsing of public part of the header when
176 * one sets an a posteriori shadow dictionary (efficiency can be
177 * seen as a side effect).
178 * @param filename file to be opened for parsing
179 * @deprecated use SetFilename() + Load() methods
181 FileHelper::FileHelper(std::string const &filename )
183 FileInternal = new File( );
184 FileInternal->SetFileName( filename );
185 FileInternal->Load();
188 if ( FileInternal->IsReadable() )
190 PixelReadConverter->GrabInformationsFromFile( FileInternal );
196 * \brief canonical destructor
197 * \note If the header (gdcm::File) was created by the FileHelper constructor,
198 * it is destroyed by the FileHelper
200 FileHelper::~FileHelper()
202 if ( PixelReadConverter )
204 delete PixelReadConverter;
206 if ( PixelWriteConverter )
208 delete PixelWriteConverter;
222 //-----------------------------------------------------------------------------
226 * \brief Sets the LoadMode of the internal gdcm::File as a boolean string.
227 * NO_SEQ, NO_SHADOW, NO_SHADOWSEQ
228 *... (nothing more, right now)
229 * WARNING : before using NO_SHADOW, be sure *all* your files
230 * contain accurate values in the 0x0000 element (if any)
231 * of *each* Shadow Group. The parser will fail if the size is wrong !
232 * @param loadMode Load mode to be used
234 void FileHelper::SetLoadMode(int loadMode)
236 GetFile()->SetLoadMode( loadMode );
239 * \brief Sets the LoadMode of the internal gdcm::File
240 * @param fileName name of the file to be open
242 void FileHelper::SetFileName(std::string const &fileName)
244 FileInternal->SetFileName( fileName );
249 * @return false if file cannot be open or no swap info was found,
250 * or no tag was found.
252 bool FileHelper::Load()
254 if ( !FileInternal->Load() )
257 PixelReadConverter->GrabInformationsFromFile( FileInternal );
262 * \brief Accesses an existing DocEntry (i.e. a Dicom Element)
263 * through it's (group, element) and modifies it's content with
265 * @param content new value (string) to substitute with
266 * @param group group number of the Dicom Element to modify
267 * @param elem element number of the Dicom Element to modify
268 * \return false if DocEntry not found
270 bool FileHelper::SetValEntry(std::string const &content,
271 uint16_t group, uint16_t elem)
273 return FileInternal->SetValEntry(content, group, elem);
278 * \brief Accesses an existing DocEntry (i.e. a Dicom Element)
279 * through it's (group, element) and modifies it's content with
281 * @param content new value (void* -> uint8_t*) to substitute with
282 * @param lgth new value length
283 * @param group group number of the Dicom Element to modify
284 * @param elem element number of the Dicom Element to modify
285 * \return false if DocEntry not found
287 bool FileHelper::SetBinEntry(uint8_t *content, int lgth,
288 uint16_t group, uint16_t elem)
290 return FileInternal->SetBinEntry(content, lgth, group, elem);
294 * \brief Modifies the value of a given DocEntry (Dicom entry)
295 * when it exists. Creates it with the given value when unexistant.
296 * @param content (string)value to be set
297 * @param group Group number of the Entry
298 * @param elem Element number of the Entry
299 * \return pointer to the modified/created Dicom entry (NULL when creation
302 ValEntry *FileHelper::InsertValEntry(std::string const &content,
303 uint16_t group, uint16_t elem)
305 return FileInternal->InsertValEntry(content, group, elem);
309 * \brief Modifies the value of a given DocEntry (Dicom entry)
310 * when it exists. Creates it with the given value when unexistant.
311 * A copy of the binArea is made to be kept in the Document.
312 * @param binArea (binary)value to be set
313 * @param lgth new value length
314 * @param group Group number of the Entry
315 * @param elem Element number of the Entry
316 * \return pointer to the modified/created Dicom entry (NULL when creation
319 BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth,
320 uint16_t group, uint16_t elem)
322 return FileInternal->InsertBinEntry(binArea, lgth, group, elem);
326 * \brief Modifies the value of a given DocEntry (Dicom entry)
327 * when it exists. Creates it, empty (?!) when unexistant.
328 * @param group Group number of the Entry
329 * @param elem Element number of the Entry
330 * \return pointer to the modified/created Dicom entry (NULL when creation
333 SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
335 return FileInternal->InsertSeqEntry(group, elem);
339 * \brief Get the size of the image data
340 * If the image can be RGB (with a lut or by default), the size
341 * corresponds to the RGB image
342 * (use GetImageDataRawSize if you want to be sure to get *only*
343 * the size of the pixels)
344 * @return The image size
346 size_t FileHelper::GetImageDataSize()
348 if ( PixelWriteConverter->GetUserData() )
350 return PixelWriteConverter->GetUserDataSize();
352 return PixelReadConverter->GetRGBSize();
356 * \brief Get the size of the image data
357 * If the image could be converted to RGB using a LUT,
358 * this transformation is not taken into account by GetImageDataRawSize
359 * (use GetImageDataSize if you wish)
360 * @return The raw image size
362 size_t FileHelper::GetImageDataRawSize()
364 if ( PixelWriteConverter->GetUserData() )
366 return PixelWriteConverter->GetUserDataSize();
368 return PixelReadConverter->GetRawSize();
372 * \brief - Allocates necessary memory,
373 * - Reads the pixels from disk (uncompress if necessary),
374 * - Transforms YBR pixels, if any, into RGB pixels,
375 * - Transforms 3 planes R, G, B, if any, into a single RGB Plane
376 * - Transforms single Grey plane + 3 Palettes into a RGB Plane
377 * - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
378 * @return Pointer to newly allocated pixel data.
379 * NULL if alloc fails
381 uint8_t *FileHelper::GetImageData()
383 if ( PixelWriteConverter->GetUserData() )
385 return PixelWriteConverter->GetUserData();
390 // If the decompression failed nothing can be done.
394 if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
396 return PixelReadConverter->GetRGB();
400 // When no LUT or LUT conversion fails, return the Raw
401 return PixelReadConverter->GetRaw();
406 * \brief Allocates necessary memory,
407 * Transforms YBR pixels (if any) into RGB pixels
408 * Transforms 3 planes R, G, B (if any) into a single RGB Plane
409 * Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
410 * DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
411 * @return Pointer to newly allocated pixel data.
412 * NULL if alloc fails
414 uint8_t *FileHelper::GetImageDataRaw ()
419 #ifndef GDCM_LEGACY_REMOVE
421 * \brief Useless function, since PixelReadConverter forces us
422 * copy the Pixels anyway.
423 * Reads the pixels from disk (uncompress if necessary),
424 * Transforms YBR pixels, if any, into RGB pixels
425 * Transforms 3 planes R, G, B, if any, into a single RGB Plane
426 * Transforms single Grey plane + 3 Palettes into a RGB Plane
427 * Copies at most MaxSize bytes of pixel data to caller allocated
429 * \warning This function allows people that want to build a volume
430 * from an image stack *not to* have, first to get the image pixels,
431 * and then move them to the volume area.
432 * It's absolutely useless for any VTK user since vtk chooses
433 * to invert the lines of an image, that is the last line comes first
434 * (for some axis related reasons?). Hence he will have
435 * to load the image line by line, starting from the end.
436 * VTK users have to call GetImageData
438 * @param destination Address (in caller's memory space) at which the
439 * pixel data should be copied
440 * @param maxSize Maximum number of bytes to be copied. When MaxSize
441 * is not sufficient to hold the pixel data the copy is not
442 * executed (i.e. no partial copy).
443 * @return On success, the number of bytes actually copied. Zero on
444 * failure e.g. MaxSize is lower than necessary.
446 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
450 // If the decompression failed nothing can be done.
454 if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
456 if ( PixelReadConverter->GetRGBSize() > maxSize )
458 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
462 (void*)PixelReadConverter->GetRGB(),
463 PixelReadConverter->GetRGBSize() );
464 return PixelReadConverter->GetRGBSize();
467 // Either no LUT conversion necessary or LUT conversion failed
468 if ( PixelReadConverter->GetRawSize() > maxSize )
470 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
474 (void *)PixelReadConverter->GetRaw(),
475 PixelReadConverter->GetRawSize() );
476 return PixelReadConverter->GetRawSize();
481 * \brief Points the internal pointer to the callers inData
482 * image representation, BUT WITHOUT COPYING THE DATA.
483 * 'image' Pixels are presented as C-like 2D arrays : line per line.
484 * 'volume'Pixels are presented as C-like 3D arrays : plane per plane
485 * \warning Since the pixels are not copied, it is the caller's responsability
486 * not to deallocate its data before gdcm uses them (e.g. with
487 * the Write() method )
488 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
489 * user is allowed to pass any kind of pixelsn since the size is
491 * @param expectedSize total image size, *in Bytes*
493 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
495 SetUserData(inData, expectedSize);
499 * \brief Set the image data defined by the user
500 * \warning When writting the file, this data are get as default data to write
501 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
502 * user is allowed to pass any kind of pixels since the size is
504 * @param expectedSize total image size, *in Bytes*
506 void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
508 PixelWriteConverter->SetUserData(inData, expectedSize);
512 * \brief Get the image data defined by the user
513 * \warning When writting the file, this data are get as default data to write
515 uint8_t *FileHelper::GetUserData()
517 return PixelWriteConverter->GetUserData();
521 * \brief Get the image data size defined by the user
522 * \warning When writting the file, this data are get as default data to write
524 size_t FileHelper::GetUserDataSize()
526 return PixelWriteConverter->GetUserDataSize();
530 * \brief Get the image data from the file.
531 * If a LUT is found, the data are expanded to be RGB
533 uint8_t *FileHelper::GetRGBData()
535 return PixelReadConverter->GetRGB();
539 * \brief Get the image data size from the file.
540 * If a LUT is found, the data are expanded to be RGB
542 size_t FileHelper::GetRGBDataSize()
544 return PixelReadConverter->GetRGBSize();
548 * \brief Get the image data from the file.
549 * Even when a LUT is found, the data are not expanded to RGB!
551 uint8_t *FileHelper::GetRawData()
553 return PixelReadConverter->GetRaw();
557 * \brief Get the image data size from the file.
558 * Even when a LUT is found, the data are not expanded to RGB!
560 size_t FileHelper::GetRawDataSize()
562 return PixelReadConverter->GetRawSize();
566 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
568 uint8_t* FileHelper::GetLutRGBA()
570 if ( PixelReadConverter->GetLutRGBA() ==0 )
571 PixelReadConverter->BuildLUTRGBA();
572 return PixelReadConverter->GetLutRGBA();
576 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number
578 int FileHelper::GetLutItemNumber()
580 return PixelReadConverter->GetLutItemNumber();
584 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size
586 int FileHelper::GetLutItemSize()
588 return PixelReadConverter->GetLutItemSize();
592 * \brief Writes on disk A SINGLE Dicom file
593 * NO test is performed on processor "Endiannity".
594 * It's up to the user to call his Reader properly
595 * @param fileName name of the file to be created
596 * (any already existing file is over written)
597 * @return false if write fails
599 bool FileHelper::WriteRawData(std::string const &fileName)
601 std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
604 gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str());
608 if ( PixelWriteConverter->GetUserData() )
610 fp1.write( (char *)PixelWriteConverter->GetUserData(),
611 PixelWriteConverter->GetUserDataSize() );
613 else if ( PixelReadConverter->GetRGB() )
615 fp1.write( (char *)PixelReadConverter->GetRGB(),
616 PixelReadConverter->GetRGBSize());
618 else if ( PixelReadConverter->GetRaw() )
620 fp1.write( (char *)PixelReadConverter->GetRaw(),
621 PixelReadConverter->GetRawSize());
625 gdcmErrorMacro( "Nothing written." );
634 * \brief Writes on disk A SINGLE Dicom file,
635 * using the Implicit Value Representation convention
636 * NO test is performed on processor "Endianity".
637 * @param fileName name of the file to be created
638 * (any already existing file is overwritten)
639 * @return false if write fails
642 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
644 SetWriteTypeToDcmImplVR();
645 return Write(fileName);
649 * \brief Writes on disk A SINGLE Dicom file,
650 * using the Explicit Value Representation convention
651 * NO test is performed on processor "Endiannity".
652 * @param fileName name of the file to be created
653 * (any already existing file is overwritten)
654 * @return false if write fails
657 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
659 SetWriteTypeToDcmExplVR();
660 return Write(fileName);
664 * \brief Writes on disk A SINGLE Dicom file,
665 * using the ACR-NEMA convention
666 * NO test is performed on processor "Endiannity".
667 * (a l'attention des logiciels cliniques
668 * qui ne prennent en entrée QUE des images ACR ...
669 * \warning if a DICOM_V3 header is supplied,
670 * groups < 0x0008 and shadow groups are ignored
671 * \warning NO TEST is performed on processor "Endiannity".
672 * @param fileName name of the file to be created
673 * (any already existing file is overwritten)
674 * @return false if write fails
677 bool FileHelper::WriteAcr (std::string const &fileName)
680 return Write(fileName);
684 * \brief Writes on disk A SINGLE Dicom file,
685 * @param fileName name of the file to be created
686 * (any already existing file is overwritten)
687 * @return false if write fails
689 bool FileHelper::Write(std::string const &fileName)
694 SetWriteFileTypeToImplicitVR();
696 case Unknown: // should never happen; ExplicitVR is the default value
698 SetWriteFileTypeToExplicitVR();
702 // NOTHING is done here just for LibIDO.
703 // Just to avoid further trouble if user creates a file ex-nihilo,
704 // wants to write it as an ACR-NEMA file,
705 // and forgets to create any Entry belonging to group 0008
707 // We add Recognition Code (RET)
708 if ( ! FileInternal->GetValEntry(0x0008, 0x0010) )
709 FileInternal->InsertValEntry("", 0x0008, 0x0010);
710 SetWriteFileTypeToACR();
711 // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR !
714 CheckMandatoryElements();
716 // --------------------------------------------------------------
717 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
719 // if recognition code tells us we dealt with a LibIDO image
720 // we reproduce on disk the switch between lineNumber and columnNumber
721 // just before writting ...
722 /// \todo the best trick would be *change* the recognition code
723 /// but pb expected if user deals with, e.g. COMPLEX images
725 if ( WriteType == ACR_LIBIDO )
731 SetWriteToNoLibido();
733 // ----------------- End of Special Patch ----------------
738 SetWriteToRaw(); // modifies and pushes to the archive, when necessary
741 SetWriteToRGB(); // modifies and pushes to the archive, when necessary
745 bool check = CheckWriteIntegrity(); // verifies length
748 check = FileInternal->Write(fileName,WriteType);
752 RestoreWriteFileType();
753 RestoreWriteMandatory();
755 // --------------------------------------------------------------
756 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
758 // ...and we restore the header to be Dicom Compliant again
759 // just after writting
760 RestoreWriteOfLibido();
761 // ----------------- End of Special Patch ----------------
766 //-----------------------------------------------------------------------------
769 * \brief Checks the write integrity
771 * The tests made are :
772 * - verify the size of the image to write with the possible write
773 * when the user set an image data
774 * @return true if check is successfull
776 bool FileHelper::CheckWriteIntegrity()
778 if ( PixelWriteConverter->GetUserData() )
780 int numberBitsAllocated = FileInternal->GetBitsAllocated();
781 if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
783 gdcmWarningMacro( "numberBitsAllocated changed from "
784 << numberBitsAllocated << " to 16 "
785 << " for consistency purpose" );
786 numberBitsAllocated = 16;
789 size_t decSize = FileInternal->GetXSize()
790 * FileInternal->GetYSize()
791 * FileInternal->GetZSize()
792 * FileInternal->GetSamplesPerPixel()
793 * ( numberBitsAllocated / 8 );
794 size_t rgbSize = decSize;
795 if ( FileInternal->HasLUT() )
796 rgbSize = decSize * 3;
801 if ( decSize!=PixelWriteConverter->GetUserDataSize() )
803 gdcmWarningMacro( "Data size (Raw) is incorrect. Should be "
804 << decSize << " / Found :"
805 << PixelWriteConverter->GetUserDataSize() );
810 if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
812 gdcmWarningMacro( "Data size (RGB) is incorrect. Should be "
813 << decSize << " / Found "
814 << PixelWriteConverter->GetUserDataSize() );
824 * \brief Updates the File to write RAW data (as opposed to RGB data)
825 * (modifies, when necessary, photochromatic interpretation,
826 * bits allocated, Pixels element VR)
828 void FileHelper::SetWriteToRaw()
830 if ( FileInternal->GetNumberOfScalarComponents() == 3
831 && !FileInternal->HasLUT() )
837 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
838 if (FileInternal->HasLUT() )
840 photInt->SetValue("PALETTE COLOR ");
844 photInt->SetValue("MONOCHROME2 ");
847 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
848 PixelReadConverter->GetRawSize());
850 std::string vr = "OB";
851 if ( FileInternal->GetBitsAllocated()>8 )
853 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
856 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
857 pixel->SetValue(GDCM_BINLOADED);
858 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
859 pixel->SetLength(PixelWriteConverter->GetDataSize());
861 Archive->Push(photInt);
862 Archive->Push(pixel);
867 * \brief Updates the File to write RGB data (as opposed to RAW data)
868 * (modifies, when necessary, photochromatic interpretation,
869 * samples per pixel, Planar configuration,
870 * bits allocated, bits stored, high bit -ACR 24 bits-
871 * Pixels element VR, pushes out the LUT, )
873 void FileHelper::SetWriteToRGB()
875 if ( FileInternal->GetNumberOfScalarComponents()==3 )
877 PixelReadConverter->BuildRGBImage();
879 ValEntry *spp = CopyValEntry(0x0028,0x0002);
882 ValEntry *planConfig = CopyValEntry(0x0028,0x0006);
883 planConfig->SetValue("0 ");
885 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
886 photInt->SetValue("RGB ");
888 if ( PixelReadConverter->GetRGB() )
890 PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
891 PixelReadConverter->GetRGBSize());
895 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
896 PixelReadConverter->GetRawSize());
899 std::string vr = "OB";
900 if ( FileInternal->GetBitsAllocated()>8 )
902 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
905 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
906 pixel->SetValue(GDCM_BINLOADED);
907 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
908 pixel->SetLength(PixelWriteConverter->GetDataSize());
911 Archive->Push(planConfig);
912 Archive->Push(photInt);
913 Archive->Push(pixel);
916 Archive->Push(0x0028,0x1101);
917 Archive->Push(0x0028,0x1102);
918 Archive->Push(0x0028,0x1103);
919 Archive->Push(0x0028,0x1201);
920 Archive->Push(0x0028,0x1202);
921 Archive->Push(0x0028,0x1203);
923 // push out Palette Color Lookup Table UID, if any
924 Archive->Push(0x0028,0x1199);
926 // For old '24 Bits' ACR-NEMA
927 // Thus, we have a RGB image and the bits allocated = 24 and
928 // samples per pixels = 1 (in the read file)
929 if ( FileInternal->GetBitsAllocated()==24 )
931 ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100);
932 bitsAlloc->SetValue("8 ");
934 ValEntry *bitsStored = CopyValEntry(0x0028,0x0101);
935 bitsStored->SetValue("8 ");
937 ValEntry *highBit = CopyValEntry(0x0028,0x0102);
938 highBit->SetValue("7 ");
940 Archive->Push(bitsAlloc);
941 Archive->Push(bitsStored);
942 Archive->Push(highBit);
952 * \brief Restore the File write mode
954 void FileHelper::RestoreWrite()
956 Archive->Restore(0x0028,0x0002);
957 Archive->Restore(0x0028,0x0004);
958 Archive->Restore(0x0028,0x0006);
959 Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
961 // For old ACR-NEMA (24 bits problem)
962 Archive->Restore(0x0028,0x0100);
963 Archive->Restore(0x0028,0x0101);
964 Archive->Restore(0x0028,0x0102);
967 Archive->Restore(0x0028,0x1101);
968 Archive->Restore(0x0028,0x1102);
969 Archive->Restore(0x0028,0x1103);
970 Archive->Restore(0x0028,0x1201);
971 Archive->Restore(0x0028,0x1202);
972 Archive->Restore(0x0028,0x1203);
974 // For the Palette Color Lookup Table UID
975 Archive->Restore(0x0028,0x1203);
978 // group 0002 may be pushed out for ACR-NEMA writting purposes
979 Archive->Restore(0x0002,0x0000);
980 Archive->Restore(0x0002,0x0001);
981 Archive->Restore(0x0002,0x0002);
982 Archive->Restore(0x0002,0x0003);
983 Archive->Restore(0x0002,0x0010);
984 Archive->Restore(0x0002,0x0012);
985 Archive->Restore(0x0002,0x0013);
986 Archive->Restore(0x0002,0x0016);
987 Archive->Restore(0x0002,0x0100);
988 Archive->Restore(0x0002,0x0102);
992 * \brief Pushes out the whole group 0002
993 * FIXME : better, set a flag to tell the writer not to write it ...
994 * FIXME : method should probably have an other name !
995 * SetWriteFileTypeToACR is NOT opposed to
996 * SetWriteFileTypeToExplicitVR and SetWriteFileTypeToImplicitVR
998 void FileHelper::SetWriteFileTypeToACR()
1000 Archive->Push(0x0002,0x0000);
1001 Archive->Push(0x0002,0x0001);
1002 Archive->Push(0x0002,0x0002);
1003 Archive->Push(0x0002,0x0003);
1004 Archive->Push(0x0002,0x0010);
1005 Archive->Push(0x0002,0x0012);
1006 Archive->Push(0x0002,0x0013);
1007 Archive->Push(0x0002,0x0016);
1008 Archive->Push(0x0002,0x0100);
1009 Archive->Push(0x0002,0x0102);
1013 * \brief Sets in the File the TransferSyntax to 'Explicit VR Little Endian"
1015 void FileHelper::SetWriteFileTypeToExplicitVR()
1017 std::string ts = Util::DicomString(
1018 Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
1020 ValEntry *tss = CopyValEntry(0x0002,0x0010);
1027 * \brief Sets in the File the TransferSyntax to 'Implicit VR Little Endian"
1029 void FileHelper::SetWriteFileTypeToImplicitVR()
1031 std::string ts = Util::DicomString(
1032 Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
1034 ValEntry *tss = CopyValEntry(0x0002,0x0010);
1042 * \brief Restore in the File the initial group 0002
1044 void FileHelper::RestoreWriteFileType()
1049 * \brief Set the Write not to Libido format
1051 void FileHelper::SetWriteToLibido()
1053 ValEntry *oldRow = dynamic_cast<ValEntry *>
1054 (FileInternal->GetDocEntry(0x0028, 0x0010));
1055 ValEntry *oldCol = dynamic_cast<ValEntry *>
1056 (FileInternal->GetDocEntry(0x0028, 0x0011));
1058 if ( oldRow && oldCol )
1060 std::string rows, columns;
1062 ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
1063 ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
1065 newRow->Copy(oldCol);
1066 newCol->Copy(oldRow);
1068 newRow->SetValue(oldCol->GetValue());
1069 newCol->SetValue(oldRow->GetValue());
1071 Archive->Push(newRow);
1072 Archive->Push(newCol);
1075 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1076 libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
1077 Archive->Push(libidoCode);
1081 * \brief Set the Write not to No Libido format
1083 void FileHelper::SetWriteToNoLibido()
1085 ValEntry *recCode = dynamic_cast<ValEntry *>
1086 (FileInternal->GetDocEntry(0x0008,0x0010));
1089 if ( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
1091 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1092 libidoCode->SetValue("");
1093 Archive->Push(libidoCode);
1099 * \brief Restore the Write format
1101 void FileHelper::RestoreWriteOfLibido()
1103 Archive->Restore(0x0028,0x0010);
1104 Archive->Restore(0x0028,0x0011);
1105 Archive->Restore(0x0008,0x0010);
1107 // Restore 'LibIDO-special' entries, if any
1108 Archive->Restore(0x0028,0x0015);
1109 Archive->Restore(0x0028,0x0016);
1110 Archive->Restore(0x0028,0x0017);
1111 Archive->Restore(0x0028,0x00199);
1115 * \brief Duplicates a ValEntry or creates it.
1116 * @param group Group number of the Entry
1117 * @param elem Element number of the Entry
1118 * \return pointer to the new Val Entry (NULL when creation failed).
1120 ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem)
1122 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1127 newE = new ValEntry(oldE->GetDictEntry());
1132 newE = GetFile()->NewValEntry(group, elem);
1139 * \brief Duplicates a BinEntry or creates it.
1140 * @param group Group number of the Entry
1141 * @param elem Element number of the Entry
1142 * @param vr Value Representation of the Entry
1143 * FIXME : what is it used for?
1144 * \return pointer to the new Bin Entry (NULL when creation failed).
1146 BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem,
1147 const std::string &vr)
1149 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1153 if ( oldE->GetVR()!=vr )
1158 newE = new BinEntry(oldE->GetDictEntry());
1163 newE = GetFile()->NewBinEntry(group, elem, vr);
1170 * \brief This method is called automatically, just before writting
1171 * in order to produce a 'True Dicom V3' image
1172 * We cannot know *how* the user made the File (reading an old ACR-NEMA
1173 * file or a not very clean DICOM file ...)
1175 * Just before writting :
1176 * - we check the Entries
1177 * - we create the mandatory entries if they are missing
1178 * - we modify the values if necessary
1179 * - we push the sensitive entries to the Archive
1180 * The writing process will restore the entries as they where before
1181 * entering FileHelper::CheckMandatoryElements, so the user will always
1182 * see the entries just as he left them.
1184 * \todo : - warn the user if we had to add some entries :
1185 * even if a mandatory entry is missing, we add it, with a default value
1186 * (we don't want to give up the writting process if user forgot to
1187 * specify Lena's Patient ID, for instance ...)
1188 * - read the whole PS 3.3 Part of DICOM (890 pages)
1189 * and write a *full* checker (probably one method per Modality ...)
1190 * Any contribution is welcome.
1191 * - write a user callable full checker, to allow post reading
1192 * and/or pre writting image consistency check.
1195 void FileHelper::CheckMandatoryElements()
1197 // just to remember : 'official' 0002 group
1198 if ( WriteType != ACR && WriteType != ACR_LIBIDO )
1200 // Group 000002 (Meta Elements) already pushed out
1202 //0002 0000 UL 1 Meta Group Length
1203 //0002 0001 OB 1 File Meta Information Version
1204 //0002 0002 UI 1 Media Stored SOP Class UID
1205 //0002 0003 UI 1 Media Stored SOP Instance UID
1206 //0002 0010 UI 1 Transfer Syntax UID
1207 //0002 0012 UI 1 Implementation Class UID
1208 //0002 0013 SH 1 Implementation Version Name
1209 //0002 0016 AE 1 Source Application Entity Title
1210 //0002 0100 UI 1 Private Information Creator
1211 //0002 0102 OB 1 Private Information
1213 // Create them if not found
1214 // Always modify the value
1215 // Push the entries to the archive.
1216 ValEntry *e_0002_0000 = CopyValEntry(0x0002,0x0000);
1217 e_0002_0000->SetValue("0"); // for the moment
1218 Archive->Push(e_0002_0000);
1220 BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB");
1221 e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(),
1223 e_0002_0001->SetLength(2);
1224 Archive->Push(e_0002_0001);
1226 // 'Media Stored SOP Class UID'
1227 ValEntry *e_0002_0002 = CopyValEntry(0x0002,0x0002);
1228 // [Secondary Capture Image Storage]
1229 e_0002_0002->SetValue("1.2.840.10008.5.1.4.1.1.7");
1230 Archive->Push(e_0002_0002);
1232 // 'Media Stored SOP Instance UID'
1233 ValEntry *e_0002_0003 = CopyValEntry(0x0002,0x0003);
1234 e_0002_0003->SetValue(Util::CreateUniqueUID());
1235 Archive->Push(e_0002_0003);
1237 // 'Implementation Class UID'
1238 ValEntry *e_0002_0012 = CopyValEntry(0x0002,0x0012);
1239 e_0002_0012->SetValue(Util::CreateUniqueUID());
1240 Archive->Push(e_0002_0012);
1242 // 'Implementation Version Name'
1243 ValEntry *e_0002_0013 = CopyValEntry(0x0002,0x0013);
1244 e_0002_0013->SetValue("GDCM 1.1");
1245 Archive->Push(e_0002_0013);
1247 //'Source Application Entity Title' Not Mandatory
1248 //ValEntry *e_0002_0016 = CopyValEntry(0x0002,0x0016);
1249 // e_0002_0016->SetValue("1.2.840.10008.5.1.4.1.1.7");
1250 // Archive->Push(e_0002_0016);
1253 // Push out 'LibIDO-special' entries, if any
1254 Archive->Push(0x0028,0x0015);
1255 Archive->Push(0x0028,0x0016);
1256 Archive->Push(0x0028,0x0017);
1257 Archive->Push(0x0028,0x00199);
1259 // Deal with the pb of (Bits Stored = 12)
1260 // - we're gonna write the image as Bits Stored = 16
1261 if ( FileInternal->GetEntryValue(0x0028,0x0100) == "12")
1263 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1264 e_0028_0100->SetValue("16");
1265 Archive->Push(e_0028_0100);
1268 // Check if user wasn't drunk ;-)
1270 std::ostringstream s;
1271 // check 'Bits Allocated' vs decent values
1272 int nbBitsAllocated = FileInternal->GetBitsAllocated();
1273 if ( nbBitsAllocated == 0 || nbBitsAllocated > 32)
1275 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1276 e_0028_0100->SetValue("16");
1277 Archive->Push(e_0028_0100);
1278 gdcmWarningMacro("(0028,0100) changed from "
1279 << nbBitsAllocated << " to 16 for consistency purpose");
1280 nbBitsAllocated = 16;
1282 // check 'Bits Stored' vs 'Bits Allocated'
1283 int nbBitsStored = FileInternal->GetBitsStored();
1284 if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
1286 s << nbBitsAllocated;
1287 ValEntry *e_0028_0101 = CopyValEntry(0x0028,0x0101);
1288 e_0028_0101->SetValue( s.str() );
1289 Archive->Push(e_0028_0101);
1290 gdcmWarningMacro("(0028,0101) changed from "
1291 << nbBitsStored << " to " << nbBitsAllocated
1292 << " for consistency purpose" );
1293 nbBitsStored = nbBitsAllocated;
1295 // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
1296 int highBitPosition = FileInternal->GetHighBitPosition();
1297 if ( highBitPosition == 0 ||
1298 highBitPosition > nbBitsAllocated-1 ||
1299 highBitPosition < nbBitsStored-1 )
1301 ValEntry *e_0028_0102 = CopyValEntry(0x0028,0x0102);
1303 s << nbBitsStored - 1;
1304 e_0028_0102->SetValue( s.str() );
1305 Archive->Push(e_0028_0102);
1306 gdcmWarningMacro("(0028,0102) changed from "
1307 << highBitPosition << " to " << nbBitsAllocated-1
1308 << " for consistency purpose");
1310 // --- Check UID-related Entries ---
1312 // If 'SOP Class UID' exists ('true DICOM' image)
1313 // we create the 'Source Image Sequence' SeqEntry
1314 // to hold informations about the Source Image
1316 ValEntry *e_0008_0016 = FileInternal->GetValEntry(0x0008, 0x0016);
1317 if ( e_0008_0016 != 0 )
1319 // Create 'Source Image Sequence' SeqEntry
1320 SeqEntry *sis = new SeqEntry (
1321 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
1322 SQItem *sqi = new SQItem(1);
1323 // (we assume 'SOP Instance UID' exists too)
1324 // create 'Referenced SOP Class UID'
1325 ValEntry *e_0008_1150 = new ValEntry(
1326 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
1327 e_0008_1150->SetValue( e_0008_0016->GetValue());
1328 sqi->AddEntry(e_0008_1150);
1330 // create 'Referenced SOP Instance UID'
1331 ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018);
1332 ValEntry *e_0008_1155 = new ValEntry(
1333 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
1334 e_0008_1155->SetValue( e_0008_0018->GetValue());
1335 sqi->AddEntry(e_0008_1155);
1337 sis->AddSQItem(sqi,1);
1338 // temporarily replaces any previous 'Source Image Sequence'
1341 // 'Image Type' (The written image is no longer an 'ORIGINAL' one)
1342 ValEntry *e_0008_0008 = CopyValEntry(0x0008,0x0008);
1343 e_0008_0008->SetValue("DERIVED\\PRIMARY");
1344 Archive->Push(e_0008_0008);
1348 // There was no 'SOP Class UID'.
1349 // the source image was NOT a true Dicom one.
1350 // We consider the image is a 'Secondary Capture' one
1352 e_0008_0016 = new ValEntry(
1353 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) );
1354 // [Secondary Capture Image Storage]
1355 e_0008_0016 ->SetValue("1.2.840.10008.5.1.4.1.1.7");
1356 Archive->Push(e_0008_0016);
1359 // ---- The user will never have to take any action on the following ----.
1361 // new value for 'SOP Instance UID'
1362 ValEntry *e_0008_0018 = new ValEntry(
1363 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0018) );
1364 e_0008_0018->SetValue( Util::CreateUniqueUID() );
1365 Archive->Push(e_0008_0018);
1367 // Instance Creation Date
1368 ValEntry *e_0008_0012 = CopyValEntry(0x0008,0x0012);
1369 std::string date = Util::GetCurrentDate();
1370 e_0008_0012->SetValue(date.c_str());
1371 Archive->Push(e_0008_0012);
1373 // Instance Creation Time
1374 ValEntry *e_0008_0013 = CopyValEntry(0x0008,0x0013);
1375 std::string time = Util::GetCurrentTime();
1376 e_0008_0013->SetValue(time.c_str());
1377 Archive->Push(e_0008_0013);
1379 // ----- Add Mandatory Entries if missing ---
1381 // Entries whose type is 1 are mandatory, with a mandatory value
1382 // Entries whose type is 1c are mandatory-inside-a-Sequence
1383 // Entries whose type is 2 are mandatory, with a optional value
1384 // Entries whose type is 2c are mandatory-inside-a-Sequence
1385 // Entries whose type is 3 are optional
1387 // 'Serie Instance UID'
1388 // Keep the value if exists
1389 // The user is allowed to create his own Series,
1390 // keeping the same 'Serie Instance UID' for various images
1391 // The user shouldn't add any image to a 'Manufacturer Serie'
1392 // but there is no way no to allowed him to do that
1393 ValEntry *e_0020_000e = FileInternal->GetValEntry(0x0020, 0x000e);
1396 e_0020_000e = new ValEntry(
1397 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000e) );
1398 e_0020_000e->SetValue(Util::CreateUniqueUID() );
1399 Archive->Push(e_0020_000e);
1402 // 'Study Instance UID'
1403 // Keep the value if exists
1404 // The user is allowed to create his own Study,
1405 // keeping the same 'Study Instance UID' for various images
1406 // The user may add images to a 'Manufacturer Study',
1407 // adding new series to an already existing Study
1408 ValEntry *e_0020_000d = FileInternal->GetValEntry(0x0020, 0x000d);
1411 e_0020_000d = new ValEntry(
1412 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000d) );
1413 e_0020_000d->SetValue(Util::CreateUniqueUID() );
1414 Archive->Push(e_0020_000d);
1417 // Modality : if missing we set it to 'OTher'
1418 ValEntry *e_0008_0060 = FileInternal->GetValEntry(0x0008, 0x0060);
1421 e_0008_0060 = new ValEntry(
1422 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0060) );
1423 e_0008_0060->SetValue("OT");
1424 Archive->Push(e_0008_0060);
1427 // Manufacturer : if missing we set it to 'GDCM Factory'
1428 ValEntry *e_0008_0070 = FileInternal->GetValEntry(0x0008, 0x0070);
1431 e_0008_0070 = new ValEntry(
1432 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0070) );
1433 e_0008_0070->SetValue("GDCM Factory");
1434 Archive->Push(e_0008_0070);
1437 // Institution Name : if missing we set it to 'GDCM Hospital'
1438 ValEntry *e_0008_0080 = FileInternal->GetValEntry(0x0008, 0x0080);
1441 e_0008_0080 = new ValEntry(
1442 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0080) );
1443 e_0008_0080->SetValue("GDCM Hospital");
1444 Archive->Push(e_0008_0080);
1447 // Patient's Name : if missing, we set it to 'GDCM^Patient'
1448 ValEntry *e_0010_0010 = FileInternal->GetValEntry(0x0010, 0x0010);
1451 e_0010_0010 = new ValEntry(
1452 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0010) );
1453 e_0010_0010->SetValue("GDCM^Patient");
1454 Archive->Push(e_0010_0010);
1457 // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
1458 ValEntry *e_0010_0030 = FileInternal->GetValEntry(0x0010, 0x0030);
1461 e_0010_0030 = new ValEntry(
1462 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0030) );
1463 e_0010_0030->SetValue("");
1464 Archive->Push(e_0010_0030);
1467 // Patient's Sex :'type 2' entry -> must exist, value not mandatory
1468 ValEntry *e_0010_0040 = FileInternal->GetValEntry(0x0010, 0x0040);
1471 e_0010_0040 = new ValEntry(
1472 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0040) );
1473 e_0010_0040->SetValue("");
1474 Archive->Push(e_0010_0040);
1477 // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
1478 ValEntry *e_0008_0090 = FileInternal->GetValEntry(0x0008, 0x0090);
1481 e_0008_0090 = new ValEntry(
1482 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0090) );
1483 e_0008_0090->SetValue("");
1484 Archive->Push(e_0008_0090);
1487 // Remove some inconstencies (probably some more will be added)
1489 // if (0028 0008)Number of Frames exists
1490 // Push out (0020 0052),Frame of Reference UID
1491 // (only meaningfull within a Serie)
1492 ValEntry *e_0028_0008 = FileInternal->GetValEntry(0x0028, 0x0008);
1495 Archive->Push(0x0020, 0X0052);
1500 * \brief Restore in the File the initial group 0002
1502 void FileHelper::RestoreWriteMandatory()
1504 // group 0002 may be pushed out for ACR-NEMA writting purposes
1505 Archive->Restore(0x0002,0x0000);
1506 Archive->Restore(0x0002,0x0001);
1507 Archive->Restore(0x0002,0x0002);
1508 Archive->Restore(0x0002,0x0003);
1509 Archive->Restore(0x0002,0x0010);
1510 Archive->Restore(0x0002,0x0012);
1511 Archive->Restore(0x0002,0x0013);
1512 Archive->Restore(0x0002,0x0016);
1513 Archive->Restore(0x0002,0x0100);
1514 Archive->Restore(0x0002,0x0102);
1516 Archive->Restore(0x0008,0x0012);
1517 Archive->Restore(0x0008,0x0013);
1518 Archive->Restore(0x0008,0x0016);
1519 Archive->Restore(0x0008,0x0018);
1520 Archive->Restore(0x0008,0x0060);
1521 Archive->Restore(0x0008,0x0070);
1522 Archive->Restore(0x0008,0x0080);
1523 Archive->Restore(0x0008,0x0090);
1524 Archive->Restore(0x0008,0x2112);
1526 Archive->Restore(0x0010,0x0010);
1527 Archive->Restore(0x0010,0x0030);
1528 Archive->Restore(0x0010,0x0040);
1530 Archive->Restore(0x0020,0x000d);
1531 Archive->Restore(0x0020,0x000e);
1535 //-----------------------------------------------------------------------------
1538 * \brief Factorization for various forms of constructors.
1540 void FileHelper::Initialize()
1544 WriteMode = WMODE_RAW;
1545 WriteType = ExplicitVR;
1547 PixelReadConverter = new PixelReadConvert;
1548 PixelWriteConverter = new PixelWriteConvert;
1549 Archive = new DocEntryArchive( FileInternal );
1553 * \brief Reads/[decompresses] the pixels,
1554 * *without* making RGB from Palette Colors
1555 * @return the pixels area, whatever its type
1556 * (uint8_t is just for prototyping : feel free to Cast it)
1558 uint8_t *FileHelper::GetRaw()
1560 PixelReadConverter->SetUserFunction( UserFunction );
1562 uint8_t *raw = PixelReadConverter->GetRaw();
1565 // The Raw image migth not be loaded yet:
1566 std::ifstream *fp = FileInternal->OpenFile();
1567 PixelReadConverter->ReadAndDecompressPixelData( fp );
1569 FileInternal->CloseFile();
1571 raw = PixelReadConverter->GetRaw();
1574 gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
1581 //-----------------------------------------------------------------------------
1583 * \brief Prints the common part of ValEntry, BinEntry, SeqEntry
1584 * @param os ostream we want to print in
1585 * @param indent (unused)
1587 void FileHelper::Print(std::ostream &os, std::string const &)
1589 FileInternal->SetPrintLevel(PrintLevel);
1590 FileInternal->Print(os);
1592 PixelReadConverter->SetPrintLevel(PrintLevel);
1593 PixelReadConverter->Print(os);
1596 //-----------------------------------------------------------------------------
1597 } // end namespace gdcm