1 /*=========================================================================
4 Module: $RCSfile: gdcmFileHelper.cxx,v $
7 Date: $Date: 2005/08/19 13:12:15 $
8 Version: $Revision: 1.52 $
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 ()
369 #ifndef GDCM_LEGACY_REMOVE
371 * \brief Useless function, since PixelReadConverter forces us
372 * copy the Pixels anyway.
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 at most MaxSize bytes of pixel data to caller allocated
379 * \warning This function allows people that want to build a volume
380 * from an image stack *not to* have, first to get the image pixels,
381 * and then move them to the volume area.
382 * It's absolutely useless for any VTK user since vtk chooses
383 * to invert the lines of an image, that is the last line comes first
384 * (for some axis related reasons?). Hence he will have
385 * to load the image line by line, starting from the end.
386 * VTK users have to call GetImageData
388 * @param destination Address (in caller's memory space) at which the
389 * pixel data should be copied
390 * @param maxSize Maximum number of bytes to be copied. When MaxSize
391 * is not sufficient to hold the pixel data the copy is not
392 * executed (i.e. no partial copy).
393 * @return On success, the number of bytes actually copied. Zero on
394 * failure e.g. MaxSize is lower than necessary.
396 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
400 // If the decompression failed nothing can be done.
404 if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
406 if ( PixelReadConverter->GetRGBSize() > maxSize )
408 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
412 (void*)PixelReadConverter->GetRGB(),
413 PixelReadConverter->GetRGBSize() );
414 return PixelReadConverter->GetRGBSize();
417 // Either no LUT conversion necessary or LUT conversion failed
418 if ( PixelReadConverter->GetRawSize() > maxSize )
420 gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
424 (void *)PixelReadConverter->GetRaw(),
425 PixelReadConverter->GetRawSize() );
426 return PixelReadConverter->GetRawSize();
431 * \brief Points the internal pointer to the callers inData
432 * image representation, BUT WITHOUT COPYING THE DATA.
433 * 'image' Pixels are presented as C-like 2D arrays : line per line.
434 * 'volume'Pixels are presented as C-like 3D arrays : plane per plane
435 * \warning Since the pixels are not copied, it is the caller's responsability
436 * not to deallocate its data before gdcm uses them (e.g. with
437 * the Write() method )
438 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
439 * user is allowed to pass any kind of pixelsn since the size is
441 * @param expectedSize total image size, *in Bytes*
443 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
445 SetUserData(inData, expectedSize);
449 * \brief Set the image data defined by the user
450 * \warning When writting the file, this data are get as default data to write
451 * @param inData user supplied pixel area (uint8_t* is just for the compiler.
452 * user is allowed to pass any kind of pixels since the size is
454 * @param expectedSize total image size, *in Bytes*
456 void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
458 PixelWriteConverter->SetUserData(inData, expectedSize);
462 * \brief Get the image data defined by the user
463 * \warning When writting the file, this data are get as default data to write
465 uint8_t *FileHelper::GetUserData()
467 return PixelWriteConverter->GetUserData();
471 * \brief Get the image data size defined by the user
472 * \warning When writting the file, this data are get as default data to write
474 size_t FileHelper::GetUserDataSize()
476 return PixelWriteConverter->GetUserDataSize();
480 * \brief Get the image data from the file.
481 * If a LUT is found, the data are expanded to be RGB
483 uint8_t *FileHelper::GetRGBData()
485 return PixelReadConverter->GetRGB();
489 * \brief Get the image data size from the file.
490 * If a LUT is found, the data are expanded to be RGB
492 size_t FileHelper::GetRGBDataSize()
494 return PixelReadConverter->GetRGBSize();
498 * \brief Get the image data from the file.
499 * Even when a LUT is found, the data are not expanded to RGB!
501 uint8_t *FileHelper::GetRawData()
503 return PixelReadConverter->GetRaw();
507 * \brief Get the image data size from the file.
508 * Even when a LUT is found, the data are not expanded to RGB!
510 size_t FileHelper::GetRawDataSize()
512 return PixelReadConverter->GetRawSize();
516 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT
518 uint8_t* FileHelper::GetLutRGBA()
520 if ( PixelReadConverter->GetLutRGBA() ==0 )
521 PixelReadConverter->BuildLUTRGBA();
522 return PixelReadConverter->GetLutRGBA();
526 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number
528 int FileHelper::GetLutItemNumber()
530 return PixelReadConverter->GetLutItemNumber();
534 * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size
536 int FileHelper::GetLutItemSize()
538 return PixelReadConverter->GetLutItemSize();
542 * \brief Writes on disk A SINGLE Dicom file
543 * NO test is performed on processor "Endiannity".
544 * It's up to the user to call his Reader properly
545 * @param fileName name of the file to be created
546 * (any already existing file is over written)
547 * @return false if write fails
549 bool FileHelper::WriteRawData(std::string const &fileName)
551 std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
554 gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str());
558 if ( PixelWriteConverter->GetUserData() )
560 fp1.write( (char *)PixelWriteConverter->GetUserData(),
561 PixelWriteConverter->GetUserDataSize() );
563 else if ( PixelReadConverter->GetRGB() )
565 fp1.write( (char *)PixelReadConverter->GetRGB(),
566 PixelReadConverter->GetRGBSize());
568 else if ( PixelReadConverter->GetRaw() )
570 fp1.write( (char *)PixelReadConverter->GetRaw(),
571 PixelReadConverter->GetRawSize());
575 gdcmErrorMacro( "Nothing written." );
584 * \brief Writes on disk A SINGLE Dicom file,
585 * using the Implicit Value Representation convention
586 * NO test is performed on processor "Endianity".
587 * @param fileName name of the file to be created
588 * (any already existing file is overwritten)
589 * @return false if write fails
592 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
594 SetWriteTypeToDcmImplVR();
595 return Write(fileName);
599 * \brief Writes on disk A SINGLE Dicom file,
600 * using the Explicit Value Representation convention
601 * NO test is performed on processor "Endiannity".
602 * @param fileName name of the file to be created
603 * (any already existing file is overwritten)
604 * @return false if write fails
607 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
609 SetWriteTypeToDcmExplVR();
610 return Write(fileName);
614 * \brief Writes on disk A SINGLE Dicom file,
615 * using the ACR-NEMA convention
616 * NO test is performed on processor "Endiannity".
617 * (a l'attention des logiciels cliniques
618 * qui ne prennent en entrée QUE des images ACR ...
619 * \warning if a DICOM_V3 header is supplied,
620 * groups < 0x0008 and shadow groups are ignored
621 * \warning NO TEST is performed on processor "Endiannity".
622 * @param fileName name of the file to be created
623 * (any already existing file is overwritten)
624 * @return false if write fails
627 bool FileHelper::WriteAcr (std::string const &fileName)
630 return Write(fileName);
634 * \brief Writes on disk A SINGLE Dicom file,
635 * @param fileName name of the file to be created
636 * (any already existing file is overwritten)
637 * @return false if write fails
639 bool FileHelper::Write(std::string const &fileName)
644 SetWriteFileTypeToImplicitVR();
646 case Unknown: // should never happen; ExplicitVR is the default value
648 SetWriteFileTypeToExplicitVR();
652 // NOTHING is done here just for LibIDO.
653 // Just to avoid further trouble if user creates a file ex-nihilo,
654 // wants to write it as an ACR-NEMA file,
655 // and forgets to create any Entry belonging to group 0008
657 // We add Recognition Code (RET)
658 if ( ! FileInternal->GetValEntry(0x0008, 0x0010) )
659 FileInternal->InsertValEntry("", 0x0008, 0x0010);
660 SetWriteFileTypeToACR();
661 // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR !
664 CheckMandatoryElements();
666 // --------------------------------------------------------------
667 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
669 // if recognition code tells us we dealt with a LibIDO image
670 // we reproduce on disk the switch between lineNumber and columnNumber
671 // just before writting ...
672 /// \todo the best trick would be *change* the recognition code
673 /// but pb expected if user deals with, e.g. COMPLEX images
675 if ( WriteType == ACR_LIBIDO )
681 SetWriteToNoLibido();
683 // ----------------- End of Special Patch ----------------
688 SetWriteToRaw(); // modifies and pushes to the archive, when necessary
691 SetWriteToRGB(); // modifies and pushes to the archive, when necessary
695 bool check = CheckWriteIntegrity(); // verifies length
698 check = FileInternal->Write(fileName,WriteType);
702 RestoreWriteFileType();
703 RestoreWriteMandatory();
705 // --------------------------------------------------------------
706 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
708 // ...and we restore the header to be Dicom Compliant again
709 // just after writting
710 RestoreWriteOfLibido();
711 // ----------------- End of Special Patch ----------------
716 //-----------------------------------------------------------------------------
719 * \brief Checks the write integrity
721 * The tests made are :
722 * - verify the size of the image to write with the possible write
723 * when the user set an image data
724 * @return true if check is successfull
726 bool FileHelper::CheckWriteIntegrity()
728 if ( PixelWriteConverter->GetUserData() )
730 int numberBitsAllocated = FileInternal->GetBitsAllocated();
731 if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
733 gdcmWarningMacro( "numberBitsAllocated changed from "
734 << numberBitsAllocated << " to 16 "
735 << " for consistency purpose" );
736 numberBitsAllocated = 16;
739 size_t decSize = FileInternal->GetXSize()
740 * FileInternal->GetYSize()
741 * FileInternal->GetZSize()
742 * FileInternal->GetSamplesPerPixel()
743 * ( numberBitsAllocated / 8 );
744 size_t rgbSize = decSize;
745 if ( FileInternal->HasLUT() )
746 rgbSize = decSize * 3;
751 if ( decSize!=PixelWriteConverter->GetUserDataSize() )
753 gdcmWarningMacro( "Data size (Raw) is incorrect. Should be "
754 << decSize << " / Found :"
755 << PixelWriteConverter->GetUserDataSize() );
760 if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
762 gdcmWarningMacro( "Data size (RGB) is incorrect. Should be "
763 << decSize << " / Found "
764 << PixelWriteConverter->GetUserDataSize() );
774 * \brief Updates the File to write RAW data (as opposed to RGB data)
775 * (modifies, when necessary, photochromatic interpretation,
776 * bits allocated, Pixels element VR)
778 void FileHelper::SetWriteToRaw()
780 if ( FileInternal->GetNumberOfScalarComponents() == 3
781 && !FileInternal->HasLUT() )
787 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
788 if (FileInternal->HasLUT() )
790 photInt->SetValue("PALETTE COLOR ");
794 photInt->SetValue("MONOCHROME2 ");
797 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
798 PixelReadConverter->GetRawSize());
800 std::string vr = "OB";
801 if ( FileInternal->GetBitsAllocated()>8 )
803 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
806 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
807 pixel->SetValue(GDCM_BINLOADED);
808 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
809 pixel->SetLength(PixelWriteConverter->GetDataSize());
811 Archive->Push(photInt);
812 Archive->Push(pixel);
817 * \brief Updates the File to write RGB data (as opposed to RAW data)
818 * (modifies, when necessary, photochromatic interpretation,
819 * samples per pixel, Planar configuration,
820 * bits allocated, bits stored, high bit -ACR 24 bits-
821 * Pixels element VR, pushes out the LUT, )
823 void FileHelper::SetWriteToRGB()
825 if ( FileInternal->GetNumberOfScalarComponents()==3 )
827 PixelReadConverter->BuildRGBImage();
829 ValEntry *spp = CopyValEntry(0x0028,0x0002);
832 ValEntry *planConfig = CopyValEntry(0x0028,0x0006);
833 planConfig->SetValue("0 ");
835 ValEntry *photInt = CopyValEntry(0x0028,0x0004);
836 photInt->SetValue("RGB ");
838 if ( PixelReadConverter->GetRGB() )
840 PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
841 PixelReadConverter->GetRGBSize());
845 PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
846 PixelReadConverter->GetRawSize());
849 std::string vr = "OB";
850 if ( FileInternal->GetBitsAllocated()>8 )
852 if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files
855 CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
856 pixel->SetValue(GDCM_BINLOADED);
857 pixel->SetBinArea(PixelWriteConverter->GetData(),false);
858 pixel->SetLength(PixelWriteConverter->GetDataSize());
861 Archive->Push(planConfig);
862 Archive->Push(photInt);
863 Archive->Push(pixel);
866 Archive->Push(0x0028,0x1101);
867 Archive->Push(0x0028,0x1102);
868 Archive->Push(0x0028,0x1103);
869 Archive->Push(0x0028,0x1201);
870 Archive->Push(0x0028,0x1202);
871 Archive->Push(0x0028,0x1203);
873 // push out Palette Color Lookup Table UID, if any
874 Archive->Push(0x0028,0x1199);
876 // For old '24 Bits' ACR-NEMA
877 // Thus, we have a RGB image and the bits allocated = 24 and
878 // samples per pixels = 1 (in the read file)
879 if ( FileInternal->GetBitsAllocated()==24 )
881 ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100);
882 bitsAlloc->SetValue("8 ");
884 ValEntry *bitsStored = CopyValEntry(0x0028,0x0101);
885 bitsStored->SetValue("8 ");
887 ValEntry *highBit = CopyValEntry(0x0028,0x0102);
888 highBit->SetValue("7 ");
890 Archive->Push(bitsAlloc);
891 Archive->Push(bitsStored);
892 Archive->Push(highBit);
902 * \brief Restore the File write mode
904 void FileHelper::RestoreWrite()
906 Archive->Restore(0x0028,0x0002);
907 Archive->Restore(0x0028,0x0004);
908 Archive->Restore(0x0028,0x0006);
909 Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
911 // For old ACR-NEMA (24 bits problem)
912 Archive->Restore(0x0028,0x0100);
913 Archive->Restore(0x0028,0x0101);
914 Archive->Restore(0x0028,0x0102);
917 Archive->Restore(0x0028,0x1101);
918 Archive->Restore(0x0028,0x1102);
919 Archive->Restore(0x0028,0x1103);
920 Archive->Restore(0x0028,0x1201);
921 Archive->Restore(0x0028,0x1202);
922 Archive->Restore(0x0028,0x1203);
924 // For the Palette Color Lookup Table UID
925 Archive->Restore(0x0028,0x1203);
928 // group 0002 may be pushed out for ACR-NEMA writting purposes
929 Archive->Restore(0x0002,0x0000);
930 Archive->Restore(0x0002,0x0001);
931 Archive->Restore(0x0002,0x0002);
932 Archive->Restore(0x0002,0x0003);
933 Archive->Restore(0x0002,0x0010);
934 Archive->Restore(0x0002,0x0012);
935 Archive->Restore(0x0002,0x0013);
936 Archive->Restore(0x0002,0x0016);
937 Archive->Restore(0x0002,0x0100);
938 Archive->Restore(0x0002,0x0102);
942 * \brief Pushes out the whole group 0002
943 * FIXME : better, set a flag to tell the writer not to write it ...
944 * FIXME : method should probably have an other name !
945 * SetWriteFileTypeToACR is NOT opposed to
946 * SetWriteFileTypeToExplicitVR and SetWriteFileTypeToImplicitVR
948 void FileHelper::SetWriteFileTypeToACR()
950 Archive->Push(0x0002,0x0000);
951 Archive->Push(0x0002,0x0001);
952 Archive->Push(0x0002,0x0002);
953 Archive->Push(0x0002,0x0003);
954 Archive->Push(0x0002,0x0010);
955 Archive->Push(0x0002,0x0012);
956 Archive->Push(0x0002,0x0013);
957 Archive->Push(0x0002,0x0016);
958 Archive->Push(0x0002,0x0100);
959 Archive->Push(0x0002,0x0102);
963 * \brief Sets in the File the TransferSyntax to 'Explicit VR Little Endian"
965 void FileHelper::SetWriteFileTypeToExplicitVR()
967 std::string ts = Util::DicomString(
968 Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
970 ValEntry *tss = CopyValEntry(0x0002,0x0010);
977 * \brief Sets in the File the TransferSyntax to 'Implicit VR Little Endian"
979 void FileHelper::SetWriteFileTypeToImplicitVR()
981 std::string ts = Util::DicomString(
982 Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
984 ValEntry *tss = CopyValEntry(0x0002,0x0010);
992 * \brief Restore in the File the initial group 0002
994 void FileHelper::RestoreWriteFileType()
999 * \brief Set the Write not to Libido format
1001 void FileHelper::SetWriteToLibido()
1003 ValEntry *oldRow = dynamic_cast<ValEntry *>
1004 (FileInternal->GetDocEntry(0x0028, 0x0010));
1005 ValEntry *oldCol = dynamic_cast<ValEntry *>
1006 (FileInternal->GetDocEntry(0x0028, 0x0011));
1008 if ( oldRow && oldCol )
1010 std::string rows, columns;
1012 ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
1013 ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
1015 newRow->Copy(oldCol);
1016 newCol->Copy(oldRow);
1018 newRow->SetValue(oldCol->GetValue());
1019 newCol->SetValue(oldRow->GetValue());
1021 Archive->Push(newRow);
1022 Archive->Push(newCol);
1025 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1026 libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
1027 Archive->Push(libidoCode);
1031 * \brief Set the Write not to No Libido format
1033 void FileHelper::SetWriteToNoLibido()
1035 ValEntry *recCode = dynamic_cast<ValEntry *>
1036 (FileInternal->GetDocEntry(0x0008,0x0010));
1039 if ( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
1041 ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
1042 libidoCode->SetValue("");
1043 Archive->Push(libidoCode);
1049 * \brief Restore the Write format
1051 void FileHelper::RestoreWriteOfLibido()
1053 Archive->Restore(0x0028,0x0010);
1054 Archive->Restore(0x0028,0x0011);
1055 Archive->Restore(0x0008,0x0010);
1057 // Restore 'LibIDO-special' entries, if any
1058 Archive->Restore(0x0028,0x0015);
1059 Archive->Restore(0x0028,0x0016);
1060 Archive->Restore(0x0028,0x0017);
1061 Archive->Restore(0x0028,0x00199);
1065 * \brief Duplicates a ValEntry or creates it.
1066 * @param group Group number of the Entry
1067 * @param elem Element number of the Entry
1068 * \return pointer to the new Val Entry (NULL when creation failed).
1070 ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem)
1072 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1077 newE = new ValEntry(oldE->GetDictEntry());
1082 newE = GetFile()->NewValEntry(group, elem);
1089 * \brief Duplicates a BinEntry or creates it.
1090 * @param group Group number of the Entry
1091 * @param elem Element number of the Entry
1092 * @param vr Value Representation of the Entry
1093 * FIXME : what is it used for?
1094 * \return pointer to the new Bin Entry (NULL when creation failed).
1096 BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem,
1097 const std::string &vr)
1099 DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
1103 if ( oldE->GetVR()!=vr )
1108 newE = new BinEntry(oldE->GetDictEntry());
1113 newE = GetFile()->NewBinEntry(group, elem, vr);
1120 * \brief This method is called automatically, just before writting
1121 * in order to produce a 'True Dicom V3' image
1122 * We cannot know *how* the user made the File (reading an old ACR-NEMA
1123 * file or a not very clean DICOM file ...)
1125 * Just before writting :
1126 * - we check the Entries
1127 * - we create the mandatory entries if they are missing
1128 * - we modify the values if necessary
1129 * - we push the sensitive entries to the Archive
1130 * The writing process will restore the entries as they where before
1131 * entering FileHelper::CheckMandatoryElements, so the user will always
1132 * see the entries just as he left them.
1134 * \todo : - warn the user if we had to add some entries :
1135 * even if a mandatory entry is missing, we add it, with a default value
1136 * (we don't want to give up the writting process if user forgot to
1137 * specify Lena's Patient ID, for instance ...)
1138 * - read the whole PS 3.3 Part of DICOM (890 pages)
1139 * and write a *full* checker (probably one method per Modality ...)
1140 * Any contribution is welcome.
1141 * - write a user callable full checker, to allow post reading
1142 * and/or pre writting image consistency check.
1145 void FileHelper::CheckMandatoryElements()
1147 // just to remember : 'official' 0002 group
1148 if ( WriteType != ACR && WriteType != ACR_LIBIDO )
1150 // Group 000002 (Meta Elements) already pushed out
1152 //0002 0000 UL 1 Meta Group Length
1153 //0002 0001 OB 1 File Meta Information Version
1154 //0002 0002 UI 1 Media Stored SOP Class UID
1155 //0002 0003 UI 1 Media Stored SOP Instance UID
1156 //0002 0010 UI 1 Transfer Syntax UID
1157 //0002 0012 UI 1 Implementation Class UID
1158 //0002 0013 SH 1 Implementation Version Name
1159 //0002 0016 AE 1 Source Application Entity Title
1160 //0002 0100 UI 1 Private Information Creator
1161 //0002 0102 OB 1 Private Information
1163 // Create them if not found
1164 // Always modify the value
1165 // Push the entries to the archive.
1166 ValEntry *e_0002_0000 = CopyValEntry(0x0002,0x0000);
1167 e_0002_0000->SetValue("0"); // for the moment
1168 Archive->Push(e_0002_0000);
1170 BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB");
1171 e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(),
1173 e_0002_0001->SetLength(2);
1174 Archive->Push(e_0002_0001);
1176 // 'Media Stored SOP Class UID'
1177 ValEntry *e_0002_0002 = CopyValEntry(0x0002,0x0002);
1178 // [Secondary Capture Image Storage]
1179 e_0002_0002->SetValue("1.2.840.10008.5.1.4.1.1.7");
1180 Archive->Push(e_0002_0002);
1182 // 'Media Stored SOP Instance UID'
1183 ValEntry *e_0002_0003 = CopyValEntry(0x0002,0x0003);
1184 e_0002_0003->SetValue(Util::CreateUniqueUID());
1185 Archive->Push(e_0002_0003);
1187 // 'Implementation Class UID'
1188 ValEntry *e_0002_0012 = CopyValEntry(0x0002,0x0012);
1189 e_0002_0012->SetValue(Util::CreateUniqueUID());
1190 Archive->Push(e_0002_0012);
1192 // 'Implementation Version Name'
1193 ValEntry *e_0002_0013 = CopyValEntry(0x0002,0x0013);
1194 e_0002_0013->SetValue("GDCM 1.1");
1195 Archive->Push(e_0002_0013);
1197 //'Source Application Entity Title' Not Mandatory
1198 //ValEntry *e_0002_0016 = CopyValEntry(0x0002,0x0016);
1199 // e_0002_0016->SetValue("1.2.840.10008.5.1.4.1.1.7");
1200 // Archive->Push(e_0002_0016);
1203 // Push out 'LibIDO-special' entries, if any
1204 Archive->Push(0x0028,0x0015);
1205 Archive->Push(0x0028,0x0016);
1206 Archive->Push(0x0028,0x0017);
1207 Archive->Push(0x0028,0x00199);
1209 // Deal with the pb of (Bits Stored = 12)
1210 // - we're gonna write the image as Bits Stored = 16
1211 if ( FileInternal->GetEntryValue(0x0028,0x0100) == "12")
1213 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1214 e_0028_0100->SetValue("16");
1215 Archive->Push(e_0028_0100);
1218 // Check if user wasn't drunk ;-)
1220 std::ostringstream s;
1221 // check 'Bits Allocated' vs decent values
1222 int nbBitsAllocated = FileInternal->GetBitsAllocated();
1223 if ( nbBitsAllocated == 0 || nbBitsAllocated > 32)
1225 ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100);
1226 e_0028_0100->SetValue("16");
1227 Archive->Push(e_0028_0100);
1228 gdcmWarningMacro("(0028,0100) changed from "
1229 << nbBitsAllocated << " to 16 for consistency purpose");
1230 nbBitsAllocated = 16;
1232 // check 'Bits Stored' vs 'Bits Allocated'
1233 int nbBitsStored = FileInternal->GetBitsStored();
1234 if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
1236 s << nbBitsAllocated;
1237 ValEntry *e_0028_0101 = CopyValEntry(0x0028,0x0101);
1238 e_0028_0101->SetValue( s.str() );
1239 Archive->Push(e_0028_0101);
1240 gdcmWarningMacro("(0028,0101) changed from "
1241 << nbBitsStored << " to " << nbBitsAllocated
1242 << " for consistency purpose" );
1243 nbBitsStored = nbBitsAllocated;
1245 // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
1246 int highBitPosition = FileInternal->GetHighBitPosition();
1247 if ( highBitPosition == 0 ||
1248 highBitPosition > nbBitsAllocated-1 ||
1249 highBitPosition < nbBitsStored-1 )
1251 ValEntry *e_0028_0102 = CopyValEntry(0x0028,0x0102);
1253 s << nbBitsStored - 1;
1254 e_0028_0102->SetValue( s.str() );
1255 Archive->Push(e_0028_0102);
1256 gdcmWarningMacro("(0028,0102) changed from "
1257 << highBitPosition << " to " << nbBitsAllocated-1
1258 << " for consistency purpose");
1260 // --- Check UID-related Entries ---
1262 // If 'SOP Class UID' exists ('true DICOM' image)
1263 // we create the 'Source Image Sequence' SeqEntry
1264 // to hold informations about the Source Image
1266 ValEntry *e_0008_0016 = FileInternal->GetValEntry(0x0008, 0x0016);
1267 if ( e_0008_0016 != 0 )
1269 // Create 'Source Image Sequence' SeqEntry
1270 SeqEntry *sis = new SeqEntry (
1271 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
1272 SQItem *sqi = new SQItem(1);
1273 // (we assume 'SOP Instance UID' exists too)
1274 // create 'Referenced SOP Class UID'
1275 ValEntry *e_0008_1150 = new ValEntry(
1276 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
1277 e_0008_1150->SetValue( e_0008_0016->GetValue());
1278 sqi->AddEntry(e_0008_1150);
1280 // create 'Referenced SOP Instance UID'
1281 ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018);
1282 ValEntry *e_0008_1155 = new ValEntry(
1283 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
1284 e_0008_1155->SetValue( e_0008_0018->GetValue());
1285 sqi->AddEntry(e_0008_1155);
1287 sis->AddSQItem(sqi,1);
1288 // temporarily replaces any previous 'Source Image Sequence'
1291 // 'Image Type' (The written image is no longer an 'ORIGINAL' one)
1292 ValEntry *e_0008_0008 = CopyValEntry(0x0008,0x0008);
1293 e_0008_0008->SetValue("DERIVED\\PRIMARY");
1294 Archive->Push(e_0008_0008);
1298 // There was no 'SOP Class UID'.
1299 // the source image was NOT a true Dicom one.
1300 // We consider the image is a 'Secondary Capture' one
1302 e_0008_0016 = new ValEntry(
1303 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) );
1304 // [Secondary Capture Image Storage]
1305 e_0008_0016 ->SetValue("1.2.840.10008.5.1.4.1.1.7");
1306 Archive->Push(e_0008_0016);
1309 // ---- The user will never have to take any action on the following ----.
1311 // new value for 'SOP Instance UID'
1312 ValEntry *e_0008_0018 = new ValEntry(
1313 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0018) );
1314 e_0008_0018->SetValue( Util::CreateUniqueUID() );
1315 Archive->Push(e_0008_0018);
1317 // Instance Creation Date
1318 ValEntry *e_0008_0012 = CopyValEntry(0x0008,0x0012);
1319 std::string date = Util::GetCurrentDate();
1320 e_0008_0012->SetValue(date.c_str());
1321 Archive->Push(e_0008_0012);
1323 // Instance Creation Time
1324 ValEntry *e_0008_0013 = CopyValEntry(0x0008,0x0013);
1325 std::string time = Util::GetCurrentTime();
1326 e_0008_0013->SetValue(time.c_str());
1327 Archive->Push(e_0008_0013);
1329 // ----- Add Mandatory Entries if missing ---
1331 // Entries whose type is 1 are mandatory, with a mandatory value
1332 // Entries whose type is 1c are mandatory-inside-a-Sequence
1333 // Entries whose type is 2 are mandatory, with a optional value
1334 // Entries whose type is 2c are mandatory-inside-a-Sequence
1335 // Entries whose type is 3 are optional
1337 // 'Serie Instance UID'
1338 // Keep the value if exists
1339 // The user is allowed to create his own Series,
1340 // keeping the same 'Serie Instance UID' for various images
1341 // The user shouldn't add any image to a 'Manufacturer Serie'
1342 // but there is no way no to allowed him to do that
1343 ValEntry *e_0020_000e = FileInternal->GetValEntry(0x0020, 0x000e);
1346 e_0020_000e = new ValEntry(
1347 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000e) );
1348 e_0020_000e->SetValue(Util::CreateUniqueUID() );
1349 Archive->Push(e_0020_000e);
1352 // 'Study Instance UID'
1353 // Keep the value if exists
1354 // The user is allowed to create his own Study,
1355 // keeping the same 'Study Instance UID' for various images
1356 // The user may add images to a 'Manufacturer Study',
1357 // adding new series to an already existing Study
1358 ValEntry *e_0020_000d = FileInternal->GetValEntry(0x0020, 0x000d);
1361 e_0020_000d = new ValEntry(
1362 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0020, 0x000d) );
1363 e_0020_000d->SetValue(Util::CreateUniqueUID() );
1364 Archive->Push(e_0020_000d);
1367 // Modality : if missing we set it to 'OTher'
1368 ValEntry *e_0008_0060 = FileInternal->GetValEntry(0x0008, 0x0060);
1371 e_0008_0060 = new ValEntry(
1372 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0060) );
1373 e_0008_0060->SetValue("OT");
1374 Archive->Push(e_0008_0060);
1377 // Manufacturer : if missing we set it to 'GDCM Factory'
1378 ValEntry *e_0008_0070 = FileInternal->GetValEntry(0x0008, 0x0070);
1381 e_0008_0070 = new ValEntry(
1382 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0070) );
1383 e_0008_0070->SetValue("GDCM Factory");
1384 Archive->Push(e_0008_0070);
1387 // Institution Name : if missing we set it to 'GDCM Hospital'
1388 ValEntry *e_0008_0080 = FileInternal->GetValEntry(0x0008, 0x0080);
1391 e_0008_0080 = new ValEntry(
1392 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0080) );
1393 e_0008_0080->SetValue("GDCM Hospital");
1394 Archive->Push(e_0008_0080);
1397 // Patient's Name : if missing, we set it to 'GDCM^Patient'
1398 ValEntry *e_0010_0010 = FileInternal->GetValEntry(0x0010, 0x0010);
1401 e_0010_0010 = new ValEntry(
1402 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0010) );
1403 e_0010_0010->SetValue("GDCM^Patient");
1404 Archive->Push(e_0010_0010);
1407 // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
1408 ValEntry *e_0010_0030 = FileInternal->GetValEntry(0x0010, 0x0030);
1411 e_0010_0030 = new ValEntry(
1412 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0030) );
1413 e_0010_0030->SetValue("");
1414 Archive->Push(e_0010_0030);
1417 // Patient's Sex :'type 2' entry -> must exist, value not mandatory
1418 ValEntry *e_0010_0040 = FileInternal->GetValEntry(0x0010, 0x0040);
1421 e_0010_0040 = new ValEntry(
1422 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0010, 0x0040) );
1423 e_0010_0040->SetValue("");
1424 Archive->Push(e_0010_0040);
1427 // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
1428 ValEntry *e_0008_0090 = FileInternal->GetValEntry(0x0008, 0x0090);
1431 e_0008_0090 = new ValEntry(
1432 Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0090) );
1433 e_0008_0090->SetValue("");
1434 Archive->Push(e_0008_0090);
1437 // Remove some inconstencies (probably some more will be added)
1439 // if (0028 0008)Number of Frames exists
1440 // Push out (0020 0052),Frame of Reference UID
1441 // (only meaningfull within a Serie)
1442 ValEntry *e_0028_0008 = FileInternal->GetValEntry(0x0028, 0x0008);
1445 Archive->Push(0x0020, 0X0052);
1450 * \brief Restore in the File the initial group 0002
1452 void FileHelper::RestoreWriteMandatory()
1454 // group 0002 may be pushed out for ACR-NEMA writting purposes
1455 Archive->Restore(0x0002,0x0000);
1456 Archive->Restore(0x0002,0x0001);
1457 Archive->Restore(0x0002,0x0002);
1458 Archive->Restore(0x0002,0x0003);
1459 Archive->Restore(0x0002,0x0010);
1460 Archive->Restore(0x0002,0x0012);
1461 Archive->Restore(0x0002,0x0013);
1462 Archive->Restore(0x0002,0x0016);
1463 Archive->Restore(0x0002,0x0100);
1464 Archive->Restore(0x0002,0x0102);
1466 Archive->Restore(0x0008,0x0012);
1467 Archive->Restore(0x0008,0x0013);
1468 Archive->Restore(0x0008,0x0016);
1469 Archive->Restore(0x0008,0x0018);
1470 Archive->Restore(0x0008,0x0060);
1471 Archive->Restore(0x0008,0x0070);
1472 Archive->Restore(0x0008,0x0080);
1473 Archive->Restore(0x0008,0x0090);
1474 Archive->Restore(0x0008,0x2112);
1476 Archive->Restore(0x0010,0x0010);
1477 Archive->Restore(0x0010,0x0030);
1478 Archive->Restore(0x0010,0x0040);
1480 Archive->Restore(0x0020,0x000d);
1481 Archive->Restore(0x0020,0x000e);
1485 //-----------------------------------------------------------------------------
1488 * \brief Factorization for various forms of constructors.
1490 void FileHelper::Initialize()
1494 WriteMode = WMODE_RAW;
1495 WriteType = ExplicitVR;
1497 PixelReadConverter = new PixelReadConvert;
1498 PixelWriteConverter = new PixelWriteConvert;
1499 Archive = new DocEntryArchive( FileInternal );
1501 if ( FileInternal->IsReadable() )
1503 PixelReadConverter->GrabInformationsFromFile( FileInternal );
1508 * \brief Reads/[decompresses] the pixels,
1509 * *without* making RGB from Palette Colors
1510 * @return the pixels area, whatever its type
1511 * (uint8_t is just for prototyping : feel free to Cast it)
1513 uint8_t *FileHelper::GetRaw()
1515 PixelReadConverter->SetUserFunction( UserFunction );
1517 uint8_t *raw = PixelReadConverter->GetRaw();
1520 // The Raw image migth not be loaded yet:
1521 std::ifstream *fp = FileInternal->OpenFile();
1522 PixelReadConverter->ReadAndDecompressPixelData( fp );
1524 FileInternal->CloseFile();
1526 raw = PixelReadConverter->GetRaw();
1529 gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
1536 //-----------------------------------------------------------------------------
1538 * \brief Prints the common part of ValEntry, BinEntry, SeqEntry
1539 * @param os ostream we want to print in
1540 * @param indent (unused)
1542 void FileHelper::Print(std::ostream &os, std::string const &)
1544 FileInternal->SetPrintLevel(PrintLevel);
1545 FileInternal->Print(os);
1547 PixelReadConverter->SetPrintLevel(PrintLevel);
1548 PixelReadConverter->Print(os);
1551 #ifndef GDCM_LEGACY_REMOVE
1553 * \brief DEPRECATED : use SetFilename() + Load() methods
1554 * Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
1555 * file (gdcm::File only deals with the ... header)
1556 * Opens (in read only and when possible) an existing file and checks
1557 * for DICOM compliance. Returns NULL on failure.
1558 * It will be up to the user to load the pixels into memory
1559 * \note the in-memory representation of all available tags found in
1560 * the DICOM header is post-poned to first header information access.
1561 * This avoid a double parsing of public part of the header when
1562 * one sets an a posteriori shadow dictionary (efficiency can be
1563 * seen as a side effect).
1564 * @param filename file to be opened for parsing
1565 * @deprecated use SetFilename() + Load() methods
1567 FileHelper::FileHelper(std::string const &filename )
1569 FileInternal = new File( );
1570 FileInternal->SetFileName( filename );
1571 FileInternal->Load();
1576 //-----------------------------------------------------------------------------
1577 } // end namespace gdcm