1 /*=========================================================================
4 Module: $RCSfile: gdcmFileHelper.cxx,v $
7 Date: $Date: 2005/07/19 15:19:27 $
8 Version: $Revision: 1.49 $
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 *f1 = new gdcm::File(fileName);
46 // user can now check some values
47 std::string v = f1->GetEntryValue(groupNb,ElementNb);
48 // to get the pixels, user needs a gdcm::FileHelper
49 gdcm::FileHelper *fh1 = new gdcm::FileHelper(f1);
50 // user may ask not to convert Palette to RGB
51 uint8_t *pixels = fh1->GetImageDataRaw();
52 int imageLength = fh1->GetImageDataRawSize();
53 // He can now use the pixels, create a new image, ...
54 uint8_t *userPixels = ...
56 To re-write the image, user re-uses the gdcm::FileHelper
58 fh1->SetImageData( userPixels, userPixelsLength);
59 fh1->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB
62 fh1->SetWriteTypeToDcmExpl(); // he wants Explicit Value Representation
63 // Little Endian is the default
64 // no other value is allowed
65 (-->SetWriteType(ExplicitVR);)
66 -->WriteType = ExplicitVR;
67 fh1->Write(newFileName); // overwrites the file, if any
70 fh1->WriteDcmExplVR(newFileName);
73 // ----------------------------- WARNING -------------------------
75 These lines will be moved to the document-to-be 'Developer's Guide'
77 WriteMode : WMODE_RAW / WMODE_RGB
78 WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO
80 fh1->Write(newFileName);
81 SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR();
82 (modifies TransferSyntax)
83 SetWriteToRaw(); / SetWriteToRGB();
84 (modifies, when necessary : photochromatic interpretation,
85 samples per pixel, Planar configuration,
86 bits allocated, bits stored, high bit -ACR 24 bits-
87 Pixels element VR, pushes out the LUT )
88 CheckWriteIntegrity();
89 (checks user given pixels length)
90 FileInternal->Write(fileName,WriteType)
91 fp = opens file(fileName);
92 ComputeGroup0002Length(writetype);
94 RemoveEntryNoDestroy(palettes, etc)
95 Document::WriteContent(fp, writetype);
97 (moves back to the File all the archived elements)
98 RestoreWriteFileType();
99 (pushes back group 0002, with TransferSyntax)
107 //-------------------------------------------------------------------------
108 // Constructor / Destructor
110 * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
111 * file (gdcm::File only deals with the ... header)
112 * Opens (in read only and when possible) an existing file and checks
113 * for DICOM compliance. Returns NULL on failure.
114 * It will be up to the user to load the pixels into memory
115 * \note the in-memory representation of all available tags found in
116 * the DICOM header is post-poned to first header information access.
117 * This avoid a double parsing of public part of the header when
118 * one sets an a posteriori shadow dictionary (efficiency can be
119 * seen as a side effect).
121 FileHelper::FileHelper( )
123 FileInternal = new File( );
129 * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
130 * file (File only deals with the ... header)
131 * Opens (in read only and when possible) an existing file and checks
132 * for DICOM compliance. Returns NULL on failure.
133 * It will be up to the user to load the pixels into memory
134 * \note the in-memory representation of all available tags found in
135 * the DICOM header is post-poned to first header information access.
136 * This avoid a double parsing of public part of the header when
137 * user sets an a posteriori shadow dictionary (efficiency can be
138 * seen as a side effect).
139 * @param header already built Header
141 FileHelper::FileHelper(File *header)
143 FileInternal = header;
150 * \brief canonical destructor
151 * \note If the header (gdcm::File) was created by the FileHelper constructor,
152 * it is destroyed by the FileHelper
154 FileHelper::~FileHelper()
156 if ( PixelReadConverter )
158 delete PixelReadConverter;
160 if ( PixelWriteConverter )
162 delete PixelWriteConverter;
176 //-----------------------------------------------------------------------------
180 * \brief Sets the LoadMode of the internal gdcm::File as a boolean string.
181 * NO_SEQ, NO_SHADOW, NO_SHADOWSEQ
182 *... (nothing more, right now)
183 * WARNING : before using NO_SHADOW, be sure *all* your files
184 * contain accurate values in the 0x0000 element (if any)
185 * of *each* Shadow Group. The parser will fail if the size is wrong !
186 * @param loadMode Load mode to be used
188 void FileHelper::SetLoadMode(int loadMode)
190 GetFile()->SetLoadMode( loadMode );
193 * \brief Sets the LoadMode of the internal gdcm::File
194 * @param fileName name of the file to be open
196 void FileHelper::SetFileName(std::string const &fileName)
198 FileInternal->SetFileName( fileName );
203 * @return false if file cannot be open or no swap info was found,
204 * or no tag was found.
206 bool FileHelper::Load()
208 return FileInternal->Load();
212 * \brief Accesses an existing DocEntry (i.e. a Dicom Element)
213 * through it's (group, element) and modifies it's content with
215 * @param content new value (string) to substitute with
216 * @param group group number of the Dicom Element to modify
217 * @param elem element number of the Dicom Element to modify
218 * \return false if DocEntry not found
220 bool FileHelper::SetValEntry(std::string const &content,
221 uint16_t group, uint16_t elem)
223 return FileInternal->SetValEntry(content, group, elem);
228 * \brief Accesses an existing DocEntry (i.e. a Dicom Element)
229 * through it's (group, element) and modifies it's content with
231 * @param content new value (void* -> uint8_t*) to substitute with
232 * @param lgth new value length
233 * @param group group number of the Dicom Element to modify
234 * @param elem element number of the Dicom Element to modify
235 * \return false if DocEntry not found
237 bool FileHelper::SetBinEntry(uint8_t *content, int lgth,
238 uint16_t group, uint16_t elem)
240 return FileInternal->SetBinEntry(content, lgth, group, elem);
244 * \brief Modifies the value of a given DocEntry (Dicom entry)
245 * when it exists. Creates it with the given value when unexistant.
246 * @param content (string)value to be set
247 * @param group Group number of the Entry
248 * @param elem Element number of the Entry
249 * \return pointer to the modified/created Dicom entry (NULL when creation
252 ValEntry *FileHelper::InsertValEntry(std::string const &content,
253 uint16_t group, uint16_t elem)
255 return FileInternal->InsertValEntry(content, group, elem);
259 * \brief Modifies the value of a given DocEntry (Dicom entry)
260 * when it exists. Creates it with the given value when unexistant.
261 * A copy of the binArea is made to be kept in the Document.
262 * @param binArea (binary)value to be set
263 * @param lgth new value length
264 * @param group Group number of the Entry
265 * @param elem Element number of the Entry
266 * \return pointer to the modified/created Dicom entry (NULL when creation
269 BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth,
270 uint16_t group, uint16_t elem)
272 return FileInternal->InsertBinEntry(binArea, lgth, group, elem);
276 * \brief Modifies the value of a given DocEntry (Dicom entry)
277 * when it exists. Creates it, empty (?!) when unexistant.
278 * @param group Group number of the Entry
279 * @param elem Element number of the Entry
280 * \return pointer to the modified/created Dicom entry (NULL when creation
283 SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
285 return FileInternal->InsertSeqEntry(group, elem);
289 * \brief Get the size of the image data
290 * If the image can be RGB (with a lut or by default), the size
291 * corresponds to the RGB image
292 * (use GetImageDataRawSize if you want to be sure to get *only*
293 * the size of the pixels)
294 * @return The image size
296 size_t FileHelper::GetImageDataSize()
298 if ( PixelWriteConverter->GetUserData() )
300 return PixelWriteConverter->GetUserDataSize();
302 return PixelReadConverter->GetRGBSize();
306 * \brief Get the size of the image data
307 * If the image could be converted to RGB using a LUT,
308 * this transformation is not taken into account by GetImageDataRawSize
309 * (use GetImageDataSize if you wish)
310 * @return The raw image size
312 size_t FileHelper::GetImageDataRawSize()
314 if ( PixelWriteConverter->GetUserData() )
316 return PixelWriteConverter->GetUserDataSize();
318 return PixelReadConverter->GetRawSize();
322 * \brief - Allocates necessary memory,
323 * - Reads the pixels from disk (uncompress if necessary),
324 * - Transforms YBR pixels, if any, into RGB pixels,
325 * - Transforms 3 planes R, G, B, if any, into a single RGB Plane
326 * - Transforms single Grey plane + 3 Palettes into a RGB Plane
327 * - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
328 * @return Pointer to newly allocated pixel data.
329 * NULL if alloc fails
331 uint8_t *FileHelper::GetImageData()
333 if ( PixelWriteConverter->GetUserData() )
335 return PixelWriteConverter->GetUserData();
340 // If the decompression failed nothing can be done.
344 if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
346 return PixelReadConverter->GetRGB();
350 // When no LUT or LUT conversion fails, return the Raw
351 return PixelReadConverter->GetRaw();
356 * \brief Allocates necessary memory,
357 * Transforms YBR pixels (if any) into RGB pixels
358 * Transforms 3 planes R, G, B (if any) into a single RGB Plane
359 * Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
360 * DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
361 * @return Pointer to newly allocated pixel data.
362 * NULL if alloc fails
364 uint8_t *FileHelper::GetImageDataRaw ()
371 * Read the pixels from disk (uncompress if necessary),
372 * Transforms YBR pixels, if any, into RGB pixels
373 * Transforms 3 planes R, G, B, if any, into a single RGB Plane
374 * Transforms single Grey plane + 3 Palettes into a RGB Plane
375 * Copies at most MaxSize bytes of pixel data to caller allocated
377 * \warning This function allows people that want to build a volume
378 * from an image stack *not to* have, first to get the image pixels,
379 * and then move them to the volume area.
380 * It's absolutely useless for any VTK user since vtk chooses
381 * to invert the lines of an image, that is the last line comes first
382 * (for some axis related reasons?). Hence he will have
383 * to load the image line by line, starting from the end.
384 * VTK users have to call GetImageData
386 * @param destination Address (in caller's memory space) at which the
387 * pixel data should be copied
388 * @param maxSize Maximum number of bytes to be copied. When MaxSize
389 * is not sufficient to hold the pixel data the copy is not
390 * executed (i.e. no partial copy).
391 * @return On success, the number of bytes actually copied. Zero on
392 * failure e.g. MaxSize is lower than necessary.
394 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
398 // If the decompression failed nothing can be done.
402 if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
404 if ( PixelReadConverter->GetRGBSize() > maxSize )
406 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
410 (void*)PixelReadConverter->GetRGB(),
411 PixelReadConverter->GetRGBSize() );
412 return PixelReadConverter->GetRGBSize();
415 // Either no LUT conversion necessary or LUT conversion failed
416 if ( PixelReadConverter->GetRawSize() > maxSize )
418 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
422 (void *)PixelReadConverter->GetRaw(),
423 PixelReadConverter->GetRawSize() );
424 return PixelReadConverter->GetRawSize();
428 * \brief Points the internal pointer to the callers inData
429 * image representation, BUT WITHOUT COPYING THE DATA.
430 * 'image' Pixels are presented as C-like 2D arrays : line per line.
431 * 'volume'Pixels are presented as C-like 3D arrays : plane per plane
432 * \warning Since the pixels are not copied, it is the caller's responsability
433 * not to deallocate its data before gdcm uses them (e.g. with
434 * the Write() method )
435 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
436 * user is allowed to pass any kind of pixelsn since the size is
438 * @param expectedSize total image size, *in Bytes*
440 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
442 SetUserData(inData, expectedSize);
446 * \brief Set the image data defined by the user
447 * \warning When writting the file, this data are get as default data to write
448 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
449 * user is allowed to pass any kind of pixels since the size is
451 * @param expectedSize total image size, *in Bytes*
453 void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
455 PixelWriteConverter->SetUserData(inData, expectedSize);
459 * \brief Get the image data defined by the user
460 * \warning When writting the file, this data are get as default data to write
462 uint8_t *FileHelper::GetUserData()
464 return PixelWriteConverter->GetUserData();
468 * \brief Get the image data size defined by the user
469 * \warning When writting the file, this data are get as default data to write
471 size_t FileHelper::GetUserDataSize()
473 return PixelWriteConverter->GetUserDataSize();
477 * \brief Get the image data from the file.
478 * If a LUT is found, the data are expanded to be RGB
480 uint8_t *FileHelper::GetRGBData()
482 return PixelReadConverter->GetRGB();
486 * \brief Get the image data size from the file.
487 * If a LUT is found, the data are expanded to be RGB
489 size_t FileHelper::GetRGBDataSize()
491 return PixelReadConverter->GetRGBSize();
495 * \brief Get the image data from the file.
496 * Even when a LUT is found, the data are not expanded to RGB!
498 uint8_t *FileHelper::GetRawData()
500 return PixelReadConverter->GetRaw();
504 * \brief Get the image data size from the file.
505 * Even when a LUT is found, the data are not expanded to RGB!
507 size_t FileHelper::GetRawDataSize()
509 return PixelReadConverter->GetRawSize();
513 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
515 uint8_t* FileHelper::GetLutRGBA()
517 if ( PixelReadConverter->GetLutRGBA() ==0 )
518 PixelReadConverter->BuildLUTRGBA();
519 return PixelReadConverter->GetLutRGBA();
523 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number
525 int FileHelper::GetLutItemNumber()
527 return PixelReadConverter->GetLutItemNumber();
531 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size
533 int FileHelper::GetLutItemSize()
535 return PixelReadConverter->GetLutItemSize();
539 * \brief Writes on disk A SINGLE Dicom file
540 * NO test is performed on processor "Endiannity".
541 * It's up to the user to call his Reader properly
542 * @param fileName name of the file to be created
543 * (any already existing file is over written)
544 * @return false if write fails
546 bool FileHelper::WriteRawData(std::string const &fileName)
548 std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
551 gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str());
555 if ( PixelWriteConverter->GetUserData() )
557 fp1.write( (char *)PixelWriteConverter->GetUserData(),
558 PixelWriteConverter->GetUserDataSize() );
560 else if ( PixelReadConverter->GetRGB() )
562 fp1.write( (char *)PixelReadConverter->GetRGB(),
563 PixelReadConverter->GetRGBSize());
565 else if ( PixelReadConverter->GetRaw() )
567 fp1.write( (char *)PixelReadConverter->GetRaw(),
568 PixelReadConverter->GetRawSize());
572 gdcmErrorMacro( "Nothing written." );
581 * \brief Writes on disk A SINGLE Dicom file,
582 * using the Implicit Value Representation convention
583 * NO test is performed on processor "Endianity".
584 * @param fileName name of the file to be created
585 * (any already existing file is overwritten)
586 * @return false if write fails
589 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
591 SetWriteTypeToDcmImplVR();
592 return Write(fileName);
596 * \brief Writes on disk A SINGLE Dicom file,
597 * using the Explicit Value Representation convention
598 * NO test is performed on processor "Endiannity".
599 * @param fileName name of the file to be created
600 * (any already existing file is overwritten)
601 * @return false if write fails
604 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
606 SetWriteTypeToDcmExplVR();
607 return Write(fileName);
611 * \brief Writes on disk A SINGLE Dicom file,
612 * using the ACR-NEMA convention
613 * NO test is performed on processor "Endiannity".
614 * (a l'attention des logiciels cliniques
615 * qui ne prennent en entrée QUE des images ACR ...
616 * \warning if a DICOM_V3 header is supplied,
617 * groups < 0x0008 and shadow groups are ignored
618 * \warning NO TEST is performed on processor "Endiannity".
619 * @param fileName name of the file to be created
620 * (any already existing file is overwritten)
621 * @return false if write fails
624 bool FileHelper::WriteAcr (std::string const &fileName)
627 return Write(fileName);
631 * \brief Writes on disk A SINGLE Dicom file,
632 * @param fileName name of the file to be created
633 * (any already existing file is overwritten)
634 * @return false if write fails
636 bool FileHelper::Write(std::string const &fileName)
641 SetWriteFileTypeToImplicitVR();
643 case Unknown: // should never happen; ExplicitVR is the default value
645 SetWriteFileTypeToExplicitVR();
649 // NOTHING is done here just for LibIDO.
650 // Just to avoid further trouble if user creates a file ex-nihilo,
651 // wants to write it as an ACR-NEMA file,
652 // and forgets to create any Entry belonging to group 0008
654 // We add Recognition Code (RET)
655 if ( ! FileInternal->GetValEntry(0x0008, 0x0010) )
656 FileInternal->InsertValEntry("", 0x0008, 0x0010);
657 SetWriteFileTypeToACR();
658 // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR !
661 CheckMandatoryElements();
663 // --------------------------------------------------------------
664 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
666 // if recognition code tells us we dealt with a LibIDO image
667 // we reproduce on disk the switch between lineNumber and columnNumber
668 // just before writting ...
669 /// \todo the best trick would be *change* the recognition code
670 /// but pb expected if user deals with, e.g. COMPLEX images
672 if ( WriteType == ACR_LIBIDO )
678 SetWriteToNoLibido();
680 // ----------------- End of Special Patch ----------------
685 SetWriteToRaw(); // modifies and pushes to the archive, when necessary
688 SetWriteToRGB(); // modifies and pushes to the archive, when necessary
692 bool check = CheckWriteIntegrity(); // verifies length
695 check = FileInternal->Write(fileName,WriteType);
699 RestoreWriteFileType();
700 RestoreWriteMandatory();
702 // --------------------------------------------------------------
703 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
705 // ...and we restore the header to be Dicom Compliant again
706 // just after writting
707 RestoreWriteOfLibido();
708 // ----------------- End of Special Patch ----------------
713 //-----------------------------------------------------------------------------
716 * \brief Checks the write integrity
718 * The tests made are :
719 * - verify the size of the image to write with the possible write
720 * when the user set an image data
721 * @return true if check is successfull
723 bool FileHelper::CheckWriteIntegrity()
725 if ( PixelWriteConverter->GetUserData() )
727 int numberBitsAllocated = FileInternal->GetBitsAllocated();
728 if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
730 gdcmWarningMacro( "numberBitsAllocated changed from "
731 << numberBitsAllocated << " to 16 "
732 << " for consistency purpose" );
733 numberBitsAllocated = 16;
736 size_t decSize = FileInternal->GetXSize()
737 * FileInternal->GetYSize()
738 * FileInternal->GetZSize()
739 * FileInternal->GetSamplesPerPixel()
740 * ( numberBitsAllocated / 8 );
741 size_t rgbSize = decSize;
742 if ( FileInternal->HasLUT() )
743 rgbSize = decSize * 3;
748 if ( decSize!=PixelWriteConverter->GetUserDataSize() )
750 gdcmWarningMacro( "Data size (Raw) is incorrect. Should be "
751 << decSize << " / Found :"
752 << PixelWriteConverter->GetUserDataSize() );
757 if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
759 gdcmWarningMacro( "Data size (RGB) is incorrect. Should be "
760 << decSize << " / Found "
761 << PixelWriteConverter->GetUserDataSize() );
771 * \brief Updates the File to write RAW data (as opposed to RGB data)
772 * (modifies, when necessary, photochromatic interpretation,
773 * bits allocated, Pixels element VR)
775 void FileHelper::SetWriteToRaw()
777 if ( FileInternal->GetNumberOfScalarComponents() == 3
778 && !FileInternal->HasLUT() )
784 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
785 if (FileInternal->HasLUT() )
787 photInt->SetValue("PALETTE COLOR ");
791 photInt->SetValue("MONOCHROME2 ");
794 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
795 PixelReadConverter->GetRawSize());
797 std::string vr = "OB";
798 if ( FileInternal->GetBitsAllocated()>8 )
800 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
803 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
804 pixel->SetValue(GDCM_BINLOADED);
805 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
806 pixel->SetLength(PixelWriteConverter->GetDataSize());
808 Archive->Push(photInt);
809 Archive->Push(pixel);
814 * \brief Updates the File to write RGB data (as opposed to RAW data)
815 * (modifies, when necessary, photochromatic interpretation,
816 * samples per pixel, Planar configuration,
817 * bits allocated, bits stored, high bit -ACR 24 bits-
818 * Pixels element VR, pushes out the LUT, )
820 void FileHelper::SetWriteToRGB()
822 if ( FileInternal->GetNumberOfScalarComponents()==3 )
824 PixelReadConverter->BuildRGBImage();
826 ValEntry *spp = CopyValEntry(0x0028,0x0002);
829 ValEntry *planConfig = CopyValEntry(0x0028,0x0006);
830 planConfig->SetValue("0 ");
832 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
833 photInt->SetValue("RGB ");
835 if ( PixelReadConverter->GetRGB() )
837 PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
838 PixelReadConverter->GetRGBSize());
842 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
843 PixelReadConverter->GetRawSize());
846 std::string vr = "OB";
847 if ( FileInternal->GetBitsAllocated()>8 )
849 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
852 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
853 pixel->SetValue(GDCM_BINLOADED);
854 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
855 pixel->SetLength(PixelWriteConverter->GetDataSize());
858 Archive->Push(planConfig);
859 Archive->Push(photInt);
860 Archive->Push(pixel);
863 Archive->Push(0x0028,0x1101);
864 Archive->Push(0x0028,0x1102);
865 Archive->Push(0x0028,0x1103);
866 Archive->Push(0x0028,0x1201);
867 Archive->Push(0x0028,0x1202);
868 Archive->Push(0x0028,0x1203);
870 // push out Palette Color Lookup Table UID, if any
871 Archive->Push(0x0028,0x1199);
873 // For old '24 Bits' ACR-NEMA
874 // Thus, we have a RGB image and the bits allocated = 24 and
875 // samples per pixels = 1 (in the read file)
876 if ( FileInternal->GetBitsAllocated()==24 )
878 ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100);
879 bitsAlloc->SetValue("8 ");
881 ValEntry *bitsStored = CopyValEntry(0x0028,0x0101);
882 bitsStored->SetValue("8 ");
884 ValEntry *highBit = CopyValEntry(0x0028,0x0102);
885 highBit->SetValue("7 ");
887 Archive->Push(bitsAlloc);
888 Archive->Push(bitsStored);
889 Archive->Push(highBit);
899 * \brief Restore the File write mode
901 void FileHelper::RestoreWrite()
903 Archive->Restore(0x0028,0x0002);
904 Archive->Restore(0x0028,0x0004);
905 Archive->Restore(0x0028,0x0006);
906 Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
908 // For old ACR-NEMA (24 bits problem)
909 Archive->Restore(0x0028,0x0100);
910 Archive->Restore(0x0028,0x0101);
911 Archive->Restore(0x0028,0x0102);
914 Archive->Restore(0x0028,0x1101);
915 Archive->Restore(0x0028,0x1102);
916 Archive->Restore(0x0028,0x1103);
917 Archive->Restore(0x0028,0x1201);
918 Archive->Restore(0x0028,0x1202);
919 Archive->Restore(0x0028,0x1203);
921 // For the Palette Color Lookup Table UID
922 Archive->Restore(0x0028,0x1203);
925 // group 0002 may be pushed out for ACR-NEMA writting purposes
926 Archive->Restore(0x0002,0x0000);
927 Archive->Restore(0x0002,0x0001);
928 Archive->Restore(0x0002,0x0002);
929 Archive->Restore(0x0002,0x0003);
930 Archive->Restore(0x0002,0x0010);
931 Archive->Restore(0x0002,0x0012);
932 Archive->Restore(0x0002,0x0013);
933 Archive->Restore(0x0002,0x0016);
934 Archive->Restore(0x0002,0x0100);
935 Archive->Restore(0x0002,0x0102);
939 * \brief Pushes out the whole group 0002
940 * FIXME : better, set a flag to tell the writer not to write it ...
941 * FIXME : method should probably have an other name !
942 * SetWriteFileTypeToACR is NOT opposed to
943 * SetWriteFileTypeToExplicitVR and SetWriteFileTypeToImplicitVR
945 void FileHelper::SetWriteFileTypeToACR()
947 Archive->Push(0x0002,0x0000);
948 Archive->Push(0x0002,0x0001);
949 Archive->Push(0x0002,0x0002);
950 Archive->Push(0x0002,0x0003);
951 Archive->Push(0x0002,0x0010);
952 Archive->Push(0x0002,0x0012);
953 Archive->Push(0x0002,0x0013);
954 Archive->Push(0x0002,0x0016);
955 Archive->Push(0x0002,0x0100);
956 Archive->Push(0x0002,0x0102);
960 * \brief Sets in the File the TransferSyntax to 'Explicit VR Little Endian"
962 void FileHelper::SetWriteFileTypeToExplicitVR()
964 std::string ts = Util::DicomString(
965 Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
967 ValEntry *tss = CopyValEntry(0x0002,0x0010);
974 * \brief Sets in the File the TransferSyntax to 'Implicit VR Little Endian"
976 void FileHelper::SetWriteFileTypeToImplicitVR()
978 std::string ts = Util::DicomString(
979 Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
981 ValEntry *tss = CopyValEntry(0x0002,0x0010);
989 * \brief Restore in the File the initial group 0002
991 void FileHelper::RestoreWriteFileType()
996 * \brief Set the Write not to Libido format
998 void FileHelper::SetWriteToLibido()
1000 ValEntry *oldRow = dynamic_cast<ValEntry *>
1001 (FileInternal->GetDocEntry(0x0028, 0x0010));
1002 ValEntry *oldCol = dynamic_cast<ValEntry *>
1003 (FileInternal->GetDocEntry(0x0028, 0x0011));
1005 if ( oldRow && oldCol )
1007 std::string rows, columns;
1009 ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
1010 ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
1012 newRow->Copy(oldCol);
1013 newCol->Copy(oldRow);
1015 newRow->SetValue(oldCol->GetValue());
1016 newCol->SetValue(oldRow->GetValue());
1018 Archive->Push(newRow);
1019 Archive->Push(newCol);
1022 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1023 libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
1024 Archive->Push(libidoCode);
1028 * \brief Set the Write not to No Libido format
1030 void FileHelper::SetWriteToNoLibido()
1032 ValEntry *recCode = dynamic_cast<ValEntry *>
1033 (FileInternal->GetDocEntry(0x0008,0x0010));
1036 if ( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
1038 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1039 libidoCode->SetValue("");
1040 Archive->Push(libidoCode);
1046 * \brief Restore the Write format
1048 void FileHelper::RestoreWriteOfLibido()
1050 Archive->Restore(0x0028,0x0010);
1051 Archive->Restore(0x0028,0x0011);
1052 Archive->Restore(0x0008,0x0010);
1054 // Restore 'LibIDO-special' entries, if any
1055 Archive->Restore(0x0028,0x0015);
1056 Archive->Restore(0x0028,0x0016);
1057 Archive->Restore(0x0028,0x0017);
1058 Archive->Restore(0x0028,0x00199);
1062 * \brief Duplicates a ValEntry or creates it.
1063 * @param group Group number of the Entry
1064 * @param elem Element number of the Entry
1065 * \return pointer to the new Val Entry (NULL when creation failed).
1067 ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem)
1069 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1074 newE = new ValEntry(oldE->GetDictEntry());
1079 newE = GetFile()->NewValEntry(group, elem);
1086 * \brief Duplicates a BinEntry or creates it.
1087 * @param group Group number of the Entry
1088 * @param elem Element number of the Entry
1089 * @param vr Value Representation of the Entry
1090 * FIXME : what is it used for?
1091 * \return pointer to the new Bin Entry (NULL when creation failed).
1093 BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem,
1094 const std::string &vr)
1096 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1100 if ( oldE->GetVR()!=vr )
1105 newE = new BinEntry(oldE->GetDictEntry());
1110 newE = GetFile()->NewBinEntry(group, elem, vr);
1117 * \brief This method is called automatically, just before writting
1118 * in order to produce a 'True Dicom V3' image
1119 * We cannot know *how* the user made the File (reading an old ACR-NEMA
1120 * file or a not very clean DICOM file ...)
1122 * Just before writting :
1123 * - we check the Entries
1124 * - we create the mandatory entries if they are missing
1125 * - we modify the values if necessary
1126 * - we push the sensitive entries to the Archive
1127 * The writing process will restore the entries as they where before
1128 * entering FileHelper::CheckMandatoryElements, so the user will always
1129 * see the entries just as he left them.
1131 * \todo : - warn the user if we had to add some entries :
1132 * even if a mandatory entry is missing, we add it, with a default value
1133 * (we don't want to give up the writting process if user forgot to
1134 * specify Lena's Patient ID, for instance ...)
1135 * - read the whole PS 3.3 Part of DICOM (890 pages)
1136 * and write a *full* checker (probably one method per Modality ...)
1137 * Any contribution is welcome.
1138 * - write a user callable full checker, to allow post reading
1139 * and/or pre writting image consistency check.
1142 void FileHelper::CheckMandatoryElements()
1144 // just to remember : 'official' 0002 group
1145 if ( WriteType != ACR && WriteType != ACR_LIBIDO )
1147 // Group 000002 (Meta Elements) already pushed out
1149 //0002 0000 UL 1 Meta Group Length
1150 //0002 0001 OB 1 File Meta Information Version
1151 //0002 0002 UI 1 Media Stored SOP Class UID
1152 //0002 0003 UI 1 Media Stored SOP Instance UID
1153 //0002 0010 UI 1 Transfer Syntax UID
1154 //0002 0012 UI 1 Implementation Class UID
1155 //0002 0013 SH 1 Implementation Version Name
1156 //0002 0016 AE 1 Source Application Entity Title
1157 //0002 0100 UI 1 Private Information Creator
1158 //0002 0102 OB 1 Private Information
1160 // Create them if not found
1161 // Always modify the value
1162 // Push the entries to the archive.
1163 ValEntry *e_0002_0000 = CopyValEntry(0x0002,0x0000);
1164 e_0002_0000->SetValue("0"); // for the moment
1165 Archive->Push(e_0002_0000);
1167 BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB");
1168 e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(),
1170 e_0002_0001->SetLength(2);
1171 Archive->Push(e_0002_0001);
1173 // 'Media Stored SOP Class UID'
1174 ValEntry *e_0002_0002 = CopyValEntry(0x0002,0x0002);
1175 // [Secondary Capture Image Storage]
1176 e_0002_0002->SetValue("1.2.840.10008.5.1.4.1.1.7");
1177 Archive->Push(e_0002_0002);
1179 // 'Media Stored SOP Instance UID'
1180 ValEntry *e_0002_0003 = CopyValEntry(0x0002,0x0003);
1181 e_0002_0003->SetValue(Util::CreateUniqueUID());
1182 Archive->Push(e_0002_0003);
1184 // 'Implementation Class UID'
1185 ValEntry *e_0002_0012 = CopyValEntry(0x0002,0x0012);
1186 e_0002_0012->SetValue(Util::CreateUniqueUID());
1187 Archive->Push(e_0002_0012);
1189 // 'Implementation Version Name'
1190 ValEntry *e_0002_0013 = CopyValEntry(0x0002,0x0013);
1191 e_0002_0013->SetValue("GDCM 1.1");
1192 Archive->Push(e_0002_0013);
1194 //'Source Application Entity Title' Not Mandatory
1195 //ValEntry *e_0002_0016 = CopyValEntry(0x0002,0x0016);
1196 // e_0002_0016->SetValue("1.2.840.10008.5.1.4.1.1.7");
1197 // Archive->Push(e_0002_0016);
1200 // Push out 'LibIDO-special' entries, if any
1201 Archive->Push(0x0028,0x0015);
1202 Archive->Push(0x0028,0x0016);
1203 Archive->Push(0x0028,0x0017);
1204 Archive->Push(0x0028,0x00199);
1206 // Deal with the pb of (Bits Stored = 12)
1207 // - we're gonna write the image as Bits Stored = 16
1208 if ( FileInternal->GetEntryValue(0x0028,0x0100) == "12")
1210 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1211 e_0028_0100->SetValue("16");
1212 Archive->Push(e_0028_0100);
1215 // Check if user wasn't drunk ;-)
1217 std::ostringstream s;
1218 // check 'Bits Allocated' vs decent values
1219 int nbBitsAllocated = FileInternal->GetBitsAllocated();
1220 if ( nbBitsAllocated == 0 || nbBitsAllocated > 32)
1222 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1223 e_0028_0100->SetValue("16");
1224 Archive->Push(e_0028_0100);
1225 gdcmWarningMacro("(0028,0100) changed from "
1226 << nbBitsAllocated << " to 16 for consistency purpose");
1227 nbBitsAllocated = 16;
1229 // check 'Bits Stored' vs 'Bits Allocated'
1230 int nbBitsStored = FileInternal->GetBitsStored();
1231 if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
1233 s << nbBitsAllocated;
1234 ValEntry *e_0028_0101 = CopyValEntry(0x0028,0x0101);
1235 e_0028_0101->SetValue( s.str() );
1236 Archive->Push(e_0028_0101);
1237 gdcmWarningMacro("(0028,0101) changed from "
1238 << nbBitsStored << " to " << nbBitsAllocated
1239 << " for consistency purpose" );
1240 nbBitsStored = nbBitsAllocated;
1242 // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
1243 int highBitPosition = FileInternal->GetHighBitPosition();
1244 if ( highBitPosition == 0 ||
1245 highBitPosition > nbBitsAllocated-1 ||
1246 highBitPosition < nbBitsStored-1 )
1248 ValEntry *e_0028_0102 = CopyValEntry(0x0028,0x0102);
1250 s << nbBitsStored - 1;
1251 e_0028_0102->SetValue( s.str() );
1252 Archive->Push(e_0028_0102);
1253 gdcmWarningMacro("(0028,0102) changed from "
1254 << highBitPosition << " to " << nbBitsAllocated-1
1255 << " for consistency purpose");
1257 // --- Check UID-related Entries ---
1259 // If 'SOP Class UID' exists ('true DICOM' image)
1260 // we create the 'Source Image Sequence' SeqEntry
1261 // to hold informations about the Source Image
1263 ValEntry *e_0008_0016 = FileInternal->GetValEntry(0x0008, 0x0016);
1264 if ( e_0008_0016 != 0 )
1266 // Create 'Source Image Sequence' SeqEntry
1267 SeqEntry *sis = new SeqEntry (
1268 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
1269 SQItem *sqi = new SQItem(1);
1270 // (we assume 'SOP Instance UID' exists too)
1271 // create 'Referenced SOP Class UID'
1272 ValEntry *e_0008_1150 = new ValEntry(
1273 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
1274 e_0008_1150->SetValue( e_0008_0016->GetValue());
1275 sqi->AddEntry(e_0008_1150);
1277 // create 'Referenced SOP Instance UID'
1278 ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018);
1279 ValEntry *e_0008_1155 = new ValEntry(
1280 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
1281 e_0008_1155->SetValue( e_0008_0018->GetValue());
1282 sqi->AddEntry(e_0008_1155);
1284 sis->AddSQItem(sqi,1);
1285 // temporarily replaces any previous 'Source Image Sequence'
1288 // 'Image Type' (The written image is no longer an 'ORIGINAL' one)
1289 ValEntry *e_0008_0008 = CopyValEntry(0x0008,0x0008);
1290 e_0008_0008->SetValue("DERIVED\\PRIMARY");
1291 Archive->Push(e_0008_0008);
1295 // There was no 'SOP Class UID'.
1296 // the source image was NOT a true Dicom one.
1297 // We consider the image is a 'Secondary Capture' one
1299 e_0008_0016 = new ValEntry(
1300 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) );
1301 // [Secondary Capture Image Storage]
1302 e_0008_0016 ->SetValue("1.2.840.10008.5.1.4.1.1.7");
1303 Archive->Push(e_0008_0016);
1306 // ---- The user will never have to take any action on the following ----.
1308 // new value for 'SOP Instance UID'
1309 ValEntry *e_0008_0018 = new ValEntry(
1310 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0018) );
1311 e_0008_0018->SetValue( Util::CreateUniqueUID() );
1312 Archive->Push(e_0008_0018);
1314 // Instance Creation Date
1315 ValEntry *e_0008_0012 = CopyValEntry(0x0008,0x0012);
1316 std::string date = Util::GetCurrentDate();
1317 e_0008_0012->SetValue(date.c_str());
1318 Archive->Push(e_0008_0012);
1320 // Instance Creation Time
1321 ValEntry *e_0008_0013 = CopyValEntry(0x0008,0x0013);
1322 std::string time = Util::GetCurrentTime();
1323 e_0008_0013->SetValue(time.c_str());
1324 Archive->Push(e_0008_0013);
1326 // ----- Add Mandatory Entries if missing ---
1328 // Entries whose type is 1 are mandatory, with a mandatory value
1329 // Entries whose type is 1c are mandatory-inside-a-Sequence
1330 // Entries whose type is 2 are mandatory, with a optional value
1331 // Entries whose type is 2c are mandatory-inside-a-Sequence
1332 // Entries whose type is 3 are optional
1334 // 'Serie Instance UID'
1335 // Keep the value if exists
1336 // The user is allowed to create his own Series,
1337 // keeping the same 'Serie Instance UID' for various images
1338 // The user shouldn't add any image to a 'Manufacturer Serie'
1339 // but there is no way no to allowed him to do that
1340 ValEntry *e_0020_000e = FileInternal->GetValEntry(0x0020, 0x000e);
1343 e_0020_000e = new ValEntry(
1344 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000e) );
1345 e_0020_000e->SetValue(Util::CreateUniqueUID() );
1346 Archive->Push(e_0020_000e);
1349 // 'Study Instance UID'
1350 // Keep the value if exists
1351 // The user is allowed to create his own Study,
1352 // keeping the same 'Study Instance UID' for various images
1353 // The user may add images to a 'Manufacturer Study',
1354 // adding new series to an already existing Study
1355 ValEntry *e_0020_000d = FileInternal->GetValEntry(0x0020, 0x000d);
1358 e_0020_000d = new ValEntry(
1359 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000d) );
1360 e_0020_000d->SetValue(Util::CreateUniqueUID() );
1361 Archive->Push(e_0020_000d);
1364 // Modality : if missing we set it to 'OTher'
1365 ValEntry *e_0008_0060 = FileInternal->GetValEntry(0x0008, 0x0060);
1368 e_0008_0060 = new ValEntry(
1369 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0060) );
1370 e_0008_0060->SetValue("OT");
1371 Archive->Push(e_0008_0060);
1374 // Manufacturer : if missing we set it to 'GDCM Factory'
1375 ValEntry *e_0008_0070 = FileInternal->GetValEntry(0x0008, 0x0070);
1378 e_0008_0070 = new ValEntry(
1379 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0070) );
1380 e_0008_0070->SetValue("GDCM Factory");
1381 Archive->Push(e_0008_0070);
1384 // Institution Name : if missing we set it to 'GDCM Hospital'
1385 ValEntry *e_0008_0080 = FileInternal->GetValEntry(0x0008, 0x0080);
1388 e_0008_0080 = new ValEntry(
1389 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0080) );
1390 e_0008_0080->SetValue("GDCM Hospital");
1391 Archive->Push(e_0008_0080);
1394 // Patient's Name : if missing, we set it to 'GDCM^Patient'
1395 ValEntry *e_0010_0010 = FileInternal->GetValEntry(0x0010, 0x0010);
1398 e_0010_0010 = new ValEntry(
1399 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0010) );
1400 e_0010_0010->SetValue("GDCM^Patient");
1401 Archive->Push(e_0010_0010);
1404 // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
1405 ValEntry *e_0010_0030 = FileInternal->GetValEntry(0x0010, 0x0030);
1408 e_0010_0030 = new ValEntry(
1409 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0030) );
1410 e_0010_0030->SetValue("");
1411 Archive->Push(e_0010_0030);
1414 // Patient's Sex :'type 2' entry -> must exist, value not mandatory
1415 ValEntry *e_0010_0040 = FileInternal->GetValEntry(0x0010, 0x0040);
1418 e_0010_0040 = new ValEntry(
1419 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0040) );
1420 e_0010_0040->SetValue("");
1421 Archive->Push(e_0010_0040);
1424 // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
1425 ValEntry *e_0008_0090 = FileInternal->GetValEntry(0x0008, 0x0090);
1428 e_0008_0090 = new ValEntry(
1429 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0090) );
1430 e_0008_0090->SetValue("");
1431 Archive->Push(e_0008_0090);
1434 // Remove some inconstencies (probably some more will be added)
1436 // if (0028 0008)Number of Frames exists
1437 // Push out (0020 0052),Frame of Reference UID
1438 // (only meaningfull within a Serie)
1439 ValEntry *e_0028_0008 = FileInternal->GetValEntry(0x0028, 0x0008);
1442 Archive->Push(0x0020, 0X0052);
1447 * \brief Restore in the File the initial group 0002
1449 void FileHelper::RestoreWriteMandatory()
1451 // group 0002 may be pushed out for ACR-NEMA writting purposes
1452 Archive->Restore(0x0002,0x0000);
1453 Archive->Restore(0x0002,0x0001);
1454 Archive->Restore(0x0002,0x0002);
1455 Archive->Restore(0x0002,0x0003);
1456 Archive->Restore(0x0002,0x0010);
1457 Archive->Restore(0x0002,0x0012);
1458 Archive->Restore(0x0002,0x0013);
1459 Archive->Restore(0x0002,0x0016);
1460 Archive->Restore(0x0002,0x0100);
1461 Archive->Restore(0x0002,0x0102);
1463 Archive->Restore(0x0008,0x0012);
1464 Archive->Restore(0x0008,0x0013);
1465 Archive->Restore(0x0008,0x0016);
1466 Archive->Restore(0x0008,0x0018);
1467 Archive->Restore(0x0008,0x0060);
1468 Archive->Restore(0x0008,0x0070);
1469 Archive->Restore(0x0008,0x0080);
1470 Archive->Restore(0x0008,0x0090);
1471 Archive->Restore(0x0008,0x2112);
1473 Archive->Restore(0x0010,0x0010);
1474 Archive->Restore(0x0010,0x0030);
1475 Archive->Restore(0x0010,0x0040);
1477 Archive->Restore(0x0020,0x000d);
1478 Archive->Restore(0x0020,0x000e);
1482 //-----------------------------------------------------------------------------
1485 * \brief Factorization for various forms of constructors.
1487 void FileHelper::Initialize()
1489 WriteMode = WMODE_RAW;
1490 WriteType = ExplicitVR;
1492 PixelReadConverter = new PixelReadConvert;
1493 PixelWriteConverter = new PixelWriteConvert;
1494 Archive = new DocEntryArchive( FileInternal );
1496 if ( FileInternal->IsReadable() )
1498 PixelReadConverter->GrabInformationsFromFile( FileInternal );
1503 * \brief Reads/[decompresses] the pixels,
1504 * *without* making RGB from Palette Colors
1505 * @return the pixels area, whatever its type
1506 * (uint8_t is just for prototyping : feel free to Cast it)
1508 uint8_t *FileHelper::GetRaw()
1510 uint8_t *raw = PixelReadConverter->GetRaw();
1513 // The Raw image migth not be loaded yet:
1514 std::ifstream *fp = FileInternal->OpenFile();
1515 PixelReadConverter->ReadAndDecompressPixelData( fp );
1517 FileInternal->CloseFile();
1519 raw = PixelReadConverter->GetRaw();
1522 gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
1529 //-----------------------------------------------------------------------------
1531 * \brief Prints the common part of ValEntry, BinEntry, SeqEntry
1532 * @param os ostream we want to print in
1533 * @param indent (unused)
1535 void FileHelper::Print(std::ostream &os, std::string const &)
1537 FileInternal->SetPrintLevel(PrintLevel);
1538 FileInternal->Print(os);
1540 PixelReadConverter->SetPrintLevel(PrintLevel);
1541 PixelReadConverter->Print(os);
1544 #ifndef GDCM_LEGACY_REMOVE
1547 * Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
1548 * file (gdcm::File only deals with the ... header)
1549 * Opens (in read only and when possible) an existing file and checks
1550 * for DICOM compliance. Returns NULL on failure.
1551 * It will be up to the user to load the pixels into memory
1552 * \note the in-memory representation of all available tags found in
1553 * the DICOM header is post-poned to first header information access.
1554 * This avoid a double parsing of public part of the header when
1555 * one sets an a posteriori shadow dictionary (efficiency can be
1556 * seen as a side effect).
1557 * @param filename file to be opened for parsing
1558 * @deprecated use SetFilename() + Load() methods
1560 FileHelper::FileHelper(std::string const &filename )
1562 FileInternal = new File( filename );
1567 //-----------------------------------------------------------------------------
1568 } // end namespace gdcm