/*========================================================================= medInria Copyright (c) INRIA 2013 All rights reserved. See LICENSE.txt for details in the root of the sources or: https://github.com/medInria/medInria-public/blob/master/LICENSE.txt This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =========================================================================*/ #include "medInrimageImageIO.h" #include #include #include #include #include #include #include #if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__)) #include #include #define _unlink unlink LPWSTR convertUTF8to16(char const * pi_pchStringToConvert) { WCHAR * pwcRes = nullptr; int iWCharBuffSize = MultiByteToWideChar( CP_UTF8, 0, pi_pchStringToConvert, -1, nullptr, 0 ); if (iWCharBuffSize > 0) { pwcRes = new WCHAR[iWCharBuffSize+1]; if (MultiByteToWideChar(CP_UTF8, 0, pi_pchStringToConvert, -1, pwcRes, iWCharBuffSize + 1) != iWCharBuffSize) { delete[] pwcRes; pwcRes = nullptr; } } return pwcRes; } gzFile universal_GzOpen(char const * pi_pchPath, char const *pi_pchMode) { gzFile fileRes = nullptr; LPWSTR pathU16 = convertUTF8to16(pi_pchPath); if (pathU16) { fileRes = ::gzopen_w(pathU16, pi_pchMode); delete[] pathU16; } return fileRes; } #else #include #define universal_GzOpen ::gzopen #endif // // GetExtension from itkAnalyzeImageIO.cxx // static std::string GetExtension(const std::string& filename) { const char* c_filename = filename.c_str(); std::string ext = ""; int len = strlen(c_filename); if (len < 4) { return ext; } ext = c_filename + len - 4; // search for .inr if (ext == ".inr") { return ext; } // else we try to find .inr.gz if (len < 7) { return ext; } ext = c_filename + len - 7; return ext; } // // GetRootName from itkAnalyzeImageIO.cxx // static std::string GetRootName(const std::string& filename) { const std::string fileExt = GetExtension(filename); // Create a base filename // i.e Image.gif --> Image if (fileExt.length() > 0) { const std::string::size_type it = filename.find_last_of(fileExt); std::string baseName(filename, 0, it - fileExt.length()); return(baseName); } else { // Case when the extension is nothing return(filename); } } // Default constructor InrimageImageIO::InrimageImageIO() { // by default, only have 2 dimensions this->SetNumberOfDimensions(2); // Initialization this->SetOrigin(0, 0.0); this->SetOrigin(1, 0.0); this->SetSpacing(0, 1.0); this->SetSpacing(1, 1.0); // pixel type is UCHAR // m_PixelType is a protected member of ImageIOBase (IODataType itk::ImageIOBase::m_PixelType) this->SetPixelType(itk::IOPixelEnum::SCALAR); this->SetNumberOfComponents(1); this->SetComponentType(itk::IOComponentEnum::DOUBLE); // Byte order this->SetByteOrder((itk::ByteSwapper::SystemIsBigEndian() == true) ? itk::IOByteOrderEnum::BigEndian : itk::IOByteOrderEnum::LittleEndian); // additionnal information // (inrimage only) m_file = NULL; //length of header of a multiple of 256 m_NumberBlocksInHeader = 1; } InrimageImageIO::~InrimageImageIO() { //Purposefully left blank } void InrimageImageIO::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << "LOCAL PARAMETERS" << std::endl; os << indent << "hdr=" << m_NumberBlocksInHeader << std::endl; os << "GLOBAL PARAMETERS" << std::endl; os << indent << "ByteOrder=" << m_ByteOrder << std::endl; os << indent << "PixelType " << m_PixelType << std::endl; } const std::type_info& InrimageImageIO::ConvertToTypeInfo(itk::IOComponentEnum t) const { switch (t) { case itk::IOComponentEnum::UCHAR: return typeid(unsigned char); case itk::IOComponentEnum::CHAR: return typeid(char); case itk::IOComponentEnum::USHORT: return typeid(unsigned short); case itk::IOComponentEnum::SHORT: return typeid(short); case itk::IOComponentEnum::UINT: return typeid(unsigned int); case itk::IOComponentEnum::INT: return typeid(int); case itk::IOComponentEnum::ULONG: return typeid(unsigned long); case itk::IOComponentEnum::LONG: return typeid(long); case itk::IOComponentEnum::FLOAT: return typeid(float); case itk::IOComponentEnum::DOUBLE: return typeid(double); /*case RGB: return typeid(RGBPixel); case RGBA: return typeid(RGBAPixel); */ default: itkExceptionMacro("Invalid type: " << m_PixelType); } return typeid(itk::IOComponentEnum::UNKNOWNCOMPONENTTYPE); } // called from CreateImageIO ( Insight/Code/IO/itkImageIOFactory.cxx ) // called from ImageFileReader::GenerateOutputInformation ( Insight/Code/IO/itkImageFileReader.txx ) bool InrimageImageIO::CanReadFile(const char* FileNameToRead) { m_FileName = FileNameToRead; // don't care about extensions // should be 'inr' but can be everything else // try to open the file m_file = universal_GzOpen(m_FileName.c_str(), "rb"); if (m_file == NULL) { std::string fileExt = GetExtension(m_FileName); // if it doesn't work, try by subtracting extension .gz if (!fileExt.compare(".inr.gz")) { std::string ImageFileName = GetRootName(m_FileName); m_file = universal_GzOpen(ImageFileName.c_str(), "rb"); if (m_file == NULL) { return false; } m_FileName = ImageFileName; } // if it still doesn't work, try by adding extension .gz else { std::string ImageFileName = m_FileName; ImageFileName += ".gz"; m_file = universal_GzOpen(ImageFileName.c_str(), "rb"); if (m_file == NULL) { return false; } m_FileName = ImageFileName; } } // here m_file is open char buf_header[257]; int nread; // find magic string at beginning nread = ::gzread(m_file, buf_header, 256); if (nread != 256) { ::gzclose(m_file); return false; } if (strncmp(buf_header, "#INRIMAGE-4#{", strlen("#INRIMAGE-4#{")) != 0) { ::gzclose(m_file); return false; } buf_header[256] = '\0'; m_header = buf_header; m_NumberBlocksInHeader = 1; // find magic string at end of header while (strncmp(&(buf_header[252]), "##}\n", strlen("##}\n")) != 0) { nread = ::gzread(m_file, buf_header, 256); if (nread != 256) { ::gzclose(m_file); return false; } buf_header[256] = '\0'; m_header += buf_header; m_NumberBlocksInHeader++; } // check endianess // (as in itkAnalyzeImageIO.cxx) ::gzclose(m_file); return true; } void InrimageImageIO::GetRotationMatrixFromAngles(double rx, double ry, double rz, vnl_matrix &rotationMatrix) { rotationMatrix.set_size(3,3); double c, s, k1, k2; vnl_vector r(3); r[0] = rx; r[1] = ry; r[2] = rz; double theta2 = 0.0; for (unsigned int i = 0;i < 3;++i) theta2 += r[i] * r[i]; double theta = std::sqrt(theta2); if (theta > 1.0e-5) { c = std::cos(theta); s = std::sin(theta); k1 = s / theta; k2 = (1 - c) / theta2; } else { // Taylor expansion around theta = 0 k2 = 1.0/2.0 - theta2/24.0; c = 1.0 - theta2*k2; k1 = 1.0 - theta2/6; } /* I + M*Mt */ for (unsigned int i = 0; i < 3; i++) { for (unsigned int j = 0; j <= i; j++) { rotationMatrix(i, j) = k2 * r[i] * r[j]; if (i != j) rotationMatrix(j,i) = rotationMatrix(i,j); else rotationMatrix(i,i) += c; } } double aux = k1 * r[2]; rotationMatrix(0,1) -= aux; rotationMatrix(1,0) += aux; aux = k1 * r[1]; rotationMatrix(0,2) += aux; rotationMatrix(2,0) -= aux; aux = k1 * r[0]; rotationMatrix(1,2) -= aux; rotationMatrix(2,1) += aux; } void InrimageImageIO::GetRotationAnglesFromMatrix(const vnl_matrix &rotationMatrix, std::vector &r) { r.resize(3); // Compute the rotation vector std::vector sin_r; double d, sq, fact; double c = 0.5 * (rotationMatrix(0,0) + rotationMatrix(1,1) + rotationMatrix(2,2) - 1.0); // cos(theta) if ((d = std::abs(c)) > 1.0) c /= d; double theta = std::acos(c); if (std::abs(theta) <= 1.0e-5) { // R close to identity : DL around theta = 0 fact = 0.5 + theta*theta/12.0; r[0] = (rotationMatrix(2,1) - rotationMatrix(1,2)) * fact; r[1] = (rotationMatrix(0,2) - rotationMatrix(2,0)) * fact; r[2] = (rotationMatrix(1,0) - rotationMatrix(0,1)) * fact; } else if (std::abs(theta - M_PI) <= 0.1) { // R is close to a symetry : DL around theta = M_PI // set values with diag terms of n.nt double rNorm = 0.0; for (int i = 0; i < 3; i++) { // approx order 0 // c = (rot[i][i] - 1.0)*0.5; sq = 1.0 + (rotationMatrix(i,i) - 1.0)/(1-c); // 0 <= [ sq = (n[i])^2 ] <= 1 if (sq < 0.0) sq = 0.; if (sq > 1.) sq = 1.; r[i] = std::sqrt(sq); rNorm += sq; } rNorm = std::sqrt(rNorm); for (int i = 0; i < 3; i++) r[i] *= theta / rNorm; // set signs with off-diag terms of n.nt if ( (rotationMatrix(0,1) + rotationMatrix(1,0) ) < 0.0) r[1] *= -1; if ( (rotationMatrix(0,2) + rotationMatrix(2,0) ) < 0.0) r[2] *= -1; // determine wether r = +/- theta*n sin_r.push_back( rotationMatrix(2,1) - rotationMatrix(1,2) ); sin_r.push_back( rotationMatrix(0,2) - rotationMatrix(2,0) ); sin_r.push_back( rotationMatrix(1,0) - rotationMatrix(0,1) ); // determine the most significant term unsigned int k = 0; if ( std::abs(sin_r[1]) > std::abs(sin_r[k])) k = 1; if ( std::abs(sin_r[2]) > std::abs(sin_r[k])) k = 2; // choose the sign if ( sin_r[k] * r[k] < 0.0 ) { // They do not have the same signs : r = -v for (int i = 0; i < 3; i++) r[i] *= -1; } } else { // At last no numerical problem fact = 0.5 * theta / std::sin(theta); r[0] = (rotationMatrix(2,1) - rotationMatrix(1,2)) * fact; r[1] = (rotationMatrix(0,2) - rotationMatrix(2,0)) * fact; r[2] = (rotationMatrix(1,0) - rotationMatrix(0,1)) * fact; } } void InrimageImageIO::ReadImageInformation() { // m_header should have been read (in CanReadFile) if (m_header.length() == 0) this->CanReadFile(this->GetFileName()); // file endianess // default = Sytem if (itk::ByteSwapper::SystemIsBigEndian() == true) this->SetByteOrderToBigEndian(); else this->SetByteOrderToLittleEndian(); // pixel type // to be read int pixsize = 0; std::string type; int ncomponents = this->GetNumberOfComponents(); // parsing the header line by line std::istringstream issh(m_header); std::string line; double rx = 0, ry = 0, rz = 0; double origin[3] = { 0.0, 0.0, 0.0 }; double voxelsize[3] = { 0.0, 0.0, 0.0 }; unsigned long dim[3] = { 0, 0, 0 }; while (std::getline(issh, line)) { // skip comments and empty lines if (line[0] == '#') continue; if (line.length() == 0) continue; // cout << "1#" << line << "#1" << endl; // translate remaining lines // go to "=" std::istringstream issl(line); std::string id; std::getline(issl, id, '='); int i; double r; std::string s; // to have information about the used methods // see http://www.itk.org/Insight/Doxygen/html/classitk_1_1ImageIOBase.html // documentation of "Abstract superclass defines image IO interface" itk::ImageIOBase switch (id[0]) { default: break; case 'C': if (std::string(id, 0, strlen("CPU")).compare("CPU") == 0) { issl >> s; if (std::string(s, 0, strlen("decm")).compare("decm") == 0 || std::string(s, 0, strlen("alpha")).compare("alpha") == 0 || std::string(s, 0, strlen("linux")).compare("linuxdecm") == 0 || std::string(s, 0, strlen("pc")).compare("pc") == 0) { this->SetByteOrderToLittleEndian(); } else if (std::string(s, 0, strlen("sun")).compare("sun") == 0 || std::string(s, 0, strlen("sgi")).compare("sgi") == 0) { this->SetByteOrderToBigEndian(); } else { itkExceptionMacro("Endianess (CPU) Unknown"); return; } } break; case 'P': if (std::string(id, 0, strlen("PIXSIZE")).compare("PIXSIZE") == 0) { issl >> pixsize; issl >> s; // cerr << pixsize << s << endl; if ((pixsize == 0) || (pixsize % 8 != 0) || (std::string(s, 0, strlen("bits")).compare("bits") != 0)) { itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Size (PIXSIZE) Unknown"); throw exception; } } break; case 'S': // SCALE = ; break; case 'T': if (std::string(id, 0, strlen("TYPE")).compare("TYPE") == 0) { issl >> type; } else if (std::string(id, 0, strlen("TX")).compare("TX") == 0) { issl >> r; origin[0] = r; } else if (std::string(id, 0, strlen("TY")).compare("TY") == 0) { issl >> r; origin[1] = r; } else if (std::string(id, 0, strlen("TZ")).compare("TZ") == 0) { issl >> r; origin[2] = r; } break; case 'R': if (std::string(id, 0, strlen("RX")).compare("RX") == 0) { issl >> rx; } else if (std::string(id, 0, strlen("RY")).compare("RY") == 0) { issl >> ry; } else if (std::string(id, 0, strlen("RZ")).compare("RZ") == 0) { issl >> rz; } break; case 'X': if (std::string(id, 0, strlen("XDIM")).compare("XDIM") == 0) { issl >> i; dim[0] = i; } break; case 'Y': if (std::string(id, 0, strlen("YDIM")).compare("YDIM") == 0) { issl >> i; dim[1] = i; } break; case 'Z': if (std::string(id, 0, strlen("ZDIM")).compare("ZDIM") == 0) { issl >> i; dim[2] = i; } break; case 'V': if (std::string(id, 0, strlen("VDIM")).compare("VDIM") == 0) { issl >> i; if (i > 1) { ncomponents = i; this->SetNumberOfComponents(ncomponents); } } else if (std::string(id, 0, strlen("VX")).compare("VX") == 0) { issl >> r; voxelsize[0] = r; } else if (std::string(id, 0, strlen("VY")).compare("VY") == 0) { issl >> r; voxelsize[1] = r; } else if (std::string(id, 0, strlen("VZ")).compare("VZ") == 0) { issl >> r; voxelsize[2] = r; } break; } } // Set principal image information if ((voxelsize[2] > 0.0) || (dim[2] > 1)) { this->SetNumberOfDimensions(3); } this->SetDimensions(0, dim[0]); this->SetDimensions(1, dim[1]); this->SetSpacing(0, voxelsize[0]); this->SetSpacing(1, voxelsize[1]); this->SetOrigin(0, origin[0]); this->SetOrigin(1, origin[1]); if (this->GetNumberOfDimensions() > 2) { this->SetDimensions(2, dim[2]); this->SetSpacing(2, voxelsize[2]); this->SetOrigin(2, origin[2]); } // header parsing is done // TYPE is "unsigned fixed", "signed fixed", or "float" // Set image cosine directions if (this->GetNumberOfDimensions() == 2) { // Not yet implemented std::cerr << "[WARNING] Orientation matrix cannot be read for 2D images. Not yet implemented\n"; } else if (this->GetNumberOfDimensions() == 3) { vnl_matrix rotationMatrix(3, 3); this->GetRotationMatrixFromAngles(rx, ry, rz, rotationMatrix); vnl_vector d(3); d[0] = std::abs(rotationMatrix(0, 0)) > 1e-10 ? rotationMatrix(0, 0) : 0; d[1] = std::abs(rotationMatrix(1, 0)) > 1e-10 ? rotationMatrix(1, 0) : 0; d[2] = std::abs(rotationMatrix(2, 0)) > 1e-10 ? rotationMatrix(2, 0) : 0; this->SetDirection(0, d); d[0] = std::abs(rotationMatrix(0, 1)) > 1e-10 ? rotationMatrix(0, 1) : 0; d[1] = std::abs(rotationMatrix(1, 1)) > 1e-10 ? rotationMatrix(1, 1) : 0; d[2] = std::abs(rotationMatrix(2, 1)) > 1e-10 ? rotationMatrix(2, 1) : 0; this->SetDirection(1, d); d[0] = std::abs(rotationMatrix(0, 2)) > 1e-10 ? rotationMatrix(0, 2) : 0; d[1] = std::abs(rotationMatrix(1, 2)) > 1e-10 ? rotationMatrix(1, 2) : 0; d[2] = std::abs(rotationMatrix(2, 2)) > 1e-10 ? rotationMatrix(2, 2) : 0; this->SetDirection(2, d); } if (std::string(type, 0, strlen("unsigned")).compare("unsigned") == 0) { if (pixsize == 8) this->SetComponentType(itk::IOComponentEnum::UCHAR); else if (pixsize == 16) this->SetComponentType(itk::IOComponentEnum::USHORT); else if (pixsize == 32) this->SetComponentType(itk::IOComponentEnum::UINT); else if (pixsize == 64) this->SetComponentType(itk::IOComponentEnum::ULONG); else { itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Size Not Recognized"); throw exception; } } else if (std::string(type, 0, strlen("signed")).compare("signed") == 0) { if (pixsize == 8) this->SetComponentType(itk::IOComponentEnum::CHAR); else if (pixsize == 16) this->SetComponentType(itk::IOComponentEnum::SHORT); else if (pixsize == 32) this->SetComponentType(itk::IOComponentEnum::INT); else if (pixsize == 64) this->SetComponentType(itk::IOComponentEnum::LONG); else { itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Size Not Recognized"); throw exception; } } else if (std::string(type, 0, strlen("float")).compare("float") == 0) { if (pixsize == 32) this->SetComponentType(itk::IOComponentEnum::FLOAT); else if (pixsize == 64) this->SetComponentType(itk::IOComponentEnum::DOUBLE); else { itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Size Not Recognized"); throw exception; } } this->SetPixelType(itk::IOPixelEnum::SCALAR); if (0) { std::cout << "type " << type << std::endl; std::cout << "pixsize " << pixsize << std::endl; std::cout << "ComponentType " << this->GetComponentType() << std::endl; std::cout << "PixelType "; if (this->GetComponentTypeInfo() == typeid(unsigned char)) std::cout << "UCHAR"; else if (this->GetComponentTypeInfo() == typeid(unsigned short)) std::cout << "USHORT"; else if (this->GetComponentTypeInfo() == typeid(signed short)) std::cout << "SHORT"; else std::cout << "not handled in switch"; std::cout << std::endl; } // I am not sure that this has to be done // GM if (0) { if (this->GetNumberOfComponents() == 3) { switch (this->GetComponentType()) { default: break; case itk::IOComponentEnum::UCHAR: this->SetPixelType(itk::IOPixelEnum::RGB); this->SetNumberOfComponents(1); break; } } else if (this->GetNumberOfComponents() == 4) { switch (this->GetComponentType()) { default: break; case itk::IOComponentEnum::UCHAR: this->SetPixelType(itk::IOPixelEnum::RGBA); this->SetNumberOfComponents(1); break; } } } return; } void InrimageImageIO::Read(void* buffer) { unsigned int nread; if (0) { std::cerr << "* ComponentType " << this->GetComponentType() << std::endl; std::cerr << "PixelType "; if (this->GetComponentTypeInfo() == typeid(unsigned char)) std::cerr << "UCHAR"; else if (this->GetComponentTypeInfo() == typeid(unsigned short)) std::cerr << "USHORT"; else if (this->GetComponentTypeInfo() == typeid(signed short)) std::cerr << "=SSHORT"; else std::cerr << "not handled in switch"; std::cerr << std::endl; } m_file = universal_GzOpen(m_FileName.c_str(), "rb"); if (m_file == NULL) { itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Unable to open file"); throw exception; } char buf_header[257]; for (unsigned int i = 0; i < m_NumberBlocksInHeader; i++) { nread = ::gzread(m_file, buf_header, 256); if (nread != 256) { ::gzclose(m_file); itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Unable to skip header"); throw exception; } } char * p = static_cast(buffer); nread = ::gzread(m_file, p, this->GetImageSizeInBytes() + 10000); if (nread != this->GetImageSizeInBytes()) { ::gzclose(m_file); itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Unable to read buffer"); throw exception; } ::gzclose(m_file); SwapBytesIfNecessary(buffer, this->GetImageSizeInComponents()); } bool InrimageImageIO::CanWriteFile(const char * FileNameToWrite) { m_FileName = FileNameToWrite; if (m_FileName != "") { const std::string fileExt = GetExtension(m_FileName); if (strcmp(fileExt.c_str(), ".inr.gz") == 0 || strcmp(fileExt.c_str(), ".inr") == 0) return true; } return false; } void InrimageImageIO::WriteImageInformation(void) { return; } void InrimageImageIO ::Write(const void* buffer) { // try to open the file bool isGz = true; std::string fileExt = GetExtension(m_FileName); // if it doesn't work, try by substracting extension .gz if (fileExt == (".inr.gz")) { m_file = universal_GzOpen(m_FileName.c_str(), "wb"); if (m_file == NULL) throw itk::ExceptionObject(__FILE__, __LINE__, "Error in opening file for writing"); } else { if (fileExt == (".inr")) { isGz = false; m_file = gzopen(m_FileName.c_str(), "wb"); if (m_file == NULL) throw itk::ExceptionObject(__FILE__, __LINE__, "Error in opening file for writing"); } else throw itk::ExceptionObject(__FILE__, __LINE__, "Unrecognized extension."); } std::string type = "signed fixed"; char scale[20]; switch (this->GetComponentType()) { case itk::IOComponentEnum::UCHAR: case itk::IOComponentEnum::USHORT: case itk::IOComponentEnum::UINT: case itk::IOComponentEnum::ULONG: type = "unsigned fixed"; sprintf(scale, "SCALE=2**0\n"); break; case itk::IOComponentEnum::CHAR: case itk::IOComponentEnum::SHORT: case itk::IOComponentEnum::INT: case itk::IOComponentEnum::LONG: type = "signed fixed"; sprintf(scale, "SCALE=2**0\n"); break; case itk::IOComponentEnum::FLOAT: case itk::IOComponentEnum::DOUBLE: type = "float"; scale[0] = '\0'; break; default: throw itk::ExceptionObject(__FILE__, __LINE__, "Error: pixel type not recognized."); } int pixsize = 8; switch (this->GetComponentType()) { case itk::IOComponentEnum::UCHAR: case itk::IOComponentEnum::CHAR: pixsize = 8; break; case itk::IOComponentEnum::USHORT: case itk::IOComponentEnum::SHORT: pixsize = 16; break; case itk::IOComponentEnum::UINT: case itk::IOComponentEnum::INT: case itk::IOComponentEnum::FLOAT: pixsize = 32; break; case itk::IOComponentEnum::ULONG: case itk::IOComponentEnum::LONG: case itk::IOComponentEnum::DOUBLE: pixsize = 64; break; default: pixsize = 0; break; } std::string endianness; if (this->GetByteOrder() == itk::IOByteOrderEnum::LittleEndian) endianness = "decm"; else endianness = "sun"; char buf[257]; /* Compute rotation angles from cosine directions */ std::vector r(3,0.0); if (this->GetNumberOfDimensions() == 2) { // Not yet implemented std::cerr << "[WARNING] Orientation matrix cannot be read for 2D images. Not yet implemented\n"; } else { std::vector d; vnl_matrix rotationMatrix(3,3); d = this->GetDirection(0); for (unsigned int i = 0;i < 3;++i) { // Direction vectors represent columns of the rotation matrix d = this->GetDirection(i); for (unsigned int j = 0;j < 3;++j) rotationMatrix(j,i) = d[j]; } this->GetRotationAnglesFromMatrix(rotationMatrix, r); } /* Get spacings. If a spacing is null (pseudo 2D image), we artificially set it to 1 */ double vx = this->GetSpacing(0); if (vx < 1e-9) vx = 1.0; double vy = this->GetSpacing(1); if (vy < 1e-9) vy = 1.0; double vz = this->GetSpacing(2); if (vz < 1e-9) vz = 1.0; /* write header information */ sprintf(buf, "#INRIMAGE-4#{\nXDIM=%llu\nYDIM=%llu\nZDIM=%llu\nVDIM=%d\nTYPE=%s\nPIXSIZE=%i bits\n%sCPU=%s\nVX=%f\nVY=%f\nVZ=%f\nTX=%f\nTY=%f\nTZ=%f\nRX=%f\nRY=%f\nRZ=%f\n#GEOMETRY=CARTESIAN\n", this->GetDimensions(0), this->GetDimensions(1), this->GetDimensions(2), this->GetNumberOfComponents(), type.c_str(), pixsize, scale, endianness.c_str(), vx, vy, vz, this->GetOrigin(0), this->GetOrigin(1), this->GetOrigin(2), r[0], r[1], r[2]); int pos = strlen(buf); size_t npix = 0; // write the header: if (isGz) npix = ::gzwrite(m_file, (void *)buf, pos); else npix = fwrite((void *)buf, 1, pos, (FILE*)m_file); if (npix != strlen(buf)) { if (isGz) ::gzclose(m_file); else fclose((FILE*)m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } /* write end of header */ pos = pos % 256; if (pos > 252) { for (int i = pos; i < 256; i++) if (isGz) { if (::gzwrite(m_file, (void *)("\n"), 1) != 1) { ::gzclose(m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } } else { if (fwrite((void *)("\n"), 1, 1, (FILE*)m_file) != 1) { fclose((FILE*)m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } } pos = 0; } buf[0] = '\0'; for (int i = pos; i < 252; i++) strcat(buf, "\n"); strcat(buf, "##}\n"); if (isGz) { if (::gzwrite(m_file, (void *)buf, strlen(buf)) != (int)(strlen(buf))) { ::gzclose(m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } } else { if (fwrite((void *)buf, 1, strlen(buf), (FILE*)m_file) != (size_t)(strlen(buf))) { fclose((FILE*)m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } } // write the buffer: if (isGz) npix = ::gzwrite(m_file, (void *)buffer, this->GetImageSizeInBytes()); else npix = fwrite((void *)buffer, 1, this->GetImageSizeInBytes(), (FILE*)m_file); if ((unsigned int)npix != this->GetImageSizeInBytes()) { if (isGz) ::gzclose(m_file); else fclose((FILE*)m_file); throw itk::ExceptionObject(__FILE__, __LINE__, "Error: bad number of bytes written."); } if (isGz) ::gzclose(m_file); else fclose((FILE*)m_file); } /************************************************************ * * private methods * ************************************************************/ void InrimageImageIO::SwapBytesIfNecessary(void* buffer, unsigned long numberOfPixels) { if (ImageIOBase::GetByteOrder() == itk::IOByteOrderEnum::LittleEndian) { switch (m_ComponentType) { case itk::IOComponentEnum::CHAR: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((char*)buffer, numberOfPixels); break; case itk::IOComponentEnum::UCHAR: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((unsigned char*)buffer, numberOfPixels); break; case itk::IOComponentEnum::SHORT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((short*)buffer, numberOfPixels); break; case itk::IOComponentEnum::USHORT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((unsigned short*)buffer, numberOfPixels); break; case itk::IOComponentEnum::INT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((int*)buffer, numberOfPixels); break; case itk::IOComponentEnum::UINT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((unsigned int*)buffer, numberOfPixels); break; case itk::IOComponentEnum::LONG: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((long*)buffer, numberOfPixels); break; case itk::IOComponentEnum::ULONG: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((unsigned long*)buffer, numberOfPixels); break; case itk::IOComponentEnum::FLOAT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((float*)buffer, numberOfPixels); break; case itk::IOComponentEnum::DOUBLE: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian ((double*)buffer, numberOfPixels); break; default: itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Type Unknown"); throw exception; } } else { switch (m_ComponentType) { case itk::IOComponentEnum::CHAR: itk::ByteSwapper::SwapRangeFromSystemToBigEndian((char *)buffer, numberOfPixels); break; case itk::IOComponentEnum::UCHAR: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((unsigned char *)buffer, numberOfPixels); break; case itk::IOComponentEnum::SHORT: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((short *)buffer, numberOfPixels); break; case itk::IOComponentEnum::USHORT: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((unsigned short *)buffer, numberOfPixels); break; case itk::IOComponentEnum::INT: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((int *)buffer, numberOfPixels); break; case itk::IOComponentEnum::UINT: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((unsigned int *)buffer, numberOfPixels); break; case itk::IOComponentEnum::LONG: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((long *)buffer, numberOfPixels); break; case itk::IOComponentEnum::ULONG: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((unsigned long *)buffer, numberOfPixels); break; case itk::IOComponentEnum::FLOAT: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((float *)buffer, numberOfPixels); break; case itk::IOComponentEnum::DOUBLE: itk::ByteSwapper::SwapRangeFromSystemToBigEndian ((double *)buffer, numberOfPixels); break; default: itk::ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Type Unknown"); throw exception; } } }