X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmFileHelper.cxx;h=7183e58967f6c7fd83d8e7bfc12c31993673edb3;hb=ffaf0119eb35e6a5b8460036fbaf6fa7e701e0cc;hp=12bfe7cf5767b985b32f67fefb479b996c5527cf;hpb=17ebda2271dd65565f512e835546b22c22ebbbb0;p=gdcm.git diff --git a/src/gdcmFileHelper.cxx b/src/gdcmFileHelper.cxx index 12bfe7cf..7183e589 100644 --- a/src/gdcmFileHelper.cxx +++ b/src/gdcmFileHelper.cxx @@ -4,8 +4,8 @@ Module: $RCSfile: gdcmFileHelper.cxx,v $ Language: C++ - Date: $Date: 2006/04/11 16:03:26 $ - Version: $Revision: 1.99 $ + Date: $Date: 2006/10/18 13:40:18 $ + Version: $Revision: 1.110 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -269,9 +269,10 @@ bool FileHelper::SetEntryBinArea(uint8_t *content, int lgth, * failed). */ DataEntry *FileHelper::InsertEntryString(std::string const &content, - uint16_t group, uint16_t elem) + uint16_t group, uint16_t elem, + VRKey const &vr ) { - return FileInternal->InsertEntryString(content, group, elem); + return FileInternal->InsertEntryString(content, group, elem, vr); } /** @@ -282,13 +283,15 @@ DataEntry *FileHelper::InsertEntryString(std::string const &content, * @param lgth new value length * @param group Group number of the Entry * @param elem Element number of the Entry + * @param vr Value Represenation of the DataElement to be inserted * \return pointer to the modified/created DataEntry (NULL when creation * failed). */ DataEntry *FileHelper::InsertEntryBinArea(uint8_t *binArea, int lgth, - uint16_t group, uint16_t elem) + uint16_t group, uint16_t elem, + VRKey const &vr ) { - return FileInternal->InsertEntryBinArea(binArea, lgth, group, elem); + return FileInternal->InsertEntryBinArea(binArea, lgth, group, elem, vr); } /** @@ -389,7 +392,7 @@ uint8_t *FileHelper::GetImageDataRaw () return GetRaw(); } -#ifndef GDCM_LEGACY_REMOVE +//#ifndef GDCM_LEGACY_REMOVE /* * \brief Useless function, since PixelReadConverter forces us * copy the Pixels anyway. @@ -416,6 +419,7 @@ uint8_t *FileHelper::GetImageDataRaw () * @return On success, the number of bytes actually copied. Zero on * failure e.g. MaxSize is lower than necessary. */ + /* size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize) { if ( ! GetRaw() ) @@ -448,7 +452,8 @@ size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize) PixelReadConverter->GetRawSize() ); return PixelReadConverter->GetRawSize(); } -#endif +*/ +//#endif /** * \brief Points the internal pointer to the callers inData @@ -703,7 +708,7 @@ bool FileHelper::Write(std::string const &fileName) } break; - SetWriteFileTypeToExplicitVR(); // to see JPRx + SetWriteFileTypeToExplicitVR(); // to see JPRx break; case ACR: case ACR_LIBIDO: @@ -724,8 +729,12 @@ bool FileHelper::Write(std::string const &fileName) case JPEG: SetWriteFileTypeToJPEG(); break; + + case JPEG2000: + SetWriteFileTypeToJPEG2000(); + break; } - + // -------------------------------------------------------------- // Special Patch to allow gdcm to re-write ACR-LibIDO formated images // @@ -756,7 +765,7 @@ bool FileHelper::Write(std::string const &fileName) } bool check = CheckWriteIntegrity(); // verifies length - if (WriteType == JPEG ) check = true; + if (WriteType == JPEG || WriteType == JPEG2000) check = true; if (check) { check = FileInternal->Write(fileName,WriteType); @@ -869,6 +878,11 @@ void FileHelper::SetWriteToRaw() vr = "OW"; if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files vr = "OB"; + // For non RAW data. Mainly JPEG + if( WriteType == JPEG || WriteType == JPEG2000) + { + vr = "OW"; + } DataEntry *pixel = CopyDataEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr); pixel->SetFlag(DataEntry::FLAG_PIXELDATA); @@ -1040,6 +1054,21 @@ void FileHelper::SetWriteFileTypeToACR() Archive->Push(0x0002,0x0102); } + /** + * \brief Sets in the File the TransferSyntax to 'JPEG2000' + */ +void FileHelper::SetWriteFileTypeToJPEG2000() +{ + std::string ts = Util::DicomString( + Global::GetTS()->GetSpecialTransferSyntax(TS::JPEG2000Lossless) ); + + DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI"); + tss->SetString(ts); + + Archive->Push(tss); + tss->Delete(); +} + /** * \brief Sets in the File the TransferSyntax to 'JPEG' */ @@ -1237,11 +1266,12 @@ We have to deal with 4 *very* different cases : USER_OWN_IMAGE -2) user modified the pixels of an existing image. FILTERED_IMAGE --3) user created a new image, using existing images (eg MIP, MPR, cartography image) +-3) user created a new image, using a set of existing images (eg MIP, MPR, cartography image) CREATED_IMAGE -4) user modified/added some tags *without processing* the pixels (anonymization.. UNMODIFIED_PIXELS_IMAGE - +-Probabely some more to be added + gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases. 1)2)3)4) @@ -1385,6 +1415,11 @@ void FileHelper::CheckMandatoryElements() //0002 0016 AE 1 Source Application Entity Title //0002 0100 UI 1 Private Information Creator //0002 0102 OB 1 Private Information + + // Push out 'ACR-NEMA-special' entries, if any + Archive->Push(0x0008,0x0001); // Length to End + Archive->Push(0x0008,0x0010); // Recognition Code + Archive->Push(0x0028,0x0005); // Image Dimension // Create them if not found // Always modify the value @@ -1485,13 +1520,26 @@ void FileHelper::CheckMandatoryElements() // It's *not* an image comming straight from a source. We force // 'Media Storage SOP Class UID' --> [Secondary Capture Image Storage] CopyMandatoryEntry(0x0008,0x0016,"1.2.840.10008.5.1.4.1.1.7", "UI"); - } - + } + + Archive->Push(0x0028,0x005); // [Image Dimensions (RET) // Push out 'LibIDO-special' entries, if any Archive->Push(0x0028,0x0015); Archive->Push(0x0028,0x0016); Archive->Push(0x0028,0x0017); - Archive->Push(0x0028,0x00199); + Archive->Push(0x0028,0x0198); // very old versions + Archive->Push(0x0028,0x0199); + + // Replace deprecated 0028 0012 US Planes + // by new 0028 0008 IS Number of Frames + + ///\todo : find if there is a rule! + DataEntry *e_0028_0012 = FileInternal->GetDataEntry(0x0028, 0x0012); + if ( e_0028_0012 ) + { + CopyMandatoryEntry(0x0028, 0x0008,e_0028_0012->GetString(),"IS"); + Archive->Push(0x0028,0x0012); + } // Deal with the pb of (Bits Stored = 12) // - we're gonna write the image as Bits Stored = 16 @@ -1505,7 +1553,8 @@ void FileHelper::CheckMandatoryElements() std::ostringstream s; // check 'Bits Allocated' vs decent values int nbBitsAllocated = FileInternal->GetBitsAllocated(); - if ( nbBitsAllocated == 0 || nbBitsAllocated > 32) + if ( nbBitsAllocated == 0 || nbBitsAllocated > 32 + || ( nbBitsAllocated > 8 && nbBitsAllocated <16) ) { CopyMandatoryEntry(0x0028,0x0100,"16","US"); gdcmWarningMacro("(0028,0100) changed from " @@ -1538,6 +1587,24 @@ void FileHelper::CheckMandatoryElements() << " for consistency purpose"); } + // check Pixel Representation (default it as 0 -unsigned-) + + DataEntry *e_0028_0103 = FileInternal->GetDataEntry(0x0028, 0x0103); + if ( !e_0028_0103 ) + { + gdcmWarningMacro("PixelRepresentation (0028,0103) is supposed to be mandatory"); + CopyMandatoryEntry(0x0028, 0x0103,"0","US"); + } + else + { + int sign = (int)e_0028_0103->GetValue(0); + if (sign !=1 && sign !=0) + { + gdcmWarningMacro("PixelRepresentation (0028,0103) is supposed to be =1 or =0"); + CopyMandatoryEntry(0x0028, 0x0103,"0","US"); + } + } + std::string pixelSpacing = FileInternal->GetEntryString(0x0028,0x0030); if ( pixelSpacing == GDCM_UNFOUND ) { @@ -1552,7 +1619,56 @@ void FileHelper::CheckMandatoryElements() // we write it only when we are *sure* the image comes from // an imager (see also 0008,0x0064) CheckMandatoryEntry(0x0018,0x1164,pixelSpacing,"DS"); + + + +/* +///Exact meaning of RETired fields + +// See page 73 of ACR-NEMA_300-1988.pdf ! + +// 0020,0020 : Patient Orientation : +Patient direction of the first row and +column of the images. The first entry id the direction of the raws, given by the +direction of the last pixel in the first row from the first pixel in tha row. +the second entry is the direction of the columns, given by the direction of the +last pixel in the first column from the first pixel in that column. +L : Left, F : Feet, A : Anterior, P : Posterior. +Up to 3 letters can be used in combination to indicate oblique planes. + +//0020,0030 Image Position (RET) +x,y,z coordinates im mm of the first pixel in the image + +// 0020,0035 Image Orientation (RET) +Direction cosines of the R axis of the image system with respect to the +equipment coordinate axes x,y,z, followed by direction cosines of the C axis of +the image system with respect to the same axes + +//0020,0050 Location +An image location reference, standard for the modality (such as CT bed +position), used to indicate position. Calculation of position for other purposes +is only from (0020,0030) and (0020,0035) +*/ + +/* +// if imagePositionPatient not found, default it with imagePositionRet, if any +// if imageOrientationPatient not found, default it with imageOrientationRet, if any + + std::string imagePositionRet = FileInternal->GetEntryString(0x0020,0x0030); + std::string imageOrientationRet = FileInternal->GetEntryString(0x0020,0x0035); + std::string imagePositionPatient = FileInternal->GetEntryString(0x0020,0x0032); + std::string imageOrientationPatient = FileInternal->GetEntryString(0x0020,0x0037); + if( imagePositionPatient == GDCM_UNFOUND && imageOrientationPatient == GDCM_UNFOUND + && imagePositionRet != GDCM_UNFOUND && imageOrientationRet != GDCM_UNFOUND) + { + CopyMandatoryEntry(0x0020, 0x0032,imagePositionRet,"DS"); + Archive->Push(0x0020,0x0030); + CopyMandatoryEntry(0x0020, 0x0037,imageOrientationRet,"DS"); + Archive->Push(0x0020,0x0035); + } +*/ + // Samples Per Pixel (type 1) : default to grayscale CheckMandatoryEntry(0x0028,0x0002,"1","US"); @@ -1671,8 +1787,8 @@ void FileHelper::CheckMandatoryElements() // Patient's Name : if missing, we set it to 'GDCM^Patient' CheckMandatoryEntry(0x0010,0x0010,"GDCM^Patient","PN"); - // Patient ID - CheckMandatoryEntry(0x0010,0x0020,"","LO"); + // Patient ID : some clinical softwares *demand* it although it's a 'type 2' entry. + CheckMandatoryEntry(0x0010,0x0020,"gdcm ID","LO"); // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory CheckMandatoryEntry(0x0010,0x0030,"","DA"); @@ -1867,3 +1983,155 @@ void FileHelper::Print(std::ostream &os, std::string const &) //----------------------------------------------------------------------------- } // end namespace gdcm + + +/* Probabely something to be added to use Rescale Slope/Intercept +Have a look ,at ITK code ! + +// Internal function to rescale pixel according to Rescale Slope/Intercept +template +void RescaleFunction(TBuffer* buffer, TSource *source, + double slope, double intercept, size_t size) +{ + size /= sizeof(TSource); + + if (slope != 1.0 && intercept != 0.0) + { + // Duff's device. Instead of this code: + // + // for(unsigned int i=0; i 0); + } + } + else if (slope == 1.0 && intercept != 0.0) + { + // Duff's device. Instead of this code: + // + // for(unsigned int i=0; i 0); + } + } + else if (slope != 1.0 && intercept == 0.0) + { + // Duff's device. Instead of this code: + // + // for(unsigned int i=0; i 0); + } + } + else + { + // Duff's device. Instead of this code: + // + // for(unsigned int i=0; i 0); + } + } + + +} + + +template +void RescaleFunction(ImageIOBase::IOComponentType bufferType, + void* buffer, TSource *source, + double slope, double intercept, size_t size) +{ + switch (bufferType) + { + case ImageIOBase::UCHAR: + RescaleFunction( (unsigned char *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::CHAR: + RescaleFunction( (char *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::USHORT: + RescaleFunction( (unsigned short *)buffer, source, slope, intercept,size); + break; + case ImageIOBase::SHORT: + RescaleFunction( (short *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::UINT: + RescaleFunction( (unsigned int *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::INT: + RescaleFunction( (int *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::FLOAT: + RescaleFunction( (float *)buffer, source, slope, intercept, size); + break; + case ImageIOBase::DOUBLE: + RescaleFunction( (double *)buffer, source, slope, intercept, size); + break; + default: + ::itk::OStringStream message; + message << "itk::ERROR: GDCMImageIO: Unknown component type : " << bufferType; + ::itk::ExceptionObject e(__FILE__, __LINE__, message.str().c_str(),ITK_LOCATION); + throw e; + } +} +*/