/*========================================================================= medInria Copyright (c) INRIA 2013 - 2018. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =========================================================================*/ #include #include #include #include #ifdef WIN32 #define snprintf sprintf_s #endif namespace itk { GISImageIO::GISImageIO() { m_IsBinary = true; this->SetNumberOfDimensions(3); m_PixelType = itk::IOPixelEnum::SCALAR; m_ComponentType = itk::IOComponentEnum::UCHAR; if (ByteSwapper::SystemIsBigEndian()) { m_ByteOrder = itk::IOByteOrderEnum::BigEndian; } else { m_ByteOrder = itk::IOByteOrderEnum::LittleEndian; } } GISImageIO::~GISImageIO() {} bool GISImageIO::CanReadFile(const char* filename) { std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename); if( extension!=".ima" && extension!=".dim" ) { return false; } // look if the header file exists std::string header_file = filename; if( extension==".ima") { std::string path = itksys::SystemTools::GetFilenamePath(filename); if (path=="") { path = "."; } header_file = path + "/" + itksys::SystemTools::GetFilenameWithoutLastExtension(filename) + ".dim"; } // if ( !itksys::SystemTools::FileExists(header_file.c_str(), true) ) if ( !itksys::SystemTools::FileExists(header_file.c_str()) ) { std::cerr << "Error: Header file does not exist." << std::endl; return false; } return true; } void GISImageIO::ReadImageInformation() { std::string extension = itksys::SystemTools::GetFilenameLastExtension(m_FileName); if( extension!=".ima" && extension!=".dim" ) { throw itk::ExceptionObject(__FILE__,__LINE__,"Error in GISImageIO::ReadImageInformation(): Extension is not recognized."); } // look if the header file exists std::string header_file = m_FileName; if( extension!=".dim") { std::string path = itksys::SystemTools::GetFilenamePath(m_FileName); if (path=="") { path = "."; } header_file = path + "/" + itksys::SystemTools::GetFilenameWithoutLastExtension(m_FileName) + ".dim"; } // if ( !itksys::SystemTools::FileExists(header_file.c_str(), true) ) if ( !itksys::SystemTools::FileExists(header_file.c_str()) ) { std::cerr << "Error: Header file does not exist." << std::endl; } std::ifstream ifs (header_file.c_str()); if( ifs.fail() ) { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot read header file."); } int dims[4]; for( int i=0; i<3; i++) { ifs >> dims[i]; } // the last (4th) dimension is sometimes not set: the keyword type appears then std::string junk; ifs >> junk; if( junk!="-type" ) { dims[3] = atoi ( junk.c_str() ); if ( dims[3]>1 ) { // this->SetNumberOfDimensions(3); this->SetNumberOfDimensions(4); //this->SetNumberOfComponents( dims[3] ); this->SetNumberOfComponents( 1 ); //this->SetPixelType (VECTOR); this->SetPixelType (itk::IOPixelEnum::SCALAR); } else { this->SetNumberOfDimensions(3); this->SetNumberOfComponents(1); this->SetPixelType (itk::IOPixelEnum::SCALAR); } ifs >> junk; } else { dims[3] = 1; this->SetNumberOfDimensions(3); this->SetNumberOfComponents(1); this->SetPixelType (itk::IOPixelEnum::SCALAR); } for( unsigned int i=0; iGetNumberOfDimensions(); i++ ) { m_Dimensions[i] = dims[i]; } if (junk != "-type") { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-type\"."); } std::string s_type; ifs >> s_type; // parse the type if( s_type== "S8" ) { m_ComponentType = itk::IOComponentEnum::CHAR; } else if( s_type== "U8" ) { m_ComponentType = itk::IOComponentEnum::UCHAR; } else if( s_type== "S16" ) { m_ComponentType = itk::IOComponentEnum::SHORT; } else if( s_type== "U16" ) { m_ComponentType = itk::IOComponentEnum::USHORT; } else if( s_type== "S32" ) { m_ComponentType = itk::IOComponentEnum::INT; } else if( s_type== "U32" ) { m_ComponentType = itk::IOComponentEnum::UINT; } else if( s_type== "F32" || s_type=="FLOAT") { m_ComponentType = itk::IOComponentEnum::FLOAT; } else if( s_type== "F64" || s_type=="DOUBLE") { m_ComponentType = itk::IOComponentEnum::DOUBLE; } else { char message[512]; snprintf( message, 512, "Error: Unsupported pixel type: %s.", s_type.c_str()); throw itk::ExceptionObject(__FILE__,__LINE__,message); } // voxel size double spacing[4]; ifs >> junk; if (junk != "-dx") { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-dx\"."); } ifs >> spacing[0]; ifs >> junk; if (junk != "-dy") { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-dy\"."); } ifs >> spacing[1]; ifs >> junk; if (junk != "-dz") { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-dz\"."); } ifs >> spacing[2]; ifs >> junk; if ( this->GetNumberOfDimensions()==4 && junk != "-dt") { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-dt\"."); } else { ifs >> spacing[3]; ifs >> junk; } for( unsigned int i=0;iGetNumberOfDimensions(); i++) { m_Spacing[i] = spacing[i]; } // byte order if( junk != "-bo") { // assuming it's LittleEndian //throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-bo\"."); m_ByteOrder = itk::IOByteOrderEnum::LittleEndian; } else { std::string s_byteorder; ifs >> s_byteorder; if( s_byteorder == "DCBA" ) { m_ByteOrder = itk::IOByteOrderEnum::LittleEndian; } else { m_ByteOrder = itk::IOByteOrderEnum::BigEndian; } ifs >> junk; } // binary/ascii buffer if( junk != "-om" ) { //throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot find keyword \"-om\"."); // assuming it's binary m_IsBinary = true; } else { std::string s_om; ifs >> s_om; if( s_om=="binar" ) { m_IsBinary = true; } else { m_IsBinary = false; } } } void GISImageIO::Read(void* buffer) { std::string extension = itksys::SystemTools::GetFilenameLastExtension(m_FileName); std::string s_filename = m_FileName; if( extension != ".ima" ) { std::string path = itksys::SystemTools::GetFilenamePath(m_FileName); if (path==""){ path = "."; } s_filename = path+"/"+itksys::SystemTools::GetFilenameWithoutLastExtension(m_FileName)+".ima"; } std::ifstream ifs; if( m_IsBinary ) { ifs.open(s_filename.c_str(), std::ios::in | std::ios::binary); } else { ifs.open(s_filename.c_str(), std::ios::in); } if( ifs.fail() ) { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot open buffer in read mode."); } /* std::cout << "filename " << s_filename << " " << m_FileName << std::endl; std::cout << "Image size in bytes: " << (Superclass::SizeType)(this->GetImageSizeInBytes()) << std::endl; std::cout << "Type: " << this->GetComponentTypeAsString( this->GetComponentType() ) << std::endl; std::cout << "Size of buffer: " << sizeof( buffer) << std::endl; std::cout << "Number of dimensions: " << this->GetNumberOfDimensions() << std::endl; std::cout << "Number of pixels: " << this->GetImageSizeInPixels() << std::endl; */ if( m_IsBinary ) { if( !this->ReadBufferAsBinary( ifs, buffer, this->GetImageSizeInBytes() ) ) { throw itk::ExceptionObject(__FILE__,__LINE__,"Error while reading buffer as binary."); } this->SwapBytesIfNecessary( buffer, this->GetImageSizeInComponents()); } else { this->ReadBufferAsASCII( ifs, buffer, m_ComponentType, this->GetImageSizeInBytes() ); } } bool GISImageIO::CanWriteFile( const char* filename) { std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename); if( extension!=".dim" && extension!=".ima" ) { itkDebugMacro(<<"The filename extension is not recognized"); return false; } /* if( this->GetNumberOfDimensions()<3 || this->GetNumberOfDimensions()>4 ) { itkDebugMacro(<<"GIS image format only supports image of dimensions 3 or 4."); return false; } // check the type as well //if( m_ComponentType != */ return true; } void GISImageIO::WriteImageInformation() { std::string header_file = m_FileName; std::string extension = itksys::SystemTools::GetFilenameLastExtension(m_FileName); if( extension!=".dim") { std::string path = itksys::SystemTools::GetFilenamePath(m_FileName); if (path=="") { path = "."; } header_file = path + "/" + itksys::SystemTools::GetFilenameWithoutLastExtension(m_FileName) + ".dim"; } std::ofstream ofs (header_file.c_str()); if( ofs.fail() ) { throw ExceptionObject(__FILE__,__LINE__,"Error: Cannot open header file for writing."); } if( this->GetNumberOfDimensions()==3 && this->GetPixelType()== itk::IOPixelEnum::SCALAR) { for( int i=0; i<3; i++ ) { ofs << m_Dimensions[i] << " "; } ofs << "1\n"; } else if (this->GetNumberOfDimensions()==3 && this->GetPixelType()== itk::IOPixelEnum::VECTOR ) { for( int i=0; i<3; i++ ) { ofs << m_Dimensions[i] << " "; } ofs << this->GetNumberOfComponents() << std::endl; } else if ( this->GetNumberOfDimensions()==4 ) { for( int i=0; i<4; i++ ) { ofs << m_Dimensions[i] << " "; } ofs << std::endl; } else { throw ExceptionObject(__FILE__,__LINE__,"Error: Number of dimensions of pixel type not supported."); } // write the type ofs << "-type "; switch (m_ComponentType ) { case itk::IOComponentEnum::CHAR: ofs << "S8\n"; break; case itk::IOComponentEnum::UCHAR: ofs << "U8\n"; break; case itk::IOComponentEnum::SHORT: ofs << "S16\n"; break; case itk::IOComponentEnum::USHORT: ofs << "U16\n"; break; case itk::IOComponentEnum::INT: ofs << "S32\n"; break; case itk::IOComponentEnum::UINT: ofs << "U32\n"; break; case itk::IOComponentEnum::FLOAT: ofs << "FLOAT\n"; break; case itk::IOComponentEnum::DOUBLE: ofs << "DOUBLE\n"; break; default: throw ExceptionObject(__FILE__,__LINE__,"Error: Pixel type not supported by GIS format."); } // spacing ofs << "-dx " << m_Spacing[0] << " -dy " << m_Spacing[1] << " -dz " << m_Spacing[2]; if( this->GetNumberOfDimensions()==3 ) { ofs << " -dt 1\n"; } else if ( this->GetNumberOfDimensions()==4 ) { ofs << " -dt " << m_Spacing[3] << std::endl; } else {} // never here // byte order if( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ofs << "-bo DCBA\n"; } else { ofs << "-bo ABCD\n"; } // buffer style: only write binary files for now m_IsBinary = true; ofs << "-om binar\n"; } void GISImageIO::Write(const void* buffer) { // check if image is supported if( this->GetNumberOfDimensions()<3 || this->GetNumberOfDimensions()>4 ) { throw ExceptionObject (__FILE__,__LINE__,"GIS image format only supports image of dimensions 3 or 4."); } if ( m_PixelType != itk::IOPixelEnum::SCALAR && m_PixelType != itk::IOPixelEnum::VECTOR) { throw ExceptionObject (__FILE__,__LINE__,"Error: GIS only supports SCALAR and VECTOR images."); } if (m_ComponentType != itk::IOComponentEnum::CHAR && m_ComponentType != itk::IOComponentEnum::UCHAR && m_ComponentType != itk::IOComponentEnum::SHORT && m_ComponentType != itk::IOComponentEnum::USHORT && m_ComponentType != itk::IOComponentEnum::INT && m_ComponentType != itk::IOComponentEnum::UINT && m_ComponentType != itk::IOComponentEnum::FLOAT && m_ComponentType != itk::IOComponentEnum::DOUBLE) { throw ExceptionObject (__FILE__,__LINE__,"Error: Pixel type is not supported by GIS format yet."); } this->WriteImageInformation(); std::string extension = itksys::SystemTools::GetFilenameLastExtension(m_FileName); std::string s_filename = m_FileName; if( extension != ".ima" ) { std::string path = itksys::SystemTools::GetFilenamePath(m_FileName); if (path=="") { path = "."; } s_filename = path + "/" + itksys::SystemTools::GetFilenameWithoutLastExtension(m_FileName) + ".ima"; } std::ofstream ofs(s_filename.c_str()); if( ofs.fail() ) { throw itk::ExceptionObject(__FILE__,__LINE__,"Error: Cannot open buffer in write mode."); } const unsigned long numberOfBytes = static_cast( this->GetImageSizeInBytes() ); const unsigned long numberOfComponents = static_cast( this->GetImageSizeInComponents() ); // Swap bytes if necessary if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { char * tempBuffer = new char[ numberOfBytes ]; memcpy( tempBuffer, buffer , numberOfBytes ); this->SwapBytesIfNecessary(tempBuffer, numberOfComponents ); ofs.write( tempBuffer, numberOfBytes ); delete [] tempBuffer; } else //if ( m_ByteOrder == BigEndian ) { char * tempBuffer = new char[ numberOfBytes ]; memcpy( tempBuffer, buffer , numberOfBytes ); this->SwapBytesIfNecessary(tempBuffer, numberOfComponents ); ofs.write( tempBuffer, numberOfBytes ); delete [] tempBuffer; } } void GISImageIO ::SwapBytesIfNecessary( void* buffer, unsigned long numberOfPixels ) { switch(m_ComponentType) { case itk::IOComponentEnum::CHAR: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian((char*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian((char *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::UCHAR: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (unsigned char*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (unsigned char *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::SHORT: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (short*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (short *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::USHORT: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (unsigned short*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (unsigned short *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::INT: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (int*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (int*)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::UINT: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (unsigned int*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (unsigned int *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::FLOAT: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (float*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (float *)buffer, numberOfPixels ); } break; } case itk::IOComponentEnum::DOUBLE: { if ( m_ByteOrder == itk::IOByteOrderEnum::LittleEndian ) { ByteSwapper::SwapRangeFromSystemToLittleEndian( (double*)buffer, numberOfPixels ); } else if ( m_ByteOrder == itk::IOByteOrderEnum::BigEndian ) { ByteSwapper::SwapRangeFromSystemToBigEndian( (double *)buffer, numberOfPixels ); } break; } default: ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Type Unknown"); throw exception; } } }