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.
 
 
 
 
 
 

636 lines
16 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkBMPReader.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 "vtkBMPReader.h"
#include "vtkByteSwap.h"
#include "vtkImageData.h"
#include "vtkLookupTable.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
vtkCxxRevisionMacro(vtkBMPReader, "$Revision: 1.53 $");
vtkStandardNewMacro(vtkBMPReader);
#ifdef read
#undef read
#endif
#ifdef close
#undef close
#endif
vtkBMPReader::vtkBMPReader()
{
this->Colors = NULL;
this->SetDataByteOrderToLittleEndian();
this->Depth = 0;
// we need to create it now in case its asked for later (pointer must be valid)
this->LookupTable = vtkLookupTable::New();
this->Allow8BitBMP = 0;
}
//----------------------------------------------------------------------------
vtkBMPReader::~vtkBMPReader()
{
// free any old memory
if (this->Colors)
{
delete [] this->Colors;
this->Colors = NULL;
}
if (this->LookupTable)
{
this->LookupTable->Delete();
this->LookupTable = NULL;
}
}
void vtkBMPReader::ExecuteInformation()
{
int xsize, ysize;
FILE *fp;
long tmp;
short stmp;
long infoSize;
int iinfoSize; // in case we are on a 64bit machine
int itmp; // in case we are on a 64bit machine
// free any old memory
if (this->Colors)
{
delete [] this->Colors;
this->Colors = NULL;
}
// if the user has not set the extent, but has set the VOI
// set the zaxis extent to the VOI z axis
if (this->DataExtent[4]==0 && this->DataExtent[5] == 0 &&
(this->DataVOI[4] || this->DataVOI[5]))
{
this->DataExtent[4] = this->DataVOI[4];
this->DataExtent[5] = this->DataVOI[5];
}
this->ComputeInternalFileName(this->DataExtent[4]);
if (this->InternalFileName == NULL || this->InternalFileName[0] == '\0')
{
return;
}
// get the magic number by reading in a file
fp = fopen(this->InternalFileName,"rb");
if (!fp)
{
vtkErrorMacro("Unable to open file " << this->InternalFileName);
return;
}
// compare magic number to determine file type
if ((fgetc(fp) != 'B')||(fgetc(fp) != 'M'))
{
vtkErrorMacro(<<"Unknown file type! " << this->InternalFileName
<<" is not a Windows BMP file!");
fclose(fp);
return;
}
// get the size of the file
int sizeLong = sizeof(long);
if (sizeLong == 4)
{
fread(&tmp,4,1,fp);
// skip 4 bytes
fread(&tmp,4,1,fp);
// read the offset
fread(&tmp,4,1,fp);
}
else
{
fread(&itmp,4,1,fp);
// skip 4 bytes
fread(&itmp,4,1,fp);
// read the offset
fread(&itmp,4,1,fp);
}
// get size of header
if (sizeLong == 4) // if we are on a 32 bit machine
{
fread(&infoSize,sizeof(long),1,fp);
vtkByteSwap::Swap4LE(&infoSize);
// error checking
if ((infoSize != 40)&&(infoSize != 12))
{
vtkErrorMacro(<<"Unknown file type! " << this->InternalFileName
<<" is not a Windows BMP file!");
fclose(fp);
return;
}
// there are two different types of BMP files
if (infoSize == 40)
{
// now get the dimensions
fread(&xsize,sizeof(long),1,fp);
vtkByteSwap::Swap4LE(&xsize);
fread(&ysize,sizeof(long),1,fp);
vtkByteSwap::Swap4LE(&ysize);
}
else
{
fread(&stmp,sizeof(short),1,fp);
vtkByteSwap::Swap2LE(&stmp);
xsize = stmp;
fread(&stmp,sizeof(short),1,fp);
vtkByteSwap::Swap2LE(&stmp);
ysize = stmp;
}
}
else // else we are on a 64bit machine
{
fread(&iinfoSize,sizeof(int),1,fp);
vtkByteSwap::Swap4LE(&iinfoSize);
infoSize = iinfoSize;
// error checking
if ((infoSize != 40)&&(infoSize != 12))
{
vtkErrorMacro(<<"Unknown file type! " << this->InternalFileName
<<" is not a Windows BMP file!");
fclose(fp);
return;
}
// there are two different types of BMP files
if (infoSize == 40)
{
// now get the dimensions
fread(&xsize,sizeof(int),1,fp);
vtkByteSwap::Swap4LE(&xsize);
fread(&ysize,sizeof(int),1,fp);
vtkByteSwap::Swap4LE(&ysize);
}
else
{
fread(&stmp,sizeof(short),1,fp);
vtkByteSwap::Swap2LE(&stmp);
xsize = stmp;
fread(&stmp,sizeof(short),1,fp);
vtkByteSwap::Swap2LE(&stmp);
ysize = stmp;
}
}
// is corner in upper left or lower left
if (ysize < 0)
{
ysize = ysize*-1;
this->FileLowerLeft = 0;
}
else
{
this->FileLowerLeft = 1;
}
// ignore planes
fread(&stmp,sizeof(short),1,fp);
// read depth
fread(&this->Depth,sizeof(short),1,fp);
vtkByteSwap::Swap2LE(&this->Depth);
if ((this->Depth != 8)&&(this->Depth != 24))
{
vtkErrorMacro(<<"Only BMP depths of (8,24) are supported. Not " << this->Depth);
fclose(fp);
return;
}
// skip over rest of info for long format
if (infoSize == 40)
{
fread(&tmp,4,1,fp);
fread(&tmp,4,1,fp);
fread(&tmp,4,1,fp);
fread(&tmp,4,1,fp);
fread(&tmp,4,1,fp);
fread(&tmp,4,1,fp);
}
// read in color table if required
if (this->Depth < 24)
{
int numColors = 256;
this->Colors = new unsigned char [numColors*3];
for (tmp = 0; tmp < numColors; tmp++)
{
this->Colors[tmp*3+2] = fgetc(fp);
this->Colors[tmp*3+1] = fgetc(fp);
this->Colors[tmp*3] = fgetc(fp);
if (infoSize == 40)
{
fgetc(fp);
}
}
if (this->Allow8BitBMP)
{
if (!this->LookupTable)
{
this->LookupTable = vtkLookupTable::New();
}
this->LookupTable->SetNumberOfTableValues(numColors);
for (tmp=0; tmp<numColors; tmp++)
{
this->LookupTable->SetTableValue(tmp,
(float)this->Colors[tmp*3+0]/255.0,
(float)this->Colors[tmp*3+1]/255.0,
(float)this->Colors[tmp*3+2]/255.0,
1);
}
this->LookupTable->SetRange(0,255);
}
}
if (fclose(fp))
{
vtkWarningMacro("File close failed on " << this->InternalFileName);
}
// if the user has set the VOI, just make sure its valid
if (this->DataVOI[0] || this->DataVOI[1] ||
this->DataVOI[2] || this->DataVOI[3] ||
this->DataVOI[4] || this->DataVOI[5])
{
if ((this->DataVOI[0] < 0) ||
(this->DataVOI[1] >= xsize) ||
(this->DataVOI[2] < 0) ||
(this->DataVOI[3] >= ysize))
{
vtkWarningMacro("The requested VOI is larger than the file's (" << this->InternalFileName << ") extent ");
this->DataVOI[0] = 0;
this->DataVOI[1] = xsize - 1;
this->DataVOI[2] = 0;
this->DataVOI[3] = ysize - 1;
}
}
this->DataExtent[0] = 0;
this->DataExtent[1] = xsize - 1;
this->DataExtent[2] = 0;
this->DataExtent[3] = ysize - 1;
this->SetDataScalarTypeToUnsignedChar();
if ((this->Depth == 8) && this->Allow8BitBMP)
{
this->SetNumberOfScalarComponents(1);
}
else
{
this->SetNumberOfScalarComponents(3);
}
this->vtkImageReader::ExecuteInformation();
}
//----------------------------------------------------------------------------
// This function opens a file to determine the file size, and to
// automatically determine the header size.
void vtkBMPReader::ComputeDataIncrements()
{
int idx;
vtkIdType fileDataLength;
// Determine the expected length of the data ...
switch (this->DataScalarType)
{
case VTK_FLOAT:
fileDataLength = sizeof(float);
break;
case VTK_INT:
fileDataLength = sizeof(int);
break;
case VTK_SHORT:
fileDataLength = sizeof(short);
break;
case VTK_UNSIGNED_SHORT:
fileDataLength = sizeof(unsigned short);
break;
case VTK_UNSIGNED_CHAR:
fileDataLength = sizeof(unsigned char);
break;
default:
vtkErrorMacro(<< "Unknown DataScalarType");
return;
}
fileDataLength *= (this->Depth/8);
// a row must end on a 4 byte boundary
// so update the Increments[1]
this->DataIncrements[0] = fileDataLength;
fileDataLength = fileDataLength *
(this->DataExtent[1] - this->DataExtent[0] + 1);
// move to 4 byte boundary
fileDataLength = fileDataLength + (4 - fileDataLength%4)%4;
// compute the fileDataLength (in units of bytes)
for (idx = 1; idx < 3; ++idx)
{
this->DataIncrements[idx] = fileDataLength;
fileDataLength = fileDataLength *
(this->DataExtent[idx*2+1] - this->DataExtent[idx*2] + 1);
}
}
//----------------------------------------------------------------------------
// This function reads in one data of data.
// templated to handle different data types.
template <class OT>
void vtkBMPReaderUpdate2(vtkBMPReader *self, vtkImageData *data, OT *outPtr)
{
vtkIdType inIncr[3], outIncr[3];
OT *outPtr0, *outPtr1, *outPtr2;
vtkIdType streamSkip0, streamSkip1;
vtkIdType streamRead;
int idx0, idx1, idx2, pixelRead;
unsigned char *buf;
int inExtent[6];
int dataExtent[6];
int pixelSkip;
unsigned char *inPtr;
unsigned char *Colors;
unsigned long count = 0;
unsigned long target;
int Keep8bit = 0;
// Get the requested extents.
data->GetExtent(inExtent);
// Convert them into to the extent needed from the file.
self->ComputeInverseTransformedExtent(inExtent,dataExtent);
// get and transform the increments
data->GetIncrements(inIncr);
self->ComputeInverseTransformedIncrements(inIncr,outIncr);
// get the color lut
Colors = self->GetColors();
// are we converting to RGB or staying as 8bit
if ((self->GetDepth() == 8) && self->GetAllow8BitBMP())
{
Keep8bit = 1;
}
// compute outPtr2
outPtr2 = outPtr;
if (outIncr[0] < 0)
{
outPtr2 = outPtr2 - outIncr[0]*(dataExtent[1] - dataExtent[0]);
}
if (outIncr[1] < 0)
{
outPtr2 = outPtr2 - outIncr[1]*(dataExtent[3] - dataExtent[2]);
}
if (outIncr[2] < 0)
{
outPtr2 = outPtr2 - outIncr[2]*(dataExtent[5] - dataExtent[4]);
}
// length of a row, num pixels read at a time
pixelRead = dataExtent[1] - dataExtent[0] + 1;
streamRead = (vtkIdType) (pixelRead * self->GetDataIncrements()[0]);
streamSkip0 = (vtkIdType) (self->GetDataIncrements()[1] - streamRead);
streamSkip1 = (vtkIdType) (self->GetDataIncrements()[2] -
(dataExtent[3] - dataExtent[2] + 1)* self->GetDataIncrements()[1]);
pixelSkip = self->GetDepth()/8;
// read from the bottom up
if (!self->GetFileLowerLeft())
{
streamSkip0 = (vtkIdType) (-streamRead - self->GetDataIncrements()[1]);
}
// create a buffer to hold a row of the data
buf = new unsigned char[streamRead];
target = (unsigned long)((dataExtent[5]-dataExtent[4]+1)*
(dataExtent[3]-dataExtent[2]+1)/50.0);
target++;
// read the data row by row
if (self->GetFileDimensionality() == 3)
{
if (!self->OpenAndSeekFile(dataExtent,0))
{
return;
}
}
for (idx2 = dataExtent[4]; idx2 <= dataExtent[5]; ++idx2)
{
if (self->GetFileDimensionality() == 2)
{
if (!self->OpenAndSeekFile(dataExtent,idx2))
{
return;
}
}
outPtr1 = outPtr2;
for (idx1 = dataExtent[2];
!self->AbortExecute && idx1 <= dataExtent[3]; ++idx1)
{
if (!(count%target))
{
self->UpdateProgress(count/(50.0*target));
}
count++;
outPtr0 = outPtr1;
// read the row.
if ( ! self->GetFile()->read((char *)buf, streamRead))
{
vtkGenericWarningMacro("File operation failed. row = " << idx1
<< ", Read = " << streamRead
<< ", Skip0 = " << streamSkip0
<< ", Skip1 = " << streamSkip1
<< ", FilePos = " << static_cast<vtkIdType>(self->GetFile()->tellg())
<< ", FileName = " << self->GetInternalFileName()
);
self->GetFile()->close();
return;
}
// copy the bytes into the typed data
inPtr = buf;
for (idx0 = dataExtent[0]; idx0 <= dataExtent[1]; ++idx0)
{
// Copy pixel into the output.
if (self->GetDepth() == 8 && !Keep8bit)
{
outPtr0[0] = (OT)(Colors[inPtr[0]*3]);
outPtr0[1] = (OT)(Colors[inPtr[0]*3+1]);
outPtr0[2] = (OT)(Colors[inPtr[0]*3+2]);
}
else if (self->GetDepth() == 8 && Keep8bit)
{
outPtr0[0] = (OT)(inPtr[0]);
}
else
{
outPtr0[0] = (OT)(inPtr[2]);
outPtr0[1] = (OT)(inPtr[1]);
outPtr0[2] = (OT)(inPtr[0]);
}
// move to next pixel
inPtr += pixelSkip;
outPtr0 += outIncr[0];
}
// move to the next row in the file and data
self->GetFile()->seekg(static_cast<long>(self->GetFile()->tellg()) + streamSkip0, ios::beg);
outPtr1 += outIncr[1];
}
// move to the next image in the file and data
self->GetFile()->seekg(static_cast<long>(self->GetFile()->tellg()) + streamSkip1, ios::beg);
outPtr2 += outIncr[2];
}
self->GetFile()->close();
// delete the temporary buffer
delete [] buf;
}
//----------------------------------------------------------------------------
// This function reads a data from a file. The datas extent/axes
// are assumed to be the same as the file extent/order.
void vtkBMPReader::ExecuteData(vtkDataObject *output)
{
vtkImageData *data = this->AllocateOutputData(output);
if (this->UpdateExtentIsEmpty(output))
{
return;
}
if (this->InternalFileName == NULL)
{
vtkErrorMacro(<< "Either a FileName or FilePrefix must be specified.");
return;
}
data->GetPointData()->GetScalars()->SetName("BMPImage");
this->ComputeDataIncrements();
// Call the correct templated function for the output
void *outPtr;
// Call the correct templated function for the input
outPtr = data->GetScalarPointer();
switch (data->GetScalarType())
{
vtkTemplateMacro(
vtkBMPReaderUpdate2(this, data, static_cast<VTK_TT*>(outPtr))
);
default:
vtkErrorMacro(<< "Execute: Unknown data type");
}
}
void vtkBMPReader::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
// this->Colors is not printed
os << indent << "Depth: " << this->Depth << "\n";
os << indent << "Allow8BitBMP: " << this->Allow8BitBMP << "\n";
if (this->LookupTable)
{
os << indent << "LookupTable: " << this->LookupTable << "\n";
}
else
{
os << indent << "LookupTable: NULL\n";
}
}
int vtkBMPReader::CanReadFile(const char* fname)
{
// get the magic number by reading in a file
FILE* fp = fopen(fname,"rb");
if (!fp)
{
return 0;
}
// compare magic number to determine file type
if ((fgetc(fp) != 'B')||(fgetc(fp) != 'M'))
{
fclose(fp);
return 0;
}
long tmp;
long infoSize;
int iinfoSize; // in case we are on a 64bit machine
int itmp; // in case we are on a 64bit machine
// get the size of the file
int sizeLong = sizeof(long);
if (sizeLong == 4)
{
fread(&tmp,4,1,fp);
// skip 4 bytes
fread(&tmp,4,1,fp);
// read the offset
fread(&tmp,4,1,fp);
}
else
{
fread(&itmp,4,1,fp);
// skip 4 bytes
fread(&itmp,4,1,fp);
// read the offset
fread(&itmp,4,1,fp);
}
// get size of header
int res = 3;
if (sizeLong == 4) // if we are on a 32 bit machine
{
fread(&infoSize,sizeof(long),1,fp);
vtkByteSwap::Swap4LE(&infoSize);
// error checking
if ((infoSize != 40)&&(infoSize != 12))
{
fclose(fp);
return 0;
}
}
else // else we are on a 64bit machine
{
fread(&iinfoSize,sizeof(int),1,fp);
vtkByteSwap::Swap4LE(&iinfoSize);
infoSize = iinfoSize;
// error checking
if ((infoSize != 40)&&(infoSize != 12))
{
fclose(fp);
res = 0;
}
}
fclose(fp);
return res;
}