X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmFileHelper.cxx;h=2f54d3edc9579bb3a11f6306b7c40f93bdee9894;hb=66c8b2ef6c096d675afb963778604ed7ae72a78c;hp=62c0374010cd07b5e0f043fa57d3fac6ba34b8e8;hpb=1c4a6671c995962804086936a409bd0c8cb2b985;p=gdcm.git diff --git a/src/gdcmFileHelper.cxx b/src/gdcmFileHelper.cxx index 62c03740..2f54d3ed 100644 --- a/src/gdcmFileHelper.cxx +++ b/src/gdcmFileHelper.cxx @@ -4,8 +4,8 @@ Module: $RCSfile: gdcmFileHelper.cxx,v $ Language: C++ - Date: $Date: 2006/05/30 08:14:50 $ - Version: $Revision: 1.104 $ + Date: $Date: 2007/07/26 08:36:49 $ + Version: $Revision: 1.119 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -51,18 +51,19 @@ gdcm::File *f = new gdcm::File(fileName); // user may also decide he doesn't want to load some parts of the header gdcm::File *f = new gdcm::File(); f->SetFileName(fileName); - f->SetLoadMode(LD_NOSEQ); // or - f->SetLoadMode(LD_NOSHADOW); // or + f->SetLoadMode(LD_NOSEQ); // or + f->SetLoadMode(LD_NOSHADOW); // or f->SetLoadMode(LD_NOSEQ | LD_NOSHADOW); // or f->SetLoadMode(LD_NOSHADOWSEQ); f->Load(); +// To decide whether it's an 'image of interest for him, or not, // user can now check some values std::string v = f->GetEntryValue(groupNb,ElementNb); // to get the pixels, user needs a gdcm::FileHelper gdcm::FileHelper *fh = new gdcm::FileHelper(f); -// user may ask not to convert Palette to RGB +// user may ask not to convert Palette (if any) to RGB uint8_t *pixels = fh->GetImageDataRaw(); int imageLength = fh->GetImageDataRawSize(); // He can now use the pixels, create a new image, ... @@ -72,8 +73,11 @@ To re-write the image, user re-uses the gdcm::FileHelper fh->SetImageData( userPixels, userPixelsLength); fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB - // (WriteMode is set) - + // (WriteMode is set) + +// If user wants to write the file as MONOCHROME1 (0=white) +fh->SetPhotometricInterpretationToMonochrome1(); + fh->SetWriteTypeToDcmExpl(); // he wants Explicit Value Representation // Little Endian is the default // no other value is allowed @@ -91,33 +95,58 @@ These lines will be moved to the document-to-be 'Developer's Guide' WriteMode : WMODE_RAW / WMODE_RGB WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO +PhotometricInterpretation : MONOCHROME2 (0=black), MONOCHROME2 (0=white) + + +fh->SetWriteMode(WMODE_RAW / WMODE_RGB) -fh1->Write(newFileName); - SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR(); - (modifies TransferSyntax) +fh->SetWriteType( ImplicitVR/ExplicitVR/ACR/ACR_LIBIDO/JPEG/JPEG2000) + +fh->Write(newFileName); + CheckMandatoryElements(); // Checks existing ones / Add missing ones + Fix VR if unknown elements + SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR(); / + SetWriteFileTypeToACR() / SetWriteFileTypeToJPEG() / SetWriteFileTypeToJ2K() + (Modifies TransferSyntax if any; Pushes to the Archives old one) SetWriteToRaw(); / SetWriteToRGB(); - (modifies, when necessary : photochromatic interpretation, - samples per pixel, Planar configuration, - bits allocated, bits stored, high bit -ACR 24 bits- - Pixels element VR, pushes out the LUT ) + (Modifies and pushes to the Archive, when necessary : photochr. interp., + samples per pixel, Planar configuration, + bits allocated, bits stored, high bit -ACR 24 bits- + Pixels element VR, pushes out the LUT ) + SetWriteToRaw() + Sets Photometric Interpretation + DataEntry *pixel =CopyDataEntry(7fe0,0010,VR) + Sets VR, BinArea, Length for PixelData + if MONOCHROME1 + ConvertFixGreyLevels + Archive->Push(photInt); + Archive->Push(pixel); + photInt->Delete(); + pixel->Delete(); + SetWriteToRGB() + if NumberOfScalarComponents==1 + SetWriteToRaw(); return; + PixelReadConverter->BuildRGBImage() + DataEntry *pixel =CopyDataEntry(7fe0,0010,VR) + Archives spp, planConfig,photInt, pixel + Pushes out any LUT CheckWriteIntegrity(); (checks user given pixels length) FileInternal->Write(fileName,WriteType) - fp = opens file(fileName); - ComputeGroup0002Length( ); - BitsAllocated 12->16 - RemoveEntry(palettes, etc) + fp = opens file(fileName); // out|binary + ComputeGroup0002Length( ); Document::WriteContent(fp, writetype); + writes Dicom File Preamble not ACR-NEMA + ElementSet::WriteContent(fp, writetype); + writes recursively all DataElements RestoreWrite(); - (moves back to the File all the archived elements) - RestoreWriteFileType(); - (pushes back group 0002, with TransferSyntax) + (moves back to the gdcm::File all the archived elements) */ -namespace gdcm +namespace GDCM_NAME_SPACE { typedef std::map GroupHT; // Hash Table //------------------------------------------------------------------------- @@ -230,8 +259,8 @@ bool FileHelper::Load() } /** - * \brief Accesses an existing DataEntry through it's (group, element) - * and modifies it's content with the given value. + * \brief Accesses an existing DataEntry through its (group, element) + * and modifies its content with the given value. * @param content new value (string) to substitute with * @param group group number of the Dicom Element to modify * @param elem element number of the Dicom Element to modify @@ -245,8 +274,8 @@ bool FileHelper::SetEntryString(std::string const &content, /** - * \brief Accesses an existing DataEntry through it's (group, element) - * and modifies it's content with the given value. + * \brief Accesses an existing DataEntry through its (group, element) + * and modifies its content with the given value. * @param content new value (void* -> uint8_t*) to substitute with * @param lgth new value length * @param group group number of the Dicom Element to modify @@ -265,6 +294,7 @@ bool FileHelper::SetEntryBinArea(uint8_t *content, int lgth, * @param content (string) value to be set * @param group Group number of the Entry * @param elem Element number of the Entry + * @param vr Value Representation of the DataElement to be inserted * \return pointer to the modified/created DataEntry (NULL when creation * failed). */ @@ -279,10 +309,11 @@ DataEntry *FileHelper::InsertEntryString(std::string const &content, * \brief Modifies the value of a given DataEntry when it exists. * Creates it with the given value when unexistant. * A copy of the binArea is made to be kept in the Document. - * @param binArea (binary)value to be set + * @param binArea (binary) value to be set * @param lgth new value length * @param group Group number of the Entry * @param elem Element number of the Entry + * @param vr Value Representation of the DataElement to be inserted * \return pointer to the modified/created DataEntry (NULL when creation * failed). */ @@ -469,7 +500,7 @@ size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize) */ void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize) { - SetUserData(inData, expectedSize); + PixelWriteConverter->SetUserData(inData, expectedSize); } /** @@ -482,7 +513,18 @@ void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize) */ void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize) { - PixelWriteConverter->SetUserData(inData, expectedSize); + if( WriteType == JPEG2000 ) + { + PixelWriteConverter->SetCompressJPEG2000UserData(inData, expectedSize, FileInternal); + } + else if( WriteType == JPEG ) + { + PixelWriteConverter->SetCompressJPEGUserData(inData, expectedSize, FileInternal); + } + else + { + PixelWriteConverter->SetUserData(inData, expectedSize); + } } /** @@ -665,7 +707,6 @@ bool FileHelper::WriteAcr (std::string const &fileName) */ bool FileHelper::Write(std::string const &fileName) { - CheckMandatoryElements(); //called once, here ! bool flag = false; @@ -687,12 +728,15 @@ bool FileHelper::Write(std::string const &fileName) // Let's just *dream* about it; *never* trust a user ! // We turn to Implicit VR if at least the VR of one element is unknown. - + // Better we let DocEntry::WriteContent to put vr=UN for undocumented Shadow Groups ! + +/* e = FileInternal->GetFirstEntry(); while (e != 0) { if (e->GetVR() == " ") { + SetWriteTypeToDcmImplVR(); SetWriteFileTypeToImplicitVR(); flag = true; @@ -706,8 +750,10 @@ bool FileHelper::Write(std::string const &fileName) SetWriteFileTypeToExplicitVR(); } break; +*/ + + SetWriteFileTypeToExplicitVR(); - SetWriteFileTypeToExplicitVR(); // to see JPRx break; case ACR: case ACR_LIBIDO: @@ -728,8 +774,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 // @@ -760,16 +810,17 @@ 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); } - RestoreWrite(); + RestoreWrite(); // RestoreWriteFileType(); // RestoreWriteMandatory(); - // -------------------------------------------------------------- // Special Patch to allow gdcm to re-write ACR-LibIDO formated images @@ -785,11 +836,7 @@ bool FileHelper::Write(std::string const &fileName) //----------------------------------------------------------------------------- // Protected /** - * \brief Checks the write integrity - * - * The tests made are : - * - verify the size of the image to write with the possible write - * when the user set an image data + * \brief Verifies the size of the user given PixelData * @return true if check is successfull */ bool FileHelper::CheckWriteIntegrity() @@ -837,7 +884,6 @@ bool FileHelper::CheckWriteIntegrity() break; } } - return true; } @@ -845,6 +891,8 @@ bool FileHelper::CheckWriteIntegrity() * \brief Updates the File to write RAW data (as opposed to RGB data) * (modifies, when necessary, photochromatic interpretation, * bits allocated, Pixels element VR) + * WARNING : if SetPhotometricInterpretationToMonochrome1() was called + * before Pixel Elements if modified :-( */ void FileHelper::SetWriteToRaw() { @@ -855,16 +903,20 @@ void FileHelper::SetWriteToRaw() } else { + // 0x0028,0x0004 : Photometric Interpretation DataEntry *photInt = CopyDataEntry(0x0028,0x0004,"CS"); if (FileInternal->HasLUT() ) { photInt->SetString("PALETTE COLOR "); } else - { - photInt->SetString("MONOCHROME2 "); + { + if (GetPhotometricInterpretation() == 2) + photInt->SetString("MONOCHROME2 "); // 0 = Black + else + photInt->SetString("MONOCHROME1 "); // 0 = White ! } - + PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(), PixelReadConverter->GetRawSize()); @@ -873,11 +925,22 @@ 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); pixel->SetBinArea(PixelWriteConverter->GetData(),false); pixel->SetLength(PixelWriteConverter->GetDataSize()); + + if (!FileInternal->HasLUT() && GetPhotometricInterpretation() == 1) + { + ConvertFixGreyLevels( pixel->GetBinArea(), pixel->GetLength() ); + } Archive->Push(photInt); Archive->Push(pixel); @@ -986,7 +1049,6 @@ void FileHelper::SetWriteToRGB() */ void FileHelper::RestoreWrite() { - Archive->Restore(0x0028,0x0002); Archive->Restore(0x0028,0x0004); @@ -1044,13 +1106,28 @@ 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' - */ + */ void FileHelper::SetWriteFileTypeToJPEG() { - std::string ts = Util::DicomString( - Global::GetTS()->GetSpecialTransferSyntax(TS::JPEGBaselineProcess1) ); + std::string ts = Util::DicomString( + Global::GetTS()->GetSpecialTransferSyntax(TS::JPEGLosslessProcess14_1) ); DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI"); tss->SetString(ts); @@ -1087,14 +1164,6 @@ void FileHelper::SetWriteFileTypeToImplicitVR() tss->Delete(); } - -/** - * \brief Restore in the File the initial group 0002 - */ -void FileHelper::RestoreWriteFileType() -{ -} - /** * \brief Set the Write not to Libido format */ @@ -1106,9 +1175,6 @@ void FileHelper::SetWriteToLibido() if ( oldRow && oldCol ) { std::string rows, columns; - - //DataEntry *newRow=DataEntry::New(oldRow->GetDictEntry()); - //DataEntry *newCol=DataEntry::New(oldCol->GetDictEntry()); DataEntry *newRow=DataEntry::New(0x0028, 0x0010, "US"); DataEntry *newCol=DataEntry::New(0x0028, 0x0011, "US"); @@ -1185,7 +1251,6 @@ DataEntry *FileHelper::CopyDataEntry(uint16_t group, uint16_t elem, if ( oldE ) { - //newE = DataEntry::New(oldE->GetDictEntry()); newE = DataEntry::New(group, elem, vr); newE->Copy(oldE); } @@ -1243,9 +1308,9 @@ We have to deal with 4 *very* different cases : FILTERED_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.. +-4) user modified/added some tags *without processing* the pixels (anonymization...) UNMODIFIED_PIXELS_IMAGE --Probabely some more to be added +-Probabely some more to be added. gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases. @@ -1382,15 +1447,20 @@ void FileHelper::CheckMandatoryElements() //0002 0000 UL 1 Meta Group Length //0002 0001 OB 1 File Meta Information Version - //0002 0002 UI 1 Media Stored SOP Class UID - //0002 0003 UI 1 Media Stored SOP Instance UID + //0002 0002 UI 1 Media Storage SOP Class UID + //0002 0003 UI 1 Media Storage SOP Instance UID //0002 0010 UI 1 Transfer Syntax UID //0002 0012 UI 1 Implementation Class UID //0002 0013 SH 1 Implementation Version Name //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 // Push the entries to the archive. @@ -1523,7 +1593,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 " @@ -1556,6 +1627,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 ) { @@ -1571,8 +1660,6 @@ void FileHelper::CheckMandatoryElements() // an imager (see also 0008,0x0064) CheckMandatoryEntry(0x0018,0x1164,pixelSpacing,"DS"); - - /* ///Exact meaning of RETired fields @@ -1616,17 +1703,17 @@ is only from (0020,0030) and (0020,0035) CopyMandatoryEntry(0x0020, 0x0032,imagePositionRet,"DS"); Archive->Push(0x0020,0x0030); CopyMandatoryEntry(0x0020, 0x0037,imageOrientationRet,"DS"); - Archive->Push(0x0020,0x0035); - } + Archive->Push(0x0020,0x0035); + } */ - + // Samples Per Pixel (type 1) : default to grayscale CheckMandatoryEntry(0x0028,0x0002,"1","US"); // --- Check UID-related Entries --- // At the end, not to overwrite the original ones, - // needed by 'Referenced SOP Instance UID', 'Referenced SOP Class UID' + // needed by 'Referenced SOP Instance UID', 'Referenced SOP Class UID' // 'SOP Instance UID' CopyMandatoryEntry(0x0008,0x0018,sop,"UI"); @@ -1638,7 +1725,7 @@ is only from (0020,0030) and (0020,0035) // See PS 3.3, Page 408 // DV = Digitized Video - // DI = Digital Interface + // DI = Digital Interface // DF = Digitized Film // WSD = Workstation // SD = Scanned Document @@ -1655,7 +1742,7 @@ is only from (0020,0030) and (0020,0035) } */ - + // ---- The user will never have to take any action on the following ---- // new value for 'SOP Instance UID' @@ -1664,7 +1751,7 @@ is only from (0020,0030) and (0020,0035) // Instance Creation Date const std::string &date = Util::GetCurrentDate(); CopyMandatoryEntry(0x0008,0x0012,date,"DA"); - + // Instance Creation Time const std::string &time = Util::GetCurrentTime(); CopyMandatoryEntry(0x0008,0x0013,time,"TM"); @@ -1712,15 +1799,15 @@ is only from (0020,0030) and (0020,0035) // Instance Number CheckMandatoryEntry(0x0020,0x0013,"","IS"); - + // Patient Orientation // Can be computed from (0020|0037) : Image Orientation (Patient) - gdcm::Orientation *o = gdcm::Orientation::New(); + GDCM_NAME_SPACE::Orientation *o = GDCM_NAME_SPACE::Orientation::New(); std::string ori = o->GetOrientation ( FileInternal ); o->Delete(); if (ori != "\\" && ori != GDCM_UNFOUND) CheckMandatoryEntry(0x0020,0x0020,ori,"CS"); - else + else CheckMandatoryEntry(0x0020,0x0020,"","CS"); // Default Patient Position to HFS @@ -1767,8 +1854,12 @@ is only from (0020,0030) and (0020,0035) CheckMandatoryEntry(it->first, 0x0000, "0"); } // Third stage : update all 'zero level' groups length -*/ +*/ + + if (PhotometricInterpretation == 1) + { + } } void FileHelper::CheckMandatoryEntry(uint16_t group,uint16_t elem,std::string value,const VRKey &vr ) @@ -1839,7 +1930,6 @@ void FileHelper::RestoreWriteMandatory() Archive->Restore(0x0020,0x000e); } - /** * \brief CallStartMethod */ @@ -1876,9 +1966,11 @@ void FileHelper::Initialize() { UserFunction = 0; ContentType = USER_OWN_IMAGE; - + WriteMode = WMODE_RAW; WriteType = ExplicitVR; + + PhotometricInterpretation = 2; // Black = 0 PixelReadConverter = new PixelReadConvert; PixelWriteConverter = new PixelWriteConvert; @@ -1914,9 +2006,95 @@ uint8_t *FileHelper::GetRaw() return raw; } +/** + * \brief Deal with Grey levels i.e. re-arange them + * to have low values = dark, high values = bright + */ +void FileHelper::ConvertFixGreyLevels(uint8_t *raw, size_t rawSize) +{ + uint32_t i; // to please M$VC6 + int16_t j; + + // Number of Bits Allocated for storing a Pixel is defaulted to 16 + // when absent from the file. + int bitsAllocated = FileInternal->GetBitsAllocated(); + if ( bitsAllocated == 0 ) + { + bitsAllocated = 16; + } + + else if (bitsAllocated > 8 && bitsAllocated < 16 && bitsAllocated != 12) + { + bitsAllocated = 16; + } + // Number of "Bits Stored", defaulted to number of "Bits Allocated" + // when absent from the file. + int bitsStored = FileInternal->GetBitsStored(); + if ( bitsStored == 0 ) + { + bitsStored = bitsAllocated; + } + + if (!FileInternal->IsSignedPixelData()) + { + if ( bitsAllocated == 8 ) + { + uint8_t *deb = (uint8_t *)raw; + for (i=0; i +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; + } +} +*/