kora-bot/Source/BWEM/EasyBMP_1.06/EasyBMP.cpp

1912 lines
49 KiB
C++

/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP.cpp *
* date added: 03-31-2006 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Actual source file *
* *
*************************************************/
#include "EasyBMP.h"
/* These functions are defined in EasyBMP.h */
bool EasyBMPwarnings = true;
void SetEasyBMPwarningsOff( void )
{ EasyBMPwarnings = false; }
void SetEasyBMPwarningsOn( void )
{ EasyBMPwarnings = true; }
bool GetEasyBMPwarningState( void )
{ return EasyBMPwarnings; }
/* These functions are defined in EasyBMP_DataStructures.h */
int IntPow( int base, int exponent )
{
int i;
int output = 1;
for( i=0 ; i < exponent ; i++ )
{ output *= base; }
return output;
}
BMFH::BMFH()
{
bfType = 19778;
bfReserved1 = 0;
bfReserved2 = 0;
}
void BMFH::SwitchEndianess( void )
{
bfType = FlipWORD( bfType );
bfSize = FlipDWORD( bfSize );
bfReserved1 = FlipWORD( bfReserved1 );
bfReserved2 = FlipWORD( bfReserved2 );
bfOffBits = FlipDWORD( bfOffBits );
return;
}
BMIH::BMIH()
{
biPlanes = 1;
biCompression = 0;
biXPelsPerMeter = DefaultXPelsPerMeter;
biYPelsPerMeter = DefaultYPelsPerMeter;
biClrUsed = 0;
biClrImportant = 0;
}
void BMIH::SwitchEndianess( void )
{
biSize = FlipDWORD( biSize );
biWidth = FlipDWORD( biWidth );
biHeight = FlipDWORD( biHeight );
biPlanes = FlipWORD( biPlanes );
biBitCount = FlipWORD( biBitCount );
biCompression = FlipDWORD( biCompression );
biSizeImage = FlipDWORD( biSizeImage );
biXPelsPerMeter = FlipDWORD( biXPelsPerMeter );
biYPelsPerMeter = FlipDWORD( biYPelsPerMeter );
biClrUsed = FlipDWORD( biClrUsed );
biClrImportant = FlipDWORD( biClrImportant );
return;
}
void BMIH::display( void )
{
using namespace std;
cout << "biSize: " << (int) biSize << endl
<< "biWidth: " << (int) biWidth << endl
<< "biHeight: " << (int) biHeight << endl
<< "biPlanes: " << (int) biPlanes << endl
<< "biBitCount: " << (int) biBitCount << endl
<< "biCompression: " << (int) biCompression << endl
<< "biSizeImage: " << (int) biSizeImage << endl
<< "biXPelsPerMeter: " << (int) biXPelsPerMeter << endl
<< "biYPelsPerMeter: " << (int) biYPelsPerMeter << endl
<< "biClrUsed: " << (int) biClrUsed << endl
<< "biClrImportant: " << (int) biClrImportant << endl << endl;
}
void BMFH::display( void )
{
using namespace std;
cout << "bfType: " << (int) bfType << endl
<< "bfSize: " << (int) bfSize << endl
<< "bfReserved1: " << (int) bfReserved1 << endl
<< "bfReserved2: " << (int) bfReserved2 << endl
<< "bfOffBits: " << (int) bfOffBits << endl << endl;
}
/* These functions are defined in EasyBMP_BMP.h */
RGBApixel BMP::GetPixel( int i, int j ) const
{
using namespace std;
bool Warn = false;
if( i >= Width )
{ i = Width-1; Warn = true; }
if( i < 0 )
{ i = 0; Warn = true; }
if( j >= Height )
{ j = Height-1; Warn = true; }
if( j < 0 )
{ j = 0; Warn = true; }
if( Warn && EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
<< " Truncating request to fit in the range [0,"
<< Width-1 << "] x [0," << Height-1 << "]." << endl;
}
return Pixels[i][j];
}
bool BMP::SetPixel( int i, int j, RGBApixel NewPixel )
{
Pixels[i][j] = NewPixel;
return true;
}
bool BMP::SetColor( int ColorNumber , RGBApixel NewColor )
{
using namespace std;
if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to change color table for a BMP object" << endl
<< " that lacks a color table. Ignoring request." << endl;
}
return false;
}
if( !Colors )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to set a color, but the color table" << endl
<< " is not defined. Ignoring request." << endl;
}
return false;
}
if( ColorNumber >= TellNumberOfColors() )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Requested color number "
<< ColorNumber << " is outside the allowed" << endl
<< " range [0," << TellNumberOfColors()-1
<< "]. Ignoring request to set this color." << endl;
}
return false;
}
Colors[ColorNumber] = NewColor;
return true;
}
// RGBApixel BMP::GetColor( int ColorNumber ) const
RGBApixel BMP::GetColor( int ColorNumber )
{
RGBApixel Output;
Output.Red = 255;
Output.Green = 255;
Output.Blue = 255;
Output.Alpha = 0;
using namespace std;
if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to access color table for a BMP object" << endl
<< " that lacks a color table. Ignoring request." << endl;
}
return Output;
}
if( !Colors )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Requested a color, but the color table" << endl
<< " is not defined. Ignoring request." << endl;
}
return Output;
}
if( ColorNumber >= TellNumberOfColors() )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Requested color number "
<< ColorNumber << " is outside the allowed" << endl
<< " range [0," << TellNumberOfColors()-1
<< "]. Ignoring request to get this color." << endl;
}
return Output;
}
Output = Colors[ColorNumber];
return Output;
}
BMP::BMP()
{
Width = 1;
Height = 1;
BitDepth = 24;
Pixels = new RGBApixel* [Width];
Pixels[0] = new RGBApixel [Height];
Colors = NULL;
XPelsPerMeter = 0;
YPelsPerMeter = 0;
MetaData1 = NULL;
SizeOfMetaData1 = 0;
MetaData2 = NULL;
SizeOfMetaData2 = 0;
}
// BMP::BMP( const BMP& Input )
BMP::BMP( BMP& Input )
{
// first, make the image empty.
Width = 1;
Height = 1;
BitDepth = 24;
Pixels = new RGBApixel* [Width];
Pixels[0] = new RGBApixel [Height];
Colors = NULL;
XPelsPerMeter = 0;
YPelsPerMeter = 0;
MetaData1 = NULL;
SizeOfMetaData1 = 0;
MetaData2 = NULL;
SizeOfMetaData2 = 0;
// now, set the correct bit depth
SetBitDepth( Input.TellBitDepth() );
// set the correct pixel size
SetSize( Input.TellWidth() , Input.TellHeight() );
// set the DPI information from Input
SetDPI( Input.TellHorizontalDPI() , Input.TellVerticalDPI() );
// if there is a color table, get all the colors
if( BitDepth == 1 || BitDepth == 4 ||
BitDepth == 8 )
{
for( int k=0 ; k < TellNumberOfColors() ; k++ )
{
SetColor( k, Input.GetColor( k ));
}
}
// get all the pixels
for( int j=0; j < Height ; j++ )
{
for( int i=0; i < Width ; i++ )
{
Pixels[i][j] = *Input(i,j);
// Pixels[i][j] = Input.GetPixel(i,j); // *Input(i,j);
}
}
}
BMP::~BMP()
{
int i;
for(i=0;i<Width;i++)
{ delete [] Pixels[i]; }
delete [] Pixels;
if( Colors )
{ delete [] Colors; }
if( MetaData1 )
{ delete [] MetaData1; }
if( MetaData2 )
{ delete [] MetaData2; }
}
RGBApixel* BMP::operator()(int i, int j)
{
using namespace std;
bool Warn = false;
if( i >= Width )
{ i = Width-1; Warn = true; }
if( i < 0 )
{ i = 0; Warn = true; }
if( j >= Height )
{ j = Height-1; Warn = true; }
if( j < 0 )
{ j = 0; Warn = true; }
if( Warn && EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
<< " Truncating request to fit in the range [0,"
<< Width-1 << "] x [0," << Height-1 << "]." << endl;
}
return &(Pixels[i][j]);
}
// int BMP::TellBitDepth( void ) const
int BMP::TellBitDepth( void )
{ return BitDepth; }
// int BMP::TellHeight( void ) const
int BMP::TellHeight( void )
{ return Height; }
// int BMP::TellWidth( void ) const
int BMP::TellWidth( void )
{ return Width; }
// int BMP::TellNumberOfColors( void ) const
int BMP::TellNumberOfColors( void )
{
int output = IntPow( 2, BitDepth );
if( BitDepth == 32 )
{ output = IntPow( 2, 24 ); }
return output;
}
bool BMP::SetBitDepth( int NewDepth )
{
using namespace std;
if( NewDepth != 1 && NewDepth != 4 &&
NewDepth != 8 && NewDepth != 16 &&
NewDepth != 24 && NewDepth != 32 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: User attempted to set unsupported bit depth "
<< NewDepth << "." << endl
<< " Bit depth remains unchanged at "
<< BitDepth << "." << endl;
}
return false;
}
BitDepth = NewDepth;
if( Colors )
{ delete [] Colors; }
int NumberOfColors = IntPow( 2, BitDepth );
if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
{ Colors = new RGBApixel [NumberOfColors]; }
else
{ Colors = NULL; }
if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
{ CreateStandardColorTable(); }
return true;
}
bool BMP::SetSize(int NewWidth , int NewHeight )
{
using namespace std;
if( NewWidth <= 0 || NewHeight <= 0 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: User attempted to set a non-positive width or height." << endl
<< " Size remains unchanged at "
<< Width << " x " << Height << "." << endl;
}
return false;
}
int i,j;
for(i=0;i<Width;i++)
{ delete [] Pixels[i]; }
delete [] Pixels;
Width = NewWidth;
Height = NewHeight;
Pixels = new RGBApixel* [ Width ];
for(i=0; i<Width; i++)
{ Pixels[i] = new RGBApixel [ Height ]; }
for( i=0 ; i < Width ; i++)
{
for( j=0 ; j < Height ; j++ )
{
Pixels[i][j].Red = 255;
Pixels[i][j].Green = 255;
Pixels[i][j].Blue = 255;
Pixels[i][j].Alpha = 0;
}
}
return true;
}
bool BMP::WriteToFile( const char* FileName )
{
using namespace std;
if( !EasyBMPcheckDataSize() )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Data types are wrong size!" << endl
<< " You may need to mess with EasyBMP_DataTypes.h" << endl
<< " to fix these errors, and then recompile." << endl
<< " All 32-bit and 64-bit machines should be" << endl
<< " supported, however." << endl << endl;
}
return false;
}
FILE* fp = fopen( FileName, "wb" );
if( fp == NULL )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Cannot open file "
<< FileName << " for output." << endl;
}
fclose( fp );
return false;
}
// some preliminaries
double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
double dBytesPerRow = dBytesPerPixel * (Width+0.0);
dBytesPerRow = ceil(dBytesPerRow);
int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
if( BytePaddingPerRow == 4 )
{ BytePaddingPerRow = 0; }
double dActualBytesPerRow = dBytesPerRow + BytePaddingPerRow;
double dTotalPixelBytes = Height * dActualBytesPerRow;
double dPaletteSize = 0;
if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
{ dPaletteSize = IntPow(2,BitDepth)*4.0; }
// leave some room for 16-bit masks
if( BitDepth == 16 )
{ dPaletteSize = 3*4; }
double dTotalFileSize = 14 + 40 + dPaletteSize + dTotalPixelBytes;
// write the file header
BMFH bmfh;
bmfh.bfSize = (ebmpDWORD) dTotalFileSize;
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfOffBits = (ebmpDWORD) (14+40+dPaletteSize);
if( IsBigEndian() )
{ bmfh.SwitchEndianess(); }
fwrite( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
fwrite( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
fwrite( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
fwrite( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
// write the info header
BMIH bmih;
bmih.biSize = 40;
bmih.biWidth = Width;
bmih.biHeight = Height;
bmih.biPlanes = 1;
bmih.biBitCount = (ebmpWORD)BitDepth;
bmih.biCompression = 0;
bmih.biSizeImage = (ebmpDWORD) dTotalPixelBytes;
if( XPelsPerMeter )
{ bmih.biXPelsPerMeter = XPelsPerMeter; }
else
{ bmih.biXPelsPerMeter = DefaultXPelsPerMeter; }
if( YPelsPerMeter )
{ bmih.biYPelsPerMeter = YPelsPerMeter; }
else
{ bmih.biYPelsPerMeter = DefaultYPelsPerMeter; }
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
// indicates that we'll be using bit fields for 16-bit files
if( BitDepth == 16 )
{ bmih.biCompression = 3; }
if( IsBigEndian() )
{ bmih.SwitchEndianess(); }
fwrite( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
fwrite( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
fwrite( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
fwrite( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
fwrite( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
// write the palette
if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
{
int NumberOfColors = IntPow(2,BitDepth);
// if there is no palette, create one
if( !Colors )
{
if( !Colors )
{ Colors = new RGBApixel [NumberOfColors]; }
CreateStandardColorTable();
}
int n;
for( n=0 ; n < NumberOfColors ; n++ )
{ fwrite( (char*) &(Colors[n]) , 4 , 1 , fp ); }
}
// write the pixels
int i,j;
if( BitDepth != 16 )
{
ebmpBYTE* Buffer;
int BufferSize = (int) ( (Width*BitDepth)/8.0 );
while( 8*BufferSize < Width*BitDepth )
{ BufferSize++; }
while( BufferSize % 4 )
{ BufferSize++; }
Buffer = new ebmpBYTE [BufferSize];
for( j=0 ; j < BufferSize; j++ )
{ Buffer[j] = 0; }
j=Height-1;
while( j > -1 )
{
bool Success = false;
if( BitDepth == 32 )
{ Success = Write32bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 24 )
{ Success = Write24bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 8 )
{ Success = Write8bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 4 )
{ Success = Write4bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 1 )
{ Success = Write1bitRow( Buffer, BufferSize, j ); }
if( Success )
{
int BytesWritten = (int) fwrite( (char*) Buffer, 1, BufferSize, fp );
if( BytesWritten != BufferSize )
{ Success = false; }
}
if( !Success )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Could not write proper amount of data." << endl;
}
j = -1;
}
j--;
}
delete [] Buffer;
}
if( BitDepth == 16 )
{
// write the bit masks
ebmpWORD BlueMask = 31; // bits 12-16
ebmpWORD GreenMask = 2016; // bits 6-11
ebmpWORD RedMask = 63488; // bits 1-5
ebmpWORD ZeroWORD;
if( IsBigEndian() )
{ RedMask = FlipWORD( RedMask ); }
fwrite( (char*) &RedMask , 2 , 1 , fp );
fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
if( IsBigEndian() )
{ GreenMask = FlipWORD( GreenMask ); }
fwrite( (char*) &GreenMask , 2 , 1 , fp );
fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
if( IsBigEndian() )
{ BlueMask = FlipWORD( BlueMask ); }
fwrite( (char*) &BlueMask , 2 , 1 , fp );
fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
int DataBytes = Width*2;
int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
// write the actual pixels
for( j=Height-1 ; j >= 0 ; j-- )
{
// write all row pixel data
i=0;
int WriteNumber = 0;
while( WriteNumber < DataBytes )
{
ebmpWORD TempWORD;
ebmpWORD RedWORD = (ebmpWORD) ((Pixels[i][j]).Red / 8);
ebmpWORD GreenWORD = (ebmpWORD) ((Pixels[i][j]).Green / 4);
ebmpWORD BlueWORD = (ebmpWORD) ((Pixels[i][j]).Blue / 8);
TempWORD = (RedWORD<<11) + (GreenWORD<<5) + BlueWORD;
if( IsBigEndian() )
{ TempWORD = FlipWORD( TempWORD ); }
fwrite( (char*) &TempWORD , 2, 1, fp);
WriteNumber += 2;
i++;
}
// write any necessary row padding
WriteNumber = 0;
while( WriteNumber < PaddingBytes )
{
ebmpBYTE TempBYTE;
fwrite( (char*) &TempBYTE , 1, 1, fp);
WriteNumber++;
}
}
}
fclose(fp);
return true;
}
bool BMP::ReadFromFile( const char* FileName )
{
using namespace std;
if( !EasyBMPcheckDataSize() )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Data types are wrong size!" << endl
<< " You may need to mess with EasyBMP_DataTypes.h" << endl
<< " to fix these errors, and then recompile." << endl
<< " All 32-bit and 64-bit machines should be" << endl
<< " supported, however." << endl << endl;
}
return false;
}
FILE* fp = fopen( FileName, "rb" );
if( fp == NULL )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Cannot open file "
<< FileName << " for input." << endl;
}
SetBitDepth(1);
SetSize(1,1);
return false;
}
// read the file header
BMFH bmfh;
bool NotCorrupted = true;
NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
bool IsBitmap = false;
if( IsBigEndian() && bmfh.bfType == 16973 )
{ IsBitmap = true; }
if( !IsBigEndian() && bmfh.bfType == 19778 )
{ IsBitmap = true; }
if( !IsBitmap )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName
<< " is not a Windows BMP file!" << endl;
}
fclose( fp );
return false;
}
NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp);
NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
if( IsBigEndian() )
{ bmfh.SwitchEndianess(); }
// read the info header
BMIH bmih;
NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
if( IsBigEndian() )
{ bmih.SwitchEndianess(); }
// a safety catch: if any of the header information didn't read properly, abort
// future idea: check to see if at least most is self-consistent
if( !NotCorrupted )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName
<< " is obviously corrupted." << endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
XPelsPerMeter = bmih.biXPelsPerMeter;
YPelsPerMeter = bmih.biYPelsPerMeter;
// if bmih.biCompression 1 or 2, then the file is RLE compressed
if( bmih.biCompression == 1 || bmih.biCompression == 2 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName << " is (RLE) compressed." << endl
<< " EasyBMP does not support compression." << endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
// if bmih.biCompression > 3, then something strange is going on
// it's probably an OS2 bitmap file.
if( bmih.biCompression > 3 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName << " is in an unsupported format."
<< endl
<< " (bmih.biCompression = "
<< bmih.biCompression << ")" << endl
<< " The file is probably an old OS2 bitmap or corrupted."
<< endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName
<< " uses bit fields and is not a" << endl
<< " 16-bit file. This is not supported." << endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
// set the bit depth
int TempBitDepth = (int) bmih.biBitCount;
if( TempBitDepth != 1 && TempBitDepth != 4
&& TempBitDepth != 8 && TempBitDepth != 16
&& TempBitDepth != 24 && TempBitDepth != 32 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName << " has unrecognized bit depth." << endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
SetBitDepth( (int) bmih.biBitCount );
// set the size
if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: " << FileName
<< " has a non-positive width or height." << endl;
}
SetSize(1,1);
SetBitDepth(1);
fclose(fp);
return false;
}
SetSize( (int) bmih.biWidth , (int) bmih.biHeight );
// some preliminaries
double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
double dBytesPerRow = dBytesPerPixel * (Width+0.0);
dBytesPerRow = ceil(dBytesPerRow);
int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
if( BytePaddingPerRow == 4 )
{ BytePaddingPerRow = 0; }
// if < 16 bits, read the palette
if( BitDepth < 16 )
{
// determine the number of colors specified in the
// color table
int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;
if( NumberOfColorsToRead > IntPow(2,BitDepth) )
{ NumberOfColorsToRead = IntPow(2,BitDepth); }
if( NumberOfColorsToRead < TellNumberOfColors() )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: file " << FileName << " has an underspecified" << endl
<< " color table. The table will be padded with extra" << endl
<< " white (255,255,255,0) entries." << endl;
}
}
int n;
for( n=0; n < NumberOfColorsToRead ; n++ )
{
SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);
}
for( n=NumberOfColorsToRead ; n < TellNumberOfColors() ; n++ )
{
RGBApixel WHITE;
WHITE.Red = 255;
WHITE.Green = 255;
WHITE.Blue = 255;
WHITE.Alpha = 0;
SetColor( n , WHITE );
}
}
// skip blank data if bfOffBits so indicates
int BytesToSkip = bmfh.bfOffBits - 54;;
if( BitDepth < 16 )
{ BytesToSkip -= 4*IntPow(2,BitDepth); }
if( BitDepth == 16 && bmih.biCompression == 3 )
{ BytesToSkip -= 3*4; }
if( BytesToSkip < 0 )
{ BytesToSkip = 0; }
if( BytesToSkip > 0 && BitDepth != 16 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Extra meta data detected in file " << FileName << endl
<< " Data will be skipped." << endl;
}
ebmpBYTE* TempSkipBYTE;
TempSkipBYTE = new ebmpBYTE [BytesToSkip];
SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
delete [] TempSkipBYTE;
}
// This code reads 1, 4, 8, 24, and 32-bpp files
// with a more-efficient buffered technique.
int i,j;
if( BitDepth != 16 )
{
int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
while( 8*BufferSize < Width*BitDepth )
{ BufferSize++; }
while( BufferSize % 4 )
{ BufferSize++; }
ebmpBYTE* Buffer;
Buffer = new ebmpBYTE [BufferSize];
j= Height-1;
while( j > -1 )
{
int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
if( BytesRead < BufferSize )
{
j = -1;
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Could not read proper amount of data." << endl;
}
}
else
{
bool Success = false;
if( BitDepth == 1 )
{ Success = Read1bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 4 )
{ Success = Read4bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 8 )
{ Success = Read8bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 24 )
{ Success = Read24bitRow( Buffer, BufferSize, j ); }
if( BitDepth == 32 )
{ Success = Read32bitRow( Buffer, BufferSize, j ); }
if( !Success )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Could not read enough pixel data!" << endl;
}
j = -1;
}
}
j--;
}
delete [] Buffer;
}
if( BitDepth == 16 )
{
int DataBytes = Width*2;
int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
// set the default mask
ebmpWORD BlueMask = 31; // bits 12-16
ebmpWORD GreenMask = 992; // bits 7-11
ebmpWORD RedMask = 31744; // bits 2-6
// read the bit fields, if necessary, to
// override the default 5-5-5 mask
if( bmih.biCompression != 0 )
{
// read the three bit masks
ebmpWORD TempMaskWORD;
// ebmpWORD ZeroWORD;
SafeFread( (char*) &RedMask , 2 , 1 , fp );
if( IsBigEndian() )
{ RedMask = FlipWORD(RedMask); }
SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
SafeFread( (char*) &GreenMask , 2 , 1 , fp );
if( IsBigEndian() )
{ GreenMask = FlipWORD(GreenMask); }
SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
SafeFread( (char*) &BlueMask , 2 , 1 , fp );
if( IsBigEndian() )
{ BlueMask = FlipWORD(BlueMask); }
SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
}
// read and skip any meta data
if( BytesToSkip > 0 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Extra meta data detected in file "
<< FileName << endl
<< " Data will be skipped." << endl;
}
ebmpBYTE* TempSkipBYTE;
TempSkipBYTE = new ebmpBYTE [BytesToSkip];
SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
delete [] TempSkipBYTE;
}
// determine the red, green and blue shifts
int GreenShift = 0;
ebmpWORD TempShiftWORD = GreenMask;
while( TempShiftWORD > 31 )
{ TempShiftWORD = TempShiftWORD>>1; GreenShift++; }
int BlueShift = 0;
TempShiftWORD = BlueMask;
while( TempShiftWORD > 31 )
{ TempShiftWORD = TempShiftWORD>>1; BlueShift++; }
int RedShift = 0;
TempShiftWORD = RedMask;
while( TempShiftWORD > 31 )
{ TempShiftWORD = TempShiftWORD>>1; RedShift++; }
// read the actual pixels
for( j=Height-1 ; j >= 0 ; j-- )
{
i=0;
int ReadNumber = 0;
while( ReadNumber < DataBytes )
{
ebmpWORD TempWORD;
SafeFread( (char*) &TempWORD , 2 , 1 , fp );
if( IsBigEndian() )
{ TempWORD = FlipWORD(TempWORD); }
ReadNumber += 2;
ebmpWORD Red = RedMask & TempWORD;
ebmpWORD Green = GreenMask & TempWORD;
ebmpWORD Blue = BlueMask & TempWORD;
ebmpBYTE BlueBYTE = (ebmpBYTE) (8*(Blue>>BlueShift));
ebmpBYTE GreenBYTE = (ebmpBYTE) (8*(Green>>GreenShift));
ebmpBYTE RedBYTE = (ebmpBYTE) (8*(Red>>RedShift));
(Pixels[i][j]).Red = RedBYTE;
(Pixels[i][j]).Green = GreenBYTE;
(Pixels[i][j]).Blue = BlueBYTE;
i++;
}
ReadNumber = 0;
while( ReadNumber < PaddingBytes )
{
ebmpBYTE TempBYTE;
SafeFread( (char*) &TempBYTE , 1, 1, fp);
ReadNumber++;
}
}
}
fclose(fp);
return true;
}
bool BMP::CreateStandardColorTable( void )
{
using namespace std;
if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
<< " depth that does not require a color table." << endl
<< " Ignoring request." << endl;
}
return false;
}
if( BitDepth == 1 )
{
int i;
for( i=0 ; i < 2 ; i++ )
{
Colors[i].Red = ebmpBYTE(i * 255);
Colors[i].Green = ebmpBYTE(i * 255);
Colors[i].Blue = ebmpBYTE(i * 255);
Colors[i].Alpha = 0;
}
return true;
}
if( BitDepth == 4 )
{
int i = 0;
int j,k,ell;
// simplify the code for the first 8 colors
for( ell=0 ; ell < 2 ; ell++ )
{
for( k=0 ; k < 2 ; k++ )
{
for( j=0 ; j < 2 ; j++ )
{
Colors[i].Red = ebmpBYTE(j * 128);
Colors[i].Green = ebmpBYTE(k * 128);
Colors[i].Blue = ebmpBYTE(ell * 128);
i++;
}
}
}
// simplify the code for the last 8 colors
for( ell=0 ; ell < 2 ; ell++ )
{
for( k=0 ; k < 2 ; k++ )
{
for( j=0 ; j < 2 ; j++ )
{
Colors[i].Red = ebmpBYTE(j * 255);
Colors[i].Green = ebmpBYTE(k * 255);
Colors[i].Blue = ebmpBYTE(ell * 255);
i++;
}
}
}
// overwrite the duplicate color
i=8;
Colors[i].Red = 192;
Colors[i].Green = 192;
Colors[i].Blue = 192;
for( i=0 ; i < 16 ; i++ )
{ Colors[i].Alpha = 0; }
return true;
}
if( BitDepth == 8 )
{
int i=0;
int j,k,ell;
// do an easy loop, which works for all but colors
// 0 to 9 and 246 to 255
for( ell=0 ; ell < 4 ; ell++ )
{
for( k=0 ; k < 8 ; k++ )
{
for( j=0; j < 8 ; j++ )
{
Colors[i].Red = ebmpBYTE(j * 32);
Colors[i].Green = ebmpBYTE(k * 32);
Colors[i].Blue = ebmpBYTE(ell * 64);
Colors[i].Alpha = ebmpBYTE(0);
i++;
}
}
}
// now redo the first 8 colors
i=0;
for( ell=0 ; ell < 2 ; ell++ )
{
for( k=0 ; k < 2 ; k++ )
{
for( j=0; j < 2 ; j++ )
{
Colors[i].Red = ebmpBYTE(j * 128);
Colors[i].Green = ebmpBYTE(k * 128);
Colors[i].Blue = ebmpBYTE(ell * 128);
i++;
}
}
}
// overwrite colors 7, 8, 9
i=7;
Colors[i].Red = 192;
Colors[i].Green = 192;
Colors[i].Blue = 192;
i++; // 8
Colors[i].Red = 192;
Colors[i].Green = 220;
Colors[i].Blue = 192;
i++; // 9
Colors[i].Red = 166;
Colors[i].Green = 202;
Colors[i].Blue = 240;
// overwrite colors 246 to 255
i=246;
Colors[i].Red = 255;
Colors[i].Green = 251;
Colors[i].Blue = 240;
i++; // 247
Colors[i].Red = 160;
Colors[i].Green = 160;
Colors[i].Blue = 164;
i++; // 248
Colors[i].Red = 128;
Colors[i].Green = 128;
Colors[i].Blue = 128;
i++; // 249
Colors[i].Red = 255;
Colors[i].Green = 0;
Colors[i].Blue = 0;
i++; // 250
Colors[i].Red = 0;
Colors[i].Green = 255;
Colors[i].Blue = 0;
i++; // 251
Colors[i].Red = 255;
Colors[i].Green = 255;
Colors[i].Blue = 0;
i++; // 252
Colors[i].Red = 0;
Colors[i].Green = 0;
Colors[i].Blue = 255;
i++; // 253
Colors[i].Red = 255;
Colors[i].Green = 0;
Colors[i].Blue = 255;
i++; // 254
Colors[i].Red = 0;
Colors[i].Green = 255;
Colors[i].Blue = 255;
i++; // 255
Colors[i].Red = 255;
Colors[i].Green = 255;
Colors[i].Blue = 255;
return true;
}
return true;
}
bool SafeFread( char* buffer, int size, int number, FILE* fp )
{
using namespace std;
int ItemsRead;
if( feof(fp) )
{ return false; }
ItemsRead = (int) fread( buffer , size , number , fp );
if( ItemsRead < number )
{ return false; }
return true;
}
void BMP::SetDPI( int HorizontalDPI, int VerticalDPI )
{
XPelsPerMeter = (int) ( HorizontalDPI * 39.37007874015748 );
YPelsPerMeter = (int) ( VerticalDPI * 39.37007874015748 );
}
// int BMP::TellVerticalDPI( void ) const
int BMP::TellVerticalDPI( void )
{
if( !YPelsPerMeter )
{ YPelsPerMeter = DefaultYPelsPerMeter; }
return (int) ( YPelsPerMeter / (double) 39.37007874015748 );
}
// int BMP::TellHorizontalDPI( void ) const
int BMP::TellHorizontalDPI( void )
{
if( !XPelsPerMeter )
{ XPelsPerMeter = DefaultXPelsPerMeter; }
return (int) ( XPelsPerMeter / (double) 39.37007874015748 );
}
/* These functions are defined in EasyBMP_VariousBMPutilities.h */
BMFH GetBMFH( const char* szFileNameIn )
{
using namespace std;
BMFH bmfh;
FILE* fp;
fp = fopen( szFileNameIn,"rb");
if( !fp )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Cannot initialize from file "
<< szFileNameIn << "." << endl
<< " File cannot be opened or does not exist."
<< endl;
}
bmfh.bfType = 0;
return bmfh;
}
SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
fclose( fp );
if( IsBigEndian() )
{ bmfh.SwitchEndianess(); }
return bmfh;
}
BMIH GetBMIH( const char* szFileNameIn )
{
using namespace std;
BMFH bmfh;
BMIH bmih;
FILE* fp;
fp = fopen( szFileNameIn,"rb");
if( !fp )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Cannot initialize from file "
<< szFileNameIn << "." << endl
<< " File cannot be opened or does not exist."
<< endl;
}
return bmih;
}
// read the bmfh, i.e., first 14 bytes (just to get it out of the way);
ebmpBYTE TempBYTE;
int i;
for( i = 14 ; i > 0 ; i-- )
{ SafeFread( (char*) &TempBYTE , sizeof(ebmpBYTE) , 1, fp ); }
// read the bmih
SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp );
SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp );
fclose( fp );
if( IsBigEndian() )
{ bmih.SwitchEndianess(); }
return bmih;
}
void DisplayBitmapInfo( const char* szFileNameIn )
{
using namespace std;
FILE* fp;
fp = fopen( szFileNameIn,"rb");
if( !fp )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: Cannot initialize from file "
<< szFileNameIn << "." << endl
<< " File cannot be opened or does not exist."
<< endl;
}
return;
}
fclose( fp );
// don't duplicate work! Just use the functions from above!
BMFH bmfh = GetBMFH(szFileNameIn);
BMIH bmih = GetBMIH(szFileNameIn);
cout << "File information for file " << szFileNameIn
<< ":" << endl << endl;
cout << "BITMAPFILEHEADER:" << endl
<< "bfType: " << bmfh.bfType << endl
<< "bfSize: " << bmfh.bfSize << endl
<< "bfReserved1: " << bmfh.bfReserved1 << endl
<< "bfReserved2: " << bmfh.bfReserved2 << endl
<< "bfOffBits: " << bmfh.bfOffBits << endl << endl;
cout << "BITMAPINFOHEADER:" << endl
<< "biSize: " << bmih.biSize << endl
<< "biWidth: " << bmih.biWidth << endl
<< "biHeight: " << bmih.biHeight << endl
<< "biPlanes: " << bmih.biPlanes << endl
<< "biBitCount: " << bmih.biBitCount << endl
<< "biCompression: " << bmih.biCompression << endl
<< "biSizeImage: " << bmih.biSizeImage << endl
<< "biXPelsPerMeter: " << bmih.biXPelsPerMeter << endl
<< "biYPelsPerMeter: " << bmih.biYPelsPerMeter << endl
<< "biClrUsed: " << bmih.biClrUsed << endl
<< "biClrImportant: " << bmih.biClrImportant << endl << endl;
return;
}
int GetBitmapColorDepth( const char* szFileNameIn )
{
BMIH bmih = GetBMIH( szFileNameIn );
return (int) bmih.biBitCount;
}
void PixelToPixelCopy( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY)
{
*To(ToX,ToY) = *From(FromX,FromY);
return;
}
void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY,
RGBApixel& Transparent )
{
if( From(FromX,FromY)->Red != Transparent.Red ||
From(FromX,FromY)->Green != Transparent.Green ||
From(FromX,FromY)->Blue != Transparent.Blue )
{ *To(ToX,ToY) = *From(FromX,FromY); }
return;
}
void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY )
{
// make sure the conventions are followed
if( FromB < FromT )
{ int Temp = FromT; FromT = FromB; FromB = Temp; }
// make sure that the copied regions exist in both bitmaps
if( FromR >= From.TellWidth() )
{ FromR = From.TellWidth()-1; }
if( FromL < 0 ){ FromL = 0; }
if( FromB >= From.TellHeight() )
{ FromB = From.TellHeight()-1; }
if( FromT < 0 ){ FromT = 0; }
if( ToX+(FromR-FromL) >= To.TellWidth() )
{ FromR = To.TellWidth()-1+FromL-ToX; }
if( ToY+(FromB-FromT) >= To.TellHeight() )
{ FromB = To.TellHeight()-1+FromT-ToY; }
int i,j;
for( j=FromT ; j <= FromB ; j++ )
{
for( i=FromL ; i <= FromR ; i++ )
{
PixelToPixelCopy( From, i,j,
To, ToX+(i-FromL), ToY+(j-FromT) );
}
}
return;
}
void RangedPixelToPixelCopyTransparent(
BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY ,
RGBApixel& Transparent )
{
// make sure the conventions are followed
if( FromB < FromT )
{ int Temp = FromT; FromT = FromB; FromB = Temp; }
// make sure that the copied regions exist in both bitmaps
if( FromR >= From.TellWidth() )
{ FromR = From.TellWidth()-1; }
if( FromL < 0 ){ FromL = 0; }
if( FromB >= From.TellHeight() )
{ FromB = From.TellHeight()-1; }
if( FromT < 0 ){ FromT = 0; }
if( ToX+(FromR-FromL) >= To.TellWidth() )
{ FromR = To.TellWidth()-1+FromL-ToX; }
if( ToY+(FromB-FromT) >= To.TellHeight() )
{ FromB = To.TellHeight()-1+FromT-ToY; }
int i,j;
for( j=FromT ; j <= FromB ; j++ )
{
for( i=FromL ; i <= FromR ; i++ )
{
PixelToPixelCopyTransparent( From, i,j,
To, ToX+(i-FromL), ToY+(j-FromT) ,
Transparent);
}
}
return;
}
bool CreateGrayscaleColorTable( BMP& InputImage )
{
using namespace std;
int BitDepth = InputImage.TellBitDepth();
if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
<< " depth that does not require a color table." << endl
<< " Ignoring request." << endl;
}
return false;
}
int i;
int NumberOfColors = InputImage.TellNumberOfColors();
ebmpBYTE StepSize;
if( BitDepth != 1 )
{
StepSize = ebmpBYTE(255 / (NumberOfColors - 1));
}
else
{ StepSize = 255; }
for( i=0 ; i < NumberOfColors ; i++ )
{
ebmpBYTE TempBYTE = ebmpBYTE(i*StepSize);
RGBApixel TempColor;
TempColor.Red = TempBYTE;
TempColor.Green = TempBYTE;
TempColor.Blue = TempBYTE;
TempColor.Alpha = 0;
InputImage.SetColor( i , TempColor );
}
return true;
}
bool BMP::Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width*4 > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{ memcpy( (char*) &(Pixels[i][Row]), (char*) Buffer+4*i, 4 ); }
return true;
}
bool BMP::Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width*3 > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{ memcpy( (char*) &(Pixels[i][Row]), Buffer+3*i, 3 ); }
return true;
}
bool BMP::Read8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{
int Index = Buffer[i];
*( this->operator()(i,Row) )= GetColor(Index);
}
return true;
}
bool BMP::Read4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int Shifts[2] = {4 ,0 };
int Masks[2] = {240,15};
int i=0;
int j;
int k=0;
if( Width > 2*BufferSize )
{ return false; }
while( i < Width )
{
j=0;
while( j < 2 && i < Width )
{
int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
*( this->operator()(i,Row) )= GetColor(Index);
i++; j++;
}
k++;
}
return true;
}
bool BMP::Read1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int Shifts[8] = {7 ,6 ,5 ,4 ,3,2,1,0};
int Masks[8] = {128,64,32,16,8,4,2,1};
int i=0;
int j;
int k=0;
if( Width > 8*BufferSize )
{ return false; }
while( i < Width )
{
j=0;
while( j < 8 && i < Width )
{
int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
*( this->operator()(i,Row) )= GetColor(Index);
i++; j++;
}
k++;
}
return true;
}
bool BMP::Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width*4 > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{ memcpy( (char*) Buffer+4*i, (char*) &(Pixels[i][Row]), 4 ); }
return true;
}
bool BMP::Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width*3 > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{ memcpy( (char*) Buffer+3*i, (char*) &(Pixels[i][Row]), 3 ); }
return true;
}
bool BMP::Write8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int i;
if( Width > BufferSize )
{ return false; }
for( i=0 ; i < Width ; i++ )
{ Buffer[i] = FindClosestColor( Pixels[i][Row] ); }
return true;
}
bool BMP::Write4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int PositionWeights[2] = {16,1};
int i=0;
int j;
int k=0;
if( Width > 2*BufferSize )
{ return false; }
while( i < Width )
{
j=0;
int Index = 0;
while( j < 2 && i < Width )
{
Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) );
i++; j++;
}
Buffer[k] = (ebmpBYTE) Index;
k++;
}
return true;
}
bool BMP::Write1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
{
int PositionWeights[8] = {128,64,32,16,8,4,2,1};
int i=0;
int j;
int k=0;
if( Width > 8*BufferSize )
{ return false; }
while( i < Width )
{
j=0;
int Index = 0;
while( j < 8 && i < Width )
{
Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) );
i++; j++;
}
Buffer[k] = (ebmpBYTE) Index;
k++;
}
return true;
}
ebmpBYTE BMP::FindClosestColor( RGBApixel& input )
{
using namespace std;
int i=0;
int NumberOfColors = TellNumberOfColors();
ebmpBYTE BestI = 0;
int BestMatch = 999999;
while( i < NumberOfColors )
{
RGBApixel Attempt = GetColor( i );
int TempMatch = IntSquare( (int) Attempt.Red - (int) input.Red )
+ IntSquare( (int) Attempt.Green - (int) input.Green )
+ IntSquare( (int) Attempt.Blue - (int) input.Blue );
if( TempMatch < BestMatch )
{ BestI = (ebmpBYTE) i; BestMatch = TempMatch; }
if( BestMatch < 1 )
{ i = NumberOfColors; }
i++;
}
return BestI;
}
bool EasyBMPcheckDataSize( void )
{
__pragma(warning(push))
__pragma(warning(disable:4127))
using namespace std;
bool ReturnValue = true;
if (sizeof(ebmpBYTE) != 1)
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: ebmpBYTE has the wrong size ("
<< sizeof( ebmpBYTE ) << " bytes)," << endl
<< " Compared to the expected 1 byte value" << endl;
}
ReturnValue = false;
}
if( sizeof( ebmpWORD ) != 2 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: ebmpWORD has the wrong size ("
<< sizeof( ebmpWORD ) << " bytes)," << endl
<< " Compared to the expected 2 byte value" << endl;
}
ReturnValue = false;
}
if( sizeof( ebmpDWORD ) != 4 )
{
if( EasyBMPwarnings )
{
cout << "EasyBMP Error: ebmpDWORD has the wrong size ("
<< sizeof( ebmpDWORD ) << " bytes)," << endl
<< " Compared to the expected 4 byte value" << endl;
}
ReturnValue = false;
}
return ReturnValue;
__pragma(warning(pop))
}
bool Rescale( BMP& InputImage , char mode, int NewDimension )
{
using namespace std;
int CapMode = toupper( mode );
BMP OldImage( InputImage );
if( CapMode != 'P' &&
CapMode != 'W' &&
CapMode != 'H' &&
CapMode != 'F' )
{
if( EasyBMPwarnings )
{
char ErrorMessage [1024];
sprintf( ErrorMessage, "EasyBMP Error: Unknown rescale mode %c requested\n" , mode );
cout << ErrorMessage;
}
return false;
}
int NewWidth =0;
int NewHeight =0;
int OldWidth = OldImage.TellWidth();
int OldHeight= OldImage.TellHeight();
if( CapMode == 'P' )
{
NewWidth = (int) floor( OldWidth * NewDimension / 100.0 );
NewHeight = (int) floor( OldHeight * NewDimension / 100.0 );
}
if( CapMode == 'F' )
{
if( OldWidth > OldHeight )
{ CapMode = 'W'; }
else
{ CapMode = 'H'; }
}
if( CapMode == 'W' )
{
double percent = (double) NewDimension / (double) OldWidth;
NewWidth = NewDimension;
NewHeight = (int) floor( OldHeight * percent );
}
if( CapMode == 'H' )
{
double percent = (double) NewDimension / (double) OldHeight;
NewHeight = NewDimension;
NewWidth = (int) floor( OldWidth * percent );
}
if( NewWidth < 1 )
{ NewWidth = 1; }
if( NewHeight < 1 )
{ NewHeight = 1; }
InputImage.SetSize( NewWidth, NewHeight );
InputImage.SetBitDepth( 24 );
int I,J;
double ThetaI,ThetaJ;
for( int j=0; j < NewHeight-1 ; j++ )
{
ThetaJ = (double)(j*(OldHeight-1.0))
/(double)(NewHeight-1.0);
J = (int) floor( ThetaJ );
ThetaJ -= J;
for( int i=0; i < NewWidth-1 ; i++ )
{
ThetaI = (double)(i*(OldWidth-1.0))
/(double)(NewWidth-1.0);
I = (int) floor( ThetaI );
ThetaI -= I;
InputImage(i,j)->Red = (ebmpBYTE)
( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*(OldImage(I,J)->Red)
+(ThetaI-ThetaI*ThetaJ)*(OldImage(I+1,J)->Red)
+(ThetaJ-ThetaI*ThetaJ)*(OldImage(I,J+1)->Red)
+(ThetaI*ThetaJ)*(OldImage(I+1,J+1)->Red) );
InputImage(i,j)->Green = (ebmpBYTE)
( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Green
+(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Green
+(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Green
+(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Green );
InputImage(i,j)->Blue = (ebmpBYTE)
( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Blue
+(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Blue
+(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Blue
+(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Blue );
}
InputImage(NewWidth-1,j)->Red = (ebmpBYTE)
( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Red)
+ ThetaJ*(OldImage(OldWidth-1,J+1)->Red) );
InputImage(NewWidth-1,j)->Green = (ebmpBYTE)
( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Green)
+ ThetaJ*(OldImage(OldWidth-1,J+1)->Green) );
InputImage(NewWidth-1,j)->Blue = (ebmpBYTE)
( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Blue)
+ ThetaJ*(OldImage(OldWidth-1,J+1)->Blue) );
}
for( int i=0 ; i < NewWidth-1 ; i++ )
{
ThetaI = (double)(i*(OldWidth-1.0))
/(double)(NewWidth-1.0);
I = (int) floor( ThetaI );
ThetaI -= I;
InputImage(i,NewHeight-1)->Red = (ebmpBYTE)
( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Red)
+ ThetaI*(OldImage(I,OldHeight-1)->Red) );
InputImage(i,NewHeight-1)->Green = (ebmpBYTE)
( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Green)
+ ThetaI*(OldImage(I,OldHeight-1)->Green) );
InputImage(i,NewHeight-1)->Blue = (ebmpBYTE)
( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Blue)
+ ThetaI*(OldImage(I,OldHeight-1)->Blue) );
}
*InputImage(NewWidth-1,NewHeight-1) = *OldImage(OldWidth-1,OldHeight-1);
return true;
}