Initial source commit
This commit is contained in:
commit
f1384c11ee
335 changed files with 52715 additions and 0 deletions
251
minorGems/graphics/converters/BMPImageConverter.h
Normal file
251
minorGems/graphics/converters/BMPImageConverter.h
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Modification History
|
||||
*
|
||||
* 2001-February-19 Jason Rohrer
|
||||
* Created.
|
||||
*
|
||||
* 2001-February-19 Jason Rohrer
|
||||
* Fixed some bugs in the raster formatting code.
|
||||
*
|
||||
* 2001-May-19 Jason Rohrer
|
||||
* Fixed a bug in zero padding for each line.
|
||||
*
|
||||
* 2001-May-21 Jason Rohrer
|
||||
* Fixed another bug in zero padding for each line.
|
||||
*
|
||||
* 2001-September-22 Jason Rohrer
|
||||
* Changed to subclass LittleEndianImageConverter.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BMP_IMAGE_CONVERTER_INCLUDED
|
||||
#define BMP_IMAGE_CONVERTER_INCLUDED
|
||||
|
||||
|
||||
#include "LittleEndianImageConverter.h"
|
||||
|
||||
|
||||
/**
|
||||
* Windows BMP implementation of the image conversion interface.
|
||||
*
|
||||
* Note that it only supports 24-bit BMP files (and thus only 3-channel
|
||||
* Images).
|
||||
*
|
||||
* BMP format information taken from:
|
||||
* http://www.daubnet.com/formats/BMP.html
|
||||
* Some information from this site is incorrect:
|
||||
* 24-bit pixels are _not_ stored in 32-bit blocks.
|
||||
*
|
||||
* @author Jason Rohrer
|
||||
*/
|
||||
class BMPImageConverter : public LittleEndianImageConverter {
|
||||
|
||||
public:
|
||||
|
||||
// implement the ImageConverter interface
|
||||
virtual void formatImage( Image *inImage,
|
||||
OutputStream *inStream );
|
||||
|
||||
virtual Image *deformatImage( InputStream *inStream );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void BMPImageConverter::formatImage( Image *inImage,
|
||||
OutputStream *inStream ) {
|
||||
|
||||
// make sure the image is in the right format
|
||||
if( inImage->getNumChannels() != 3 ) {
|
||||
printf(
|
||||
"Only 3-channel images can be converted to the BMP format.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
long width = inImage->getWidth();
|
||||
long height = inImage->getHeight();
|
||||
|
||||
long numPixels = width * height;
|
||||
|
||||
// each line should be padded with zeros to
|
||||
// end on a 4-byte boundary
|
||||
int numZeroPaddingBytes = ( 4 - ( width * 3 ) % 4 ) % 4;
|
||||
|
||||
short bitCount = 24;
|
||||
long rasterSize = numPixels * 3;
|
||||
// zero padding bytes for each row
|
||||
rasterSize += numZeroPaddingBytes * height;
|
||||
|
||||
// offset past two headers
|
||||
long offsetToRaster = 14 + 40;
|
||||
|
||||
long fileSize = offsetToRaster + rasterSize;
|
||||
|
||||
long compressionType = 0;
|
||||
|
||||
|
||||
long pixelsPerMeter = 2834;
|
||||
|
||||
// both are 0 since we have no color map
|
||||
long colorsUsed = 0;
|
||||
long colorsImportant = 0;
|
||||
|
||||
// write the header
|
||||
unsigned char *signature = new unsigned char[2];
|
||||
signature[0] = 'B';
|
||||
signature[1] = 'M';
|
||||
inStream->write( signature, 2 );
|
||||
delete [] signature;
|
||||
writeLittleEndianLong( fileSize, inStream );
|
||||
writeLittleEndianLong( 0, inStream );
|
||||
writeLittleEndianLong( offsetToRaster, inStream );
|
||||
|
||||
// write the info header
|
||||
// header size
|
||||
writeLittleEndianLong( 40, inStream );
|
||||
writeLittleEndianLong( width, inStream );
|
||||
writeLittleEndianLong( height, inStream );
|
||||
// numPlanes
|
||||
writeLittleEndianShort( 1, inStream );
|
||||
writeLittleEndianShort( bitCount, inStream );
|
||||
writeLittleEndianLong( compressionType, inStream );
|
||||
writeLittleEndianLong( rasterSize, inStream );
|
||||
writeLittleEndianLong( pixelsPerMeter, inStream );
|
||||
writeLittleEndianLong( pixelsPerMeter, inStream );
|
||||
writeLittleEndianLong( colorsUsed, inStream );
|
||||
writeLittleEndianLong( colorsImportant, inStream );
|
||||
|
||||
// no color table...
|
||||
|
||||
// now write the raster
|
||||
|
||||
unsigned char *raster = new unsigned char[ rasterSize ];
|
||||
double *red = inImage->getChannel( 0 );
|
||||
double *green = inImage->getChannel( 1 );
|
||||
double *blue = inImage->getChannel( 2 );
|
||||
|
||||
// pixels are stored bottom-up, left to right
|
||||
// (row major order)
|
||||
|
||||
long rasterIndex = 0;
|
||||
for( int y=height-1; y>=0; y-- ) {
|
||||
for( int x=0; x<width; x++ ) {
|
||||
int imageIndex = y * width + x;
|
||||
|
||||
raster[rasterIndex] =
|
||||
(unsigned char)( 255 * blue[imageIndex] );
|
||||
raster[rasterIndex + 1] =
|
||||
(unsigned char)( 255 * green[imageIndex] );
|
||||
raster[rasterIndex + 2] =
|
||||
(unsigned char)( 255 * red[imageIndex] );
|
||||
|
||||
rasterIndex += 3;
|
||||
}
|
||||
|
||||
for( int p=0; p<numZeroPaddingBytes; p++ ) {
|
||||
// insert at the end of this line
|
||||
raster[ rasterIndex ] = 0;
|
||||
rasterIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
inStream->write( raster, rasterSize );
|
||||
|
||||
delete [] raster;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline Image *BMPImageConverter::deformatImage( InputStream *inStream ) {
|
||||
// temp buffer used to skip data in the stream
|
||||
unsigned char *temp = new unsigned char[ 100 ];
|
||||
|
||||
// skip signature
|
||||
inStream->read( temp, 2 );
|
||||
|
||||
long fileSize = readLittleEndianLong( inStream );
|
||||
|
||||
// skip unused
|
||||
inStream->read( temp, 4 );
|
||||
|
||||
long rasterOffset = readLittleEndianLong( inStream );
|
||||
long rasterSize = fileSize - rasterOffset;
|
||||
|
||||
// skip size of header
|
||||
inStream->read( temp, 4 );
|
||||
|
||||
long width = readLittleEndianLong( inStream );
|
||||
long height = readLittleEndianLong( inStream );
|
||||
|
||||
// skip planes
|
||||
inStream->read( temp, 2 );
|
||||
|
||||
short bitCount = readLittleEndianShort( inStream );
|
||||
|
||||
char failing = false;
|
||||
if( bitCount != 24 ) {
|
||||
printf( "Only 24-bit BMP file formats supported.\n" );
|
||||
failing = true;
|
||||
}
|
||||
long compression = readLittleEndianLong( inStream );
|
||||
if( compression != 0 ) {
|
||||
printf( "Only uncompressed BMP file formats supported.\n" );
|
||||
failing = true;
|
||||
}
|
||||
|
||||
// skip imageSize, resolution, and color usage information
|
||||
inStream->read( temp, 20 );
|
||||
|
||||
// now we're at the raster.
|
||||
|
||||
// each line should be padded with zeros to
|
||||
// end on a 4-byte boundary
|
||||
int numZeroPaddingBytes = ( 4 - ( width * 3 ) % 4 ) % 4;
|
||||
|
||||
unsigned char *raster = new unsigned char[ rasterSize ];
|
||||
inStream->read( raster, rasterSize );
|
||||
Image *returnImage;
|
||||
if( failing ) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
|
||||
returnImage = new Image( width, height, 3 );
|
||||
|
||||
double *red = returnImage->getChannel( 0 );
|
||||
double *green = returnImage->getChannel( 1 );
|
||||
double *blue = returnImage->getChannel( 2 );
|
||||
|
||||
// pixels are stored bottom-up, left to right
|
||||
// (row major order)
|
||||
|
||||
long rasterIndex = 0;
|
||||
for( int y=height-1; y>=0; y-- ) {
|
||||
for( int x=0; x<width; x++ ) {
|
||||
int imageIndex = y * width + x;
|
||||
|
||||
blue[imageIndex] =
|
||||
(double)( raster[rasterIndex] ) / 255.0;
|
||||
green[imageIndex] =
|
||||
(double)( raster[rasterIndex + 1] ) / 255.0;
|
||||
red[imageIndex] =
|
||||
(double)( raster[rasterIndex + 2] ) / 255.0;
|
||||
|
||||
rasterIndex += 3;
|
||||
}
|
||||
|
||||
// skip the zero padding bytes at the end of this line
|
||||
rasterIndex += numZeroPaddingBytes;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] raster;
|
||||
delete [] temp;
|
||||
|
||||
return returnImage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue