X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmFileHelper.cxx;h=0bf7bf7d11f499ad4859da40f8853edfe54b1e18;hb=34e322ceb4e12797e6d4cb1e691a36425015d2e0;hp=583a619297edf04e7c93673f42596f9ae82416d3;hpb=408fab710453f393e745037b04ae8aec68509b87;p=gdcm.git diff --git a/src/gdcmFileHelper.cxx b/src/gdcmFileHelper.cxx index 583a6192..0bf7bf7d 100644 --- a/src/gdcmFileHelper.cxx +++ b/src/gdcmFileHelper.cxx @@ -4,8 +4,8 @@ Module: $RCSfile: gdcmFileHelper.cxx,v $ Language: C++ - Date: $Date: 2005/04/19 12:31:56 $ - Version: $Revision: 1.34 $ + Date: $Date: 2005/07/23 01:59:21 $ + Version: $Revision: 1.50 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -145,25 +145,6 @@ FileHelper::FileHelper(File *header) Initialize(); } -/** - * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 - * file (gdcm::File only deals with the ... header) - * Opens (in read only and when possible) an existing file and checks - * for DICOM compliance. Returns NULL on failure. - * It will be up to the user to load the pixels into memory - * \note the in-memory representation of all available tags found in - * the DICOM header is post-poned to first header information access. - * This avoid a double parsing of public part of the header when - * one sets an a posteriori shadow dictionary (efficiency can be - * seen as a side effect). - * @param filename file to be opened for parsing - */ -FileHelper::FileHelper(std::string const &filename ) -{ - FileInternal = new File( filename ); - SelfHeader = true; - Initialize(); -} /** * \brief canonical destructor @@ -172,20 +153,20 @@ FileHelper::FileHelper(std::string const &filename ) */ FileHelper::~FileHelper() { - if( PixelReadConverter ) + if ( PixelReadConverter ) { delete PixelReadConverter; } - if( PixelWriteConverter ) + if ( PixelWriteConverter ) { delete PixelWriteConverter; } - if( Archive ) + if ( Archive ) { delete Archive; } - if( SelfHeader ) + if ( SelfHeader ) { delete FileInternal; } @@ -194,6 +175,39 @@ FileHelper::~FileHelper() //----------------------------------------------------------------------------- // Public + +/** + * \brief Sets the LoadMode of the internal gdcm::File as a boolean string. + * NO_SEQ, NO_SHADOW, NO_SHADOWSEQ + *... (nothing more, right now) + * WARNING : before using NO_SHADOW, be sure *all* your files + * contain accurate values in the 0x0000 element (if any) + * of *each* Shadow Group. The parser will fail if the size is wrong ! + * @param loadMode Load mode to be used + */ +void FileHelper::SetLoadMode(int loadMode) +{ + GetFile()->SetLoadMode( loadMode ); +} +/** + * \brief Sets the LoadMode of the internal gdcm::File + * @param fileName name of the file to be open + */ +void FileHelper::SetFileName(std::string const &fileName) +{ + FileInternal->SetFileName( fileName ); +} + +/** + * \brief Loader + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool FileHelper::Load() +{ + return FileInternal->Load(); +} + /** * \brief Accesses an existing DocEntry (i.e. a Dicom Element) * through it's (group, element) and modifies it's content with @@ -238,7 +252,7 @@ bool FileHelper::SetBinEntry(uint8_t *content, int lgth, ValEntry *FileHelper::InsertValEntry(std::string const &content, uint16_t group, uint16_t elem) { - return FileInternal->InsertValEntry(content,group,elem); + return FileInternal->InsertValEntry(content, group, elem); } /** @@ -285,7 +299,6 @@ size_t FileHelper::GetImageDataSize() { return PixelWriteConverter->GetUserDataSize(); } - return PixelReadConverter->GetRGBSize(); } @@ -302,7 +315,6 @@ size_t FileHelper::GetImageDataRawSize() { return PixelWriteConverter->GetUserDataSize(); } - return PixelReadConverter->GetRawSize(); } @@ -407,7 +419,7 @@ size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize) return 0; } memcpy( destination, - (void*)PixelReadConverter->GetRaw(), + (void *)PixelReadConverter->GetRaw(), PixelReadConverter->GetRawSize() ); return PixelReadConverter->GetRawSize(); } @@ -502,9 +514,27 @@ size_t FileHelper::GetRawDataSize() */ uint8_t* FileHelper::GetLutRGBA() { + if ( PixelReadConverter->GetLutRGBA() ==0 ) + PixelReadConverter->BuildLUTRGBA(); return PixelReadConverter->GetLutRGBA(); } +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number + */ +int FileHelper::GetLutItemNumber() +{ + return PixelReadConverter->GetLutItemNumber(); +} + +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size + */ +int FileHelper::GetLutItemSize() +{ + return PixelReadConverter->GetLutItemSize(); +} + /** * \brief Writes on disk A SINGLE Dicom file * NO test is performed on processor "Endiannity". @@ -522,19 +552,19 @@ bool FileHelper::WriteRawData(std::string const &fileName) return false; } - if( PixelWriteConverter->GetUserData() ) + if ( PixelWriteConverter->GetUserData() ) { - fp1.write( (char*)PixelWriteConverter->GetUserData(), + fp1.write( (char *)PixelWriteConverter->GetUserData(), PixelWriteConverter->GetUserDataSize() ); } else if ( PixelReadConverter->GetRGB() ) { - fp1.write( (char*)PixelReadConverter->GetRGB(), + fp1.write( (char *)PixelReadConverter->GetRGB(), PixelReadConverter->GetRGBSize()); } else if ( PixelReadConverter->GetRaw() ) { - fp1.write( (char*)PixelReadConverter->GetRaw(), + fp1.write( (char *)PixelReadConverter->GetRaw(), PixelReadConverter->GetRawSize()); } else @@ -550,7 +580,7 @@ bool FileHelper::WriteRawData(std::string const &fileName) /** * \brief Writes on disk A SINGLE Dicom file, * using the Implicit Value Representation convention - * NO test is performed on processor "Endiannity". + * NO test is performed on processor "Endianity". * @param fileName name of the file to be created * (any already existing file is overwritten) * @return false if write fails @@ -609,28 +639,26 @@ bool FileHelper::Write(std::string const &fileName) { case ImplicitVR: SetWriteFileTypeToImplicitVR(); - CheckMandatoryElements(); break; case Unknown: // should never happen; ExplicitVR is the default value case ExplicitVR: SetWriteFileTypeToExplicitVR(); - CheckMandatoryElements(); break; case ACR: case ACR_LIBIDO: - // Just to avoid further trouble if user create a file ex-nihilo, + // NOTHING is done here just for LibIDO. + // Just to avoid further trouble if user creates a file ex-nihilo, // wants to write it as an ACR-NEMA file, - // and forget to create any Entry belonging to group 0008 + // and forgets to create any Entry belonging to group 0008 // (shame on him !) // We add Recognition Code (RET) if ( ! FileInternal->GetValEntry(0x0008, 0x0010) ) FileInternal->InsertValEntry("", 0x0008, 0x0010); SetWriteFileTypeToACR(); - SetWriteFileTypeToImplicitVR(); - CheckMandatoryElements(); + // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR ! break; - } + CheckMandatoryElements(); // -------------------------------------------------------------- // Special Patch to allow gdcm to re-write ACR-LibIDO formated images @@ -641,7 +669,7 @@ bool FileHelper::Write(std::string const &fileName) /// \todo the best trick would be *change* the recognition code /// but pb expected if user deals with, e.g. COMPLEX images - if( WriteType == ACR_LIBIDO ) + if ( WriteType == ACR_LIBIDO ) { SetWriteToLibido(); } @@ -662,7 +690,7 @@ bool FileHelper::Write(std::string const &fileName) } bool check = CheckWriteIntegrity(); // verifies length - if(check) + if (check) { check = FileInternal->Write(fileName,WriteType); } @@ -694,27 +722,30 @@ bool FileHelper::Write(std::string const &fileName) */ bool FileHelper::CheckWriteIntegrity() { - if(PixelWriteConverter->GetUserData()) + if ( PixelWriteConverter->GetUserData() ) { int numberBitsAllocated = FileInternal->GetBitsAllocated(); if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 ) { + gdcmWarningMacro( "numberBitsAllocated changed from " + << numberBitsAllocated << " to 16 " + << " for consistency purpose" ); numberBitsAllocated = 16; } size_t decSize = FileInternal->GetXSize() - * FileInternal->GetYSize() - * FileInternal->GetZSize() - * ( numberBitsAllocated / 8 ) - * FileInternal->GetSamplesPerPixel(); + * FileInternal->GetYSize() + * FileInternal->GetZSize() + * FileInternal->GetSamplesPerPixel() + * ( numberBitsAllocated / 8 ); size_t rgbSize = decSize; - if( FileInternal->HasLUT() ) + if ( FileInternal->HasLUT() ) rgbSize = decSize * 3; switch(WriteMode) { case WMODE_RAW : - if( decSize!=PixelWriteConverter->GetUserDataSize() ) + if ( decSize!=PixelWriteConverter->GetUserDataSize() ) { gdcmWarningMacro( "Data size (Raw) is incorrect. Should be " << decSize << " / Found :" @@ -723,7 +754,7 @@ bool FileHelper::CheckWriteIntegrity() } break; case WMODE_RGB : - if( rgbSize!=PixelWriteConverter->GetUserDataSize() ) + if ( rgbSize!=PixelWriteConverter->GetUserDataSize() ) { gdcmWarningMacro( "Data size (RGB) is incorrect. Should be " << decSize << " / Found " @@ -732,8 +763,7 @@ bool FileHelper::CheckWriteIntegrity() } break; } - } - + } return true; } @@ -744,15 +774,15 @@ bool FileHelper::CheckWriteIntegrity() */ void FileHelper::SetWriteToRaw() { - if( FileInternal->GetNumberOfScalarComponents() == 3 - && !FileInternal->HasLUT()) + if ( FileInternal->GetNumberOfScalarComponents() == 3 + && !FileInternal->HasLUT() ) { SetWriteToRGB(); } else { ValEntry *photInt = CopyValEntry(0x0028,0x0004); - if(FileInternal->HasLUT()) + if (FileInternal->HasLUT() ) { photInt->SetValue("PALETTE COLOR "); } @@ -765,9 +795,9 @@ void FileHelper::SetWriteToRaw() PixelReadConverter->GetRawSize()); std::string vr = "OB"; - if( FileInternal->GetBitsAllocated()>8 ) + if ( FileInternal->GetBitsAllocated()>8 ) vr = "OW"; - if( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files + if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files vr = "OB"; BinEntry *pixel = CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr); @@ -789,7 +819,7 @@ void FileHelper::SetWriteToRaw() */ void FileHelper::SetWriteToRGB() { - if(FileInternal->GetNumberOfScalarComponents()==3) + if ( FileInternal->GetNumberOfScalarComponents()==3 ) { PixelReadConverter->BuildRGBImage(); @@ -802,7 +832,7 @@ void FileHelper::SetWriteToRGB() ValEntry *photInt = CopyValEntry(0x0028,0x0004); photInt->SetValue("RGB "); - if(PixelReadConverter->GetRGB()) + if ( PixelReadConverter->GetRGB() ) { PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(), PixelReadConverter->GetRGBSize()); @@ -814,9 +844,9 @@ void FileHelper::SetWriteToRGB() } std::string vr = "OB"; - if( FileInternal->GetBitsAllocated()>8 ) + if ( FileInternal->GetBitsAllocated()>8 ) vr = "OW"; - if( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files + if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files vr = "OB"; BinEntry *pixel = CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr); @@ -837,10 +867,13 @@ void FileHelper::SetWriteToRGB() Archive->Push(0x0028,0x1202); Archive->Push(0x0028,0x1203); + // push out Palette Color Lookup Table UID, if any + Archive->Push(0x0028,0x1199); + // For old '24 Bits' ACR-NEMA // Thus, we have a RGB image and the bits allocated = 24 and // samples per pixels = 1 (in the read file) - if(FileInternal->GetBitsAllocated()==24) + if ( FileInternal->GetBitsAllocated()==24 ) { ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100); bitsAlloc->SetValue("8 "); @@ -885,6 +918,10 @@ void FileHelper::RestoreWrite() Archive->Restore(0x0028,0x1202); Archive->Restore(0x0028,0x1203); + // For the Palette Color Lookup Table UID + Archive->Restore(0x0028,0x1203); + + // group 0002 may be pushed out for ACR-NEMA writting purposes Archive->Restore(0x0002,0x0000); Archive->Restore(0x0002,0x0001); @@ -965,7 +1002,7 @@ void FileHelper::SetWriteToLibido() ValEntry *oldCol = dynamic_cast (FileInternal->GetDocEntry(0x0028, 0x0011)); - if( oldRow && oldCol ) + if ( oldRow && oldCol ) { std::string rows, columns; @@ -994,9 +1031,9 @@ void FileHelper::SetWriteToNoLibido() { ValEntry *recCode = dynamic_cast (FileInternal->GetDocEntry(0x0008,0x0010)); - if( recCode ) + if ( recCode ) { - if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" ) + if ( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" ) { ValEntry *libidoCode = CopyValEntry(0x0008,0x0010); libidoCode->SetValue(""); @@ -1032,7 +1069,7 @@ ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem) DocEntry *oldE = FileInternal->GetDocEntry(group, elem); ValEntry *newE; - if( oldE ) + if ( oldE ) { newE = new ValEntry(oldE->GetDictEntry()); newE->Copy(oldE); @@ -1059,11 +1096,11 @@ BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem, DocEntry *oldE = FileInternal->GetDocEntry(group, elem); BinEntry *newE; - if( oldE ) - if( oldE->GetVR()!=vr ) + if ( oldE ) + if ( oldE->GetVR()!=vr ) oldE = NULL; - if( oldE ) + if ( oldE ) { newE = new BinEntry(oldE->GetDictEntry()); newE->Copy(oldE); @@ -1105,7 +1142,10 @@ BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem, void FileHelper::CheckMandatoryElements() { // just to remember : 'official' 0002 group - + if ( WriteType != ACR && WriteType != ACR_LIBIDO ) + { + // Group 000002 (Meta Elements) already pushed out + //0002 0000 UL 1 Meta Group Length //0002 0001 OB 1 File Meta Information Version //0002 0002 UI 1 Media Stored SOP Class UID @@ -1120,41 +1160,42 @@ void FileHelper::CheckMandatoryElements() // Create them if not found // Always modify the value // Push the entries to the archive. - ValEntry *e_0002_0000 = CopyValEntry(0x0002,0x0000); + ValEntry *e_0002_0000 = CopyValEntry(0x0002,0x0000); e_0002_0000->SetValue("0"); // for the moment Archive->Push(e_0002_0000); - BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB"); + BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB"); e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(), false); e_0002_0001->SetLength(2); Archive->Push(e_0002_0001); // 'Media Stored SOP Class UID' - ValEntry *e_0002_0002 = CopyValEntry(0x0002,0x0002); + ValEntry *e_0002_0002 = CopyValEntry(0x0002,0x0002); // [Secondary Capture Image Storage] e_0002_0002->SetValue("1.2.840.10008.5.1.4.1.1.7"); Archive->Push(e_0002_0002); // 'Media Stored SOP Instance UID' - ValEntry *e_0002_0003 = CopyValEntry(0x0002,0x0003); + ValEntry *e_0002_0003 = CopyValEntry(0x0002,0x0003); e_0002_0003->SetValue(Util::CreateUniqueUID()); Archive->Push(e_0002_0003); // 'Implementation Class UID' - ValEntry *e_0002_0012 = CopyValEntry(0x0002,0x0012); + ValEntry *e_0002_0012 = CopyValEntry(0x0002,0x0012); e_0002_0012->SetValue(Util::CreateUniqueUID()); Archive->Push(e_0002_0012); // 'Implementation Version Name' - ValEntry *e_0002_0013 = CopyValEntry(0x0002,0x0013); - e_0002_0013->SetValue("GDCM 1.0"); + ValEntry *e_0002_0013 = CopyValEntry(0x0002,0x0013); + e_0002_0013->SetValue("GDCM 1.1"); Archive->Push(e_0002_0013); //'Source Application Entity Title' Not Mandatory //ValEntry *e_0002_0016 = CopyValEntry(0x0002,0x0016); // e_0002_0016->SetValue("1.2.840.10008.5.1.4.1.1.7"); // Archive->Push(e_0002_0016); + } // Push out 'LibIDO-special' entries, if any Archive->Push(0x0028,0x0015); @@ -1162,7 +1203,58 @@ void FileHelper::CheckMandatoryElements() Archive->Push(0x0028,0x0017); Archive->Push(0x0028,0x00199); - // --- Check UID-related Entries --- + // Deal with the pb of (Bits Stored = 12) + // - we're gonna write the image as Bits Stored = 16 + if ( FileInternal->GetEntryValue(0x0028,0x0100) == "12") + { + ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100); + e_0028_0100->SetValue("16"); + Archive->Push(e_0028_0100); + } + + // Check if user wasn't drunk ;-) + + std::ostringstream s; + // check 'Bits Allocated' vs decent values + int nbBitsAllocated = FileInternal->GetBitsAllocated(); + if ( nbBitsAllocated == 0 || nbBitsAllocated > 32) + { + ValEntry *e_0028_0100 = CopyValEntry(0x0028,0x0100); + e_0028_0100->SetValue("16"); + Archive->Push(e_0028_0100); + gdcmWarningMacro("(0028,0100) changed from " + << nbBitsAllocated << " to 16 for consistency purpose"); + nbBitsAllocated = 16; + } + // check 'Bits Stored' vs 'Bits Allocated' + int nbBitsStored = FileInternal->GetBitsStored(); + if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated ) + { + s << nbBitsAllocated; + ValEntry *e_0028_0101 = CopyValEntry(0x0028,0x0101); + e_0028_0101->SetValue( s.str() ); + Archive->Push(e_0028_0101); + gdcmWarningMacro("(0028,0101) changed from " + << nbBitsStored << " to " << nbBitsAllocated + << " for consistency purpose" ); + nbBitsStored = nbBitsAllocated; + } + // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored' + int highBitPosition = FileInternal->GetHighBitPosition(); + if ( highBitPosition == 0 || + highBitPosition > nbBitsAllocated-1 || + highBitPosition < nbBitsStored-1 ) + { + ValEntry *e_0028_0102 = CopyValEntry(0x0028,0x0102); + + s << nbBitsStored - 1; + e_0028_0102->SetValue( s.str() ); + Archive->Push(e_0028_0102); + gdcmWarningMacro("(0028,0102) changed from " + << highBitPosition << " to " << nbBitsAllocated-1 + << " for consistency purpose"); + } + // --- Check UID-related Entries --- // If 'SOP Class UID' exists ('true DICOM' image) // we create the 'Source Image Sequence' SeqEntry @@ -1172,7 +1264,7 @@ void FileHelper::CheckMandatoryElements() if ( e_0008_0016 != 0 ) { // Create 'Source Image Sequence' SeqEntry - SeqEntry *s = new SeqEntry ( + SeqEntry *sis = new SeqEntry ( Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) ); SQItem *sqi = new SQItem(1); // (we assume 'SOP Instance UID' exists too) @@ -1189,9 +1281,9 @@ void FileHelper::CheckMandatoryElements() e_0008_1155->SetValue( e_0008_0018->GetValue()); sqi->AddEntry(e_0008_1155); - s->AddSQItem(sqi,1); + sis->AddSQItem(sqi,1); // temporarily replaces any previous 'Source Image Sequence' - Archive->Push(s); + Archive->Push(sis); // 'Image Type' (The written image is no longer an 'ORIGINAL' one) ValEntry *e_0008_0008 = CopyValEntry(0x0008,0x0008); @@ -1361,11 +1453,30 @@ void FileHelper::RestoreWriteMandatory() Archive->Restore(0x0002,0x0001); Archive->Restore(0x0002,0x0002); Archive->Restore(0x0002,0x0003); + Archive->Restore(0x0002,0x0010); Archive->Restore(0x0002,0x0012); Archive->Restore(0x0002,0x0013); Archive->Restore(0x0002,0x0016); Archive->Restore(0x0002,0x0100); Archive->Restore(0x0002,0x0102); + + Archive->Restore(0x0008,0x0012); + Archive->Restore(0x0008,0x0013); + Archive->Restore(0x0008,0x0016); + Archive->Restore(0x0008,0x0018); + Archive->Restore(0x0008,0x0060); + Archive->Restore(0x0008,0x0070); + Archive->Restore(0x0008,0x0080); + Archive->Restore(0x0008,0x0090); + Archive->Restore(0x0008,0x2112); + + Archive->Restore(0x0010,0x0010); + Archive->Restore(0x0010,0x0030); + Archive->Restore(0x0010,0x0040); + + Archive->Restore(0x0020,0x000d); + Archive->Restore(0x0020,0x000e); + } //----------------------------------------------------------------------------- @@ -1402,7 +1513,7 @@ uint8_t *FileHelper::GetRaw() // The Raw image migth not be loaded yet: std::ifstream *fp = FileInternal->OpenFile(); PixelReadConverter->ReadAndDecompressPixelData( fp ); - if(fp) + if ( fp ) FileInternal->CloseFile(); raw = PixelReadConverter->GetRaw(); @@ -1412,7 +1523,6 @@ uint8_t *FileHelper::GetRaw() return 0; } } - return raw; } @@ -1431,5 +1541,30 @@ void FileHelper::Print(std::ostream &os, std::string const &) PixelReadConverter->Print(os); } +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief + * Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (gdcm::File only deals with the ... header) + * Opens (in read only and when possible) an existing file and checks + * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * \note the in-memory representation of all available tags found in + * the DICOM header is post-poned to first header information access. + * This avoid a double parsing of public part of the header when + * one sets an a posteriori shadow dictionary (efficiency can be + * seen as a side effect). + * @param filename file to be opened for parsing + * @deprecated use SetFilename() + Load() methods + */ +FileHelper::FileHelper(std::string const &filename ) +{ + FileInternal = new File( ); + FileInternal->SetFileName( filename ); + FileInternal->Load(); + SelfHeader = true; + Initialize(); +} +#endif //----------------------------------------------------------------------------- } // end namespace gdcm