Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

671 lines
20 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkMetaImageReader.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkMetaImageReader.h"
#include "vtkObjectFactory.h"
#include "vtkImageData.h"
#include "vtkInformationVector.h"
#include <vtkstd/string>
#include <sys/stat.h>
//----------------------------------------------------------------------------
vtkCxxRevisionMacro(vtkMetaImageReader, "$Revision: 1.18 $");
vtkStandardNewMacro(vtkMetaImageReader);
//----------------------------------------------------------------------------
vtkMetaImageReader::vtkMetaImageReader()
{
this->MHDFileName = 0;
}
//----------------------------------------------------------------------------
vtkMetaImageReader::~vtkMetaImageReader()
{
this->SetFileName(0);
}
//----------------------------------------------------------------------------
void vtkMetaImageReader::SetFileName(const char* fname)
{
this->SetMHDFileName(fname);
}
//----------------------------------------------------------------------------
class vtkMetaImageReaderInternal
{
public:
static void ReplaceString(vtkstd::string& source, const char* replace,
const char* with);
static void ConvertToUnixSlashes(vtkstd::string& path);
static vtkstd::string GetFilenamePath(const vtkstd::string& filename);
static int StringEquals(const char* s1, const char* s2, size_t maxlen);
static int StringEqualsCase(const char* s1, const char* s2, size_t maxlen);
static int GetLineFromStream(istream& is, vtkstd::string& line,
bool *has_newline /* = 0 */, size_t maxlen /* = 0 */);
};
//----------------------------------------------------------------------------
// replace replace with with as many times as it shows up in source.
// write the result into source.
void vtkMetaImageReaderInternal::ReplaceString(vtkstd::string& source,
const char* replace,
const char* with)
{
const char *src = source.c_str();
char *searchPos = const_cast<char *>(strstr(src,replace));
// get out quick if string is not found
if (!searchPos)
{
return;
}
// perform replacements until done
size_t replaceSize = strlen(replace);
char *orig = strdup(src);
char *currentPos = orig;
searchPos = searchPos - src + orig;
// initialize the result
source.erase(source.begin(),source.end());
do
{
*searchPos = '\0';
source += currentPos;
currentPos = searchPos + replaceSize;
// replace
source += with;
searchPos = strstr(currentPos,replace);
}
while (searchPos);
// copy any trailing text
source += currentPos;
free(orig);
}
//----------------------------------------------------------------------------
// convert windows slashes to unix slashes
void vtkMetaImageReaderInternal::ConvertToUnixSlashes(vtkstd::string& path)
{
vtkstd::string::size_type pos = 0;
while((pos = path.find('\\', pos)) != vtkstd::string::npos)
{
path[pos] = '/';
pos++;
}
// Remove all // from the path just like most unix shells
int start_find;
#ifdef _WIN32
// However, on windows if the first characters are both slashes,
// then keep them that way, so that network paths can be handled.
start_find = 1;
#else
start_find = 0;
#endif
while((pos = path.find("//", start_find)) != vtkstd::string::npos)
{
vtkMetaImageReaderInternal::ReplaceString(path, "//", "/");
}
// remove any trailing slash
if(path.size() && path[path.size()-1] == '/')
{
path = path.substr(0, path.size()-1);
}
// if there is a tilda ~ then replace it with HOME
if(path.find("~") == 0)
{
if (getenv("HOME"))
{
path = getenv("HOME");
path += path.substr(1);
}
}
// if there is a /tmp_mnt in a path get rid of it!
if(path.find("/tmp_mnt") == 0)
{
path = path.substr(8);
}
}
//----------------------------------------------------------------------------
/**
* Return path of a full filename (no trailing slashes).
* Warning: returned path is converted to Unix slashes format.
*/
vtkstd::string vtkMetaImageReaderInternal::GetFilenamePath(const vtkstd::string& filename)
{
vtkstd::string fn = filename;
vtkMetaImageReaderInternal::ConvertToUnixSlashes(fn);
vtkstd::string::size_type slash_pos = fn.rfind("/");
if(slash_pos != vtkstd::string::npos)
{
return fn.substr(0, slash_pos);
}
return "";
}
//----------------------------------------------------------------------------
// Due to a buggy stream library on the HP and another on Mac OSX, we
// need this very carefully written version of getline. Returns true
// if any data were read before the end-of-file was reached.
int vtkMetaImageReaderInternal::GetLineFromStream(istream& is, vtkstd::string& line,
bool *has_newline /* = 0 */, size_t maxlen /* = 0 */)
{
const int bufferSize = 1024;
char buffer[bufferSize];
line = "";
bool haveData = 0;
if ( has_newline )
{
*has_newline = 0;
}
// If no characters are read from the stream, the end of file has
// been reached.
while((is.getline(buffer, bufferSize), is.gcount() > 0))
{
haveData = 1;
if ( maxlen > 0 && is.gcount() + line.size() > maxlen )
{
line.append(buffer, maxlen - line.size());
}
else
{
line.append(buffer);
}
// If newline character was read, the gcount includes the
// character, but the buffer does not. The end of line has been
// reached.
if(strlen(buffer) < static_cast<size_t>(is.gcount()))
{
if ( has_newline )
{
*has_newline = 1;
}
break;
}
// The fail bit may be set. Clear it.
is.clear(is.rdstate() & ~ios::failbit);
}
return haveData;
}
#if defined( _WIN32 ) && !defined(__CYGWIN__)
# if defined(__BORLANDC__)
# define STRCASECMP stricmp
# else
# define STRCASECMP _stricmp
# endif
#else
# define STRCASECMP strcasecmp
#endif
#define MHDMIN(x,y) (((x)<(y))?(x):(y))
//----------------------------------------------------------------------------
int vtkMetaImageReaderInternal::StringEqualsCase(const char* s1, const char* s2, size_t maxlen)
{
if ( s1 == s2 )
{
return 1;
}
if ( !s1 || !s2 )
{
return 0;
}
vtkstd::string ss1(s1, MHDMIN(maxlen, strlen(s1)));
vtkstd::string ss2(s2, MHDMIN(maxlen, strlen(s2)));
return STRCASECMP(ss1.c_str(), ss2.c_str()) == 0;
}
//----------------------------------------------------------------------------
int vtkMetaImageReaderInternal::StringEquals(const char* s1, const char* s2, size_t maxlen)
{
if ( s1 == s2 )
{
return 1;
}
if ( !s1 || !s2 )
{
return 0;
}
return strncmp(s1, s2, maxlen) == 0;
}
//----------------------------------------------------------------------------
int vtkMetaImageReader::RequestInformation(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
const char* fname = this->MHDFileName;
if ( !this->GetFileInformation(fname, 1) )
{
return 0;
}
vtkDataObject::SetPointDataActiveScalarInfo( outputVector->GetInformationObject(0),
this->DataScalarType, this->NumberOfScalarComponents);
return this->Superclass::RequestInformation( request, inputVector, outputVector );
}
//----------------------------------------------------------------------------
int vtkMetaImageReader::GetFileInformation(const char* fname, int populate)
{
if ( !fname )
{
return 0;
}
struct stat fs;
if ( stat( fname, &fs) )
{
if ( populate )
{
vtkErrorMacro(<< "Initialize: Could not open file " << fname);
}
return 0;
}
ifstream ifs(fname);
if ( !ifs)
{
return 0;
}
vtkstd::string path = vtkMetaImageReaderInternal::GetFilenamePath(fname);
int ndims = 0;
int bigendian = 0;
int dims[3] = { 0, 0, 0 };
double origin[3] = { 0.0, 0.0, 0.0 };
double spacing[3] = { 1.0, 1.0, 1.0 };
int data_type = VTK_UNSIGNED_CHAR;
int number_of_channels = 1;
vtkstd::string datafile = "";
unsigned long headerlen = 0;
int size_type = 1;
vtkstd::string line;
int count = -1;
while(vtkMetaImageReaderInternal::GetLineFromStream(ifs, line, 0, 0) )
{
count ++;
vtkstd::string::size_type pos = line.find("=");
if ( pos != vtkstd::string::npos )
{
vtkstd::string::size_type keylen, valuelen;
const char* key = line.c_str();
const char* value = line.c_str()+pos+1;
const char* endkey = line.c_str()+pos-1;
const char* endvalue = line.c_str()+line.size();
while ( *key!= 0 )
{
if ( *key!= ' ' && *key!= '\t' && *key!= '\r' )
{
break;
}
key++;
}
while ( endkey > key )
{
if ( *endkey != ' ' && *endkey != '\t' && *endkey != '\r' && *endkey != 0 )
{
break;
}
endkey--;
}
keylen = endkey - key + 1;
while ( *value != 0 )
{
if ( *value != ' ' && *value != '\t' && *value != '\r' )
{
break;
}
value++;
}
while ( endvalue > value )
{
if ( *endvalue != ' ' && *endvalue != '\t' && *endvalue != '\r' && *endvalue != 0 )
{
break;
}
endvalue--;
}
valuelen = endvalue - value + 1;
//cout << "Key: [";
//cout.write(key, keylen);
//cout << "] -- Value: [";
//cout.write(value, valuelen);
//cout << "]" << endl;
if ( vtkMetaImageReaderInternal::StringEquals(key, "ObjectType", keylen) )
{
if ( !vtkMetaImageReaderInternal::StringEqualsCase(value, "Image", valuelen) )
{
if ( populate )
{
vtkErrorMacro(<<"Only understand image data. This is not an image data");
}
return 0;
}
vtkDebugMacro(<< "* Have image data");
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "NDims", keylen) )
{
sscanf(value, "%d", &ndims);
if ( ndims <= 0 || ndims >= 4)
{
if ( populate )
{
vtkErrorMacro(
<< "Only understands image data of 1, 2, or 3 dimensions. This image has "
<< ndims << " dimensions");
}
return 0;
}
vtkDebugMacro(<< "* This image has " << ndims << " dimensions");
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "BinaryData", keylen) )
{
if ( !vtkMetaImageReaderInternal::StringEqualsCase(value, "true", valuelen) )
{
if ( populate )
{
vtkErrorMacro(
<< "Only understand binary image data. This one has BinaryData set to: "
<< value);
}
return 0;
}
vtkDebugMacro(<< "* This image has binary data");
}
else if ( vtkMetaImageReaderInternal::StringEquals(key,
"BinaryDataByteOrderMSB", keylen) )
{
if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "true", valuelen) )
{
bigendian = 1;
}
else
{
bigendian = 0;
}
vtkDebugMacro(<< "* This image has data which is "
<< (bigendian?"big":"little") << " endian");
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "DimSize", keylen) )
{
sscanf(value, "%d %d %d", dims, dims+1, dims+2);
vtkDebugMacro(<< "* This image has dimensions "
<< dims[0] << " " << dims[1] << " " << dims[2]);
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "ElementSpacing", keylen) )
{
sscanf(value, "%lf %lf %lf", spacing, spacing+1, spacing+2);
vtkDebugMacro(<< "* This image has spacing "
<< spacing[0] << " " << spacing[1] << " " << spacing[2]);
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "Position", keylen) )
{
sscanf(value, "%lf %lf %lf", origin, origin+1, origin+2);
vtkDebugMacro(<< "* This image has origin "
<< origin[0] << " " << origin[1] << " " << origin[2]);
}
else if ( vtkMetaImageReaderInternal::StringEquals(key,
"ElementNumberOfChannels", keylen) )
{
sscanf(value, "%d", &number_of_channels);
if ( ndims <= 0 )
{
if ( populate )
{
vtkErrorMacro(
<< "Only understands image data of 1 or more channels. This image has "
<< number_of_channels << " dimensions");
}
return 0;
}
vtkDebugMacro(<< "* This image has " << number_of_channels << " channels");
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "ElementType", keylen) )
{
if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_CHAR", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_CHAR_ARRAY", valuelen) )
{
data_type = VTK_CHAR;
size_type = sizeof(char);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_UCHAR", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_UCHAR_ARRAY", valuelen) )
{
data_type = VTK_UNSIGNED_CHAR;
size_type = sizeof(unsigned char);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_SHORT", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_SHORT_ARRAY", valuelen) )
{
data_type = VTK_SHORT;
size_type = sizeof(short);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_USHORT", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_USHORT_ARRAY", valuelen) )
{
data_type = VTK_UNSIGNED_SHORT;
size_type = sizeof(unsigned short);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_INT", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_INT_ARRAY", valuelen) )
{
data_type = VTK_INT;
size_type = sizeof(int);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_UINT", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_UINT_ARRAY", valuelen) )
{
data_type = VTK_UNSIGNED_INT;
size_type = sizeof(unsigned int);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_LONG", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_LONG_ARRAY", valuelen) )
{
data_type = VTK_LONG;
size_type = sizeof(long);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_ULONG", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_ULONG_ARRAY", valuelen) )
{
data_type = VTK_UNSIGNED_LONG;
size_type = sizeof(unsigned long);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_FLOAT", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_FLOAT_ARRAY", valuelen) )
{
data_type = VTK_FLOAT;
size_type = sizeof(float);
}
else if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_DOUBLE", valuelen) ||
vtkMetaImageReaderInternal::StringEqualsCase(value, "MET_DOUBLE_ARRAY", valuelen) )
{
data_type = VTK_DOUBLE;
size_type = sizeof(double);
}
else
{
if ( populate )
{
vtkErrorMacro(<< "Unknown data type: " << value);
}
return 0;
}
}
else if ( vtkMetaImageReaderInternal::StringEquals(key, "ElementDataFile", keylen) )
{
if ( vtkMetaImageReaderInternal::StringEqualsCase(value, "LOCAL", valuelen) )
{
datafile = fname;
}
else
{
if ( value[0] == '/' ||
( value[1] == ':' && ( value[2] == '/' || value[2] == '\\' ) ) ||
( value[0] == '\\' && value[1] == '\\' ) ||
path.size() == 0)
{
datafile = "";
datafile.append(value, valuelen);
vtkDebugMacro("Use absolute path");
}
else
{
datafile = path;
datafile += "/";
datafile.append(value, valuelen);
vtkDebugMacro("Use relative path");
}
if ( stat( datafile.c_str(), &fs) )
{
if ( populate )
{
vtkErrorMacro(<< "Initialize: Could not open file " << datafile.c_str());
}
return 0;
}
vtkDebugMacro(<< "* Use data file: " << datafile.c_str());
}
}
}
else
{
if ( datafile == fname )
{
break;
}
if ( populate )
{
vtkErrorMacro(<< "Problem parsing line: " << count << " of file: " << fname);
}
return 0;
}
}
if ( ndims <= 0 )
{
if ( populate )
{
vtkErrorMacro(<< "Number of dimensions not specified");
}
return 0;
}
int cc;
for ( cc = 0; cc < ndims; cc ++ )
{
if ( dims[cc] <= 0 )
{
if ( populate )
{
vtkErrorMacro(<< "Dimension " << cc << " is " << dims[cc]);
}
return 0;
}
if ( spacing[cc] == 0 )
{
if ( populate )
{
vtkErrorMacro(<< "Spacing " << cc << " is 0.");
}
return 0;
}
}
for ( cc = ndims; cc < 3; cc ++ )
{
dims[cc] = 1;
}
if ( populate )
{
this->DataScalarType = data_type;
//this->SetDataScalarType(data_type);
this->SetNumberOfScalarComponents(number_of_channels);
this->SetDataExtent(0, dims[0]-1, 0, dims[1]-1, 0, dims[2]-1);
this->SetFileDimensionality(3);
this->SetDataSpacing(spacing);
this->SetDataOrigin(origin);
this->FileLowerLeftOn();
if ( bigendian )
{
this->SetDataByteOrderToBigEndian();
}
else
{
this->SetDataByteOrderToLittleEndian();
}
this->Superclass::SetFileName(datafile.c_str());
}
if ( datafile == fname )
{
unsigned long datasize = number_of_channels * dims[0] * dims[1] * dims[2] * size_type;
unsigned long filesize = fs.st_size;
if ( filesize < datasize )
{
if ( populate )
{
vtkErrorMacro("File size (" << filesize << ") is less than datasize ("
<< datasize << ")");
}
return 0;
}
headerlen = filesize - datasize;
vtkDebugMacro("Read raw data from local file");
}
else
{
vtkDebugMacro("Read raw file: " << datafile.c_str());
}
if ( populate )
{
this->SetHeaderSize(headerlen);
}
return 3;
}
//----------------------------------------------------------------------------
int vtkMetaImageReader::CanReadFile(const char* fname)
{
return this->GetFileInformation(fname, 0);
}
//----------------------------------------------------------------------------
void vtkMetaImageReader::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "MHDFileName: " << (this->MHDFileName?this->MHDFileName:"(none)") << endl;
}