Skip to content

Instantly share code, notes, and snippets.

@BradenAndros
Created November 13, 2012 18:40
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save BradenAndros/14e3f57a393c638ac84f to your computer and use it in GitHub Desktop.
Homework 5
/*************************************************
* *
* 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 = 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 = i*255;
Colors[i].Green = i*255;
Colors[i].Blue = 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 = j*128;
Colors[i].Green = k*128;
Colors[i].Blue = 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 = j*255;
Colors[i].Green = k*255;
Colors[i].Blue = 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 = j*32;
Colors[i].Green = k*32;
Colors[i].Blue = ell*64;
Colors[i].Alpha = 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 = j*128;
Colors[i].Green = k*128;
Colors[i].Blue = 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 = 255/(NumberOfColors-1); }
else
{ StepSize = 255; }
for( i=0 ; i < NumberOfColors ; i++ )
{
ebmpBYTE TempBYTE = 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 )
{
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;
}
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;
}
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP.h *
* date added: 01-31-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Main include file *
* *
*************************************************/
#ifdef _MSC_VER
// MS Visual Studio gives warnings when using
// fopen. But fopen_s is not going to work well
// with most compilers, and fopen_s uses different
// syntax than fopen. (i.e., a macro won't work)
// So, we'lll use this:
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <iostream>
#include <cmath>
#include <cctype>
#include <cstring>
#ifndef EasyBMP
#define EasyBMP
#ifdef __BCPLUSPLUS__
// The Borland compiler must use this because something
// is wrong with their cstdio file.
#include <stdio.h>
#else
#include <cstdio>
#endif
#ifdef __GNUC__
// If g++ specific code is ever required, this is
// where it goes.
#endif
#ifdef __INTEL_COMPILER
// If Intel specific code is ever required, this is
// where it goes.
#endif
#ifndef _DefaultXPelsPerMeter_
#define _DefaultXPelsPerMeter_
#define DefaultXPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#ifndef _DefaultYPelsPerMeter_
#define _DefaultYPelsPerMeter_
#define DefaultYPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#include "EasyBMP_DataStructures.h"
#include "EasyBMP_BMP.h"
#include "EasyBMP_VariousBMPutilities.h"
#ifndef _EasyBMP_Version_
#define _EasyBMP_Version_ 1.06
#define _EasyBMP_Version_Integer_ 106
#define _EasyBMP_Version_String_ "1.06"
#endif
#ifndef _EasyBMPwarnings_
#define _EasyBMPwarnings_
#endif
void SetEasyBMPwarningsOff( void );
void SetEasyBMPwarningsOn( void );
bool GetEasyBMPwarningState( void );
#endif
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines BMP class *
* *
*************************************************/
#ifndef _EasyBMP_BMP_h_
#define _EasyBMP_BMP_h_
bool SafeFread( char* buffer, int size, int number, FILE* fp );
bool EasyBMPcheckDataSize( void );
class BMP
{private:
int BitDepth;
int Width;
int Height;
RGBApixel** Pixels;
RGBApixel* Colors;
int XPelsPerMeter;
int YPelsPerMeter;
ebmpBYTE* MetaData1;
int SizeOfMetaData1;
ebmpBYTE* MetaData2;
int SizeOfMetaData2;
bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
ebmpBYTE FindClosestColor( RGBApixel& input );
public:
int TellBitDepth( void );
int TellWidth( void );
int TellHeight( void );
int TellNumberOfColors( void );
void SetDPI( int HorizontalDPI, int VerticalDPI );
int TellVerticalDPI( void );
int TellHorizontalDPI( void );
BMP();
BMP( BMP& Input );
~BMP();
RGBApixel* operator()(int i,int j);
RGBApixel GetPixel( int i, int j ) const;
bool SetPixel( int i, int j, RGBApixel NewPixel );
bool CreateStandardColorTable( void );
bool SetSize( int NewWidth, int NewHeight );
bool SetBitDepth( int NewDepth );
bool WriteToFile( const char* FileName );
bool ReadFromFile( const char* FileName );
RGBApixel GetColor( int ColorNumber );
bool SetColor( int ColorNumber, RGBApixel NewColor );
};
#endif
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_DataStructures.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines basic data structures for *
* the BMP class *
* *
*************************************************/
#ifndef _EasyBMP_Custom_Math_Functions_
#define _EasyBMP_Custom_Math_Functions_
inline double Square( double number )
{ return number*number; }
inline int IntSquare( int number )
{ return number*number; }
#endif
int IntPow( int base, int exponent );
#ifndef _EasyBMP_Defined_WINGDI
#define _EasyBMP_Defined_WINGDI
typedef unsigned char ebmpBYTE;
typedef unsigned short ebmpWORD;
typedef unsigned int ebmpDWORD;
#endif
#ifndef _EasyBMP_DataStructures_h_
#define _EasyBMP_DataStructures_h_
inline bool IsBigEndian()
{
short word = 0x0001;
if((*(char *)& word) != 0x01 )
{ return true; }
return false;
}
inline ebmpWORD FlipWORD( ebmpWORD in )
{ return ( (in >> 8) | (in << 8) ); }
inline ebmpDWORD FlipDWORD( ebmpDWORD in )
{
return ( ((in&0xFF000000)>>24) | ((in&0x000000FF)<<24) |
((in&0x00FF0000)>>8 ) | ((in&0x0000FF00)<<8 ) );
}
// it's easier to use a struct than a class
// because we can read/write all four of the bytes
// at once (as we can count on them being continuous
// in memory
typedef struct RGBApixel {
ebmpBYTE Blue;
ebmpBYTE Green;
ebmpBYTE Red;
ebmpBYTE Alpha;
} RGBApixel;
class BMFH{
public:
ebmpWORD bfType;
ebmpDWORD bfSize;
ebmpWORD bfReserved1;
ebmpWORD bfReserved2;
ebmpDWORD bfOffBits;
BMFH();
void display( void );
void SwitchEndianess( void );
};
class BMIH{
public:
ebmpDWORD biSize;
ebmpDWORD biWidth;
ebmpDWORD biHeight;
ebmpWORD biPlanes;
ebmpWORD biBitCount;
ebmpDWORD biCompression;
ebmpDWORD biSizeImage;
ebmpDWORD biXPelsPerMeter;
ebmpDWORD biYPelsPerMeter;
ebmpDWORD biClrUsed;
ebmpDWORD biClrImportant;
BMIH();
void display( void );
void SwitchEndianess( void );
};
#endif
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Various utilities. *
* *
*************************************************/
#ifndef _EasyBMP_VariousBMPutilities_h_
#define _EasyBMP_VariousBMPutilities_h_
BMFH GetBMFH( const char* szFileNameIn );
BMIH GetBMIH( const char* szFileNameIn );
void DisplayBitmapInfo( const char* szFileNameIn );
int GetBitmapColorDepth( const char* szFileNameIn );
void PixelToPixelCopy( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY);
void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY,
RGBApixel& Transparent );
void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY );
void RangedPixelToPixelCopyTransparent(
BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY ,
RGBApixel& Transparent );
bool CreateGrayscaleColorTable( BMP& InputImage );
bool Rescale( BMP& InputImage , char mode, int NewDimension );
#endif
//-----------------------------------------------------------------------------
// Programmer: Braden Andros
// Name: hw5.cpp
// Description: TODO
//-----------------------------------------------------------------------------
#include "Image.h"
#include <iostream>
#include <stack>
using namespace std;
// define struct to hold pixel location
struct PixelLocation {
int r;
int c;
};
// possible function prototypes that you may consider using (optional):
bool findPixelLocationWithGivenValue(const Image &image, int pixelValue, int &foundRow, int &foundCol);
int markConnectedComponent(Image &image, int seedRow, int seedCol, int ccLabel, int &largeLabel);
int main( int argc, char* argv[] )
{
// get input/output image file names from command line
if (argc != 4)
{
std::cout << "Usage instructions: " << std::endl;
std::cout << "> hw5.exe inputFileName.bmp thresholdedOutputFileName.bmp largeCCOutputFileName.bmp" << std::endl;
return -1;
}
std::string inputFileName(argv[1]);
std::string thresholdedOutputFileName(argv[2]);
std::string largeCCOutputFileName(argv[3]);
// read image from input file
std::cout << "Reading input image: " << inputFileName << std::endl;
Image myImage;
bool success = myImage.readFromBMPFile(inputFileName);
if (! success)
{
std::cout << "Error reading input image." << std::endl;
return -1;
}
const int THRESHOLD = 128;
const int LARGE = 500;
int r = myImage.getNumRows();
int c = myImage.getNumCols();
for (int i=0; i<r; i++)
{
for (int j=0; j<c; j++)
{
if (myImage.getPixel(i,j)>THRESHOLD)
{
myImage.setPixel(i, j, 255);
}
else
{
myImage.setPixel(i, j, 0);
}
}
}
myImage.writeToBMPFile(thresholdedOutputFileName);
int seedRow=0;
int seedCol=0;
int numLargeObjects=0;
int connectedLabel=1;
while (findPixelLocationWithGivenValue(myImage, 255, seedRow, seedCol))
{
int val = 0;
++connectedLabel;
val = markConnectedComponent(myImage, seedRow, seedCol, connectedLabel, numLargeObjects);
if (val>=LARGE)
{
numLargeObjects++;
}
else
{
myImage.setAllPixelsWithOldValToNewVal(connectedLabel,0);
}
std::cout<<val<<endl;
}
std::cout<<endl;
std::cout<<"The number of large objects is: "<<numLargeObjects<<endl;
myImage.switchToRandomColorMapping();
myImage.writeToBMPFile(largeCCOutputFileName);
return 0;
}
bool findPixelLocationWithGivenValue(const Image &image, int pixelValue, int &foundRow, int &foundCol)
{
int r = image.getNumRows();
int c = image.getNumCols();
for (int i = 0; i<r; i++)
{
for (int j = 0; j<c; j++)
{
if (image.getPixel(i,j)==pixelValue)
{
foundRow=i;
foundCol=j;
return true;
}
}
}
return false;
}
int markConnectedComponent(Image &image, int seedRow, int seedCol, int ccLabel, int &largeLabel)
{
stack<PixelLocation> pixelStack;
PixelLocation currPixel = {seedRow, seedCol};
const int seedVal = image.getPixel(seedRow, seedCol);
int numPixels=0;
pixelStack.push(currPixel);
while (!pixelStack.empty())
{
currPixel = pixelStack.top();
PixelLocation neighbors[] = {{currPixel.r+1, currPixel.c},{currPixel.r-1, currPixel.c}, {currPixel.r, currPixel.c+1}, {currPixel.r, currPixel.c-1}};
size_t numNeighbors = sizeof(neighbors) / sizeof(*neighbors);
pixelStack.pop();
if (seedVal==image.getPixel(currPixel.r, currPixel.c))
{
image.setPixel(currPixel.r, currPixel.c, ccLabel);
for (size_t i=0; i < numNeighbors; i++)
{
if (image.isInBounds(neighbors[i].r, neighbors[i].c))
{
pixelStack.push(neighbors[i]);
}
}
numPixels++;
}
}
return numPixels;
}
#include "Image.h"
#include "EasyBMP/EasyBMP.h"
#include <cstdlib>
#include <ctime>
Image::Image()
{
m_numRows = 0;
m_numCols = 0;
m_pixels = NULL;
switchToGrayColorMapping(); // default color mapping is grayscale
}
Image::Image(int numRows, int numCols)
{
m_numRows = numRows;
m_numCols = numCols;
if (m_numRows*m_numCols > 0)
{
m_pixels = new int[m_numRows*m_numCols];
setAllPixels(0);
}
else
{
m_pixels = NULL;
}
switchToGrayColorMapping(); // default color mapping is grayscale
}
Image::Image(const Image &imageToCopyFrom)
{
// copy rows/cols/pixels
m_numRows = imageToCopyFrom.m_numRows;
m_numCols = imageToCopyFrom.m_numCols;
if (m_numRows*m_numCols > 0)
{
m_pixels = new int[m_numRows*m_numCols];
for (int i = 0; i < m_numRows*m_numCols; i++)
{
m_pixels[i] = imageToCopyFrom.m_pixels[i];
}
}
else
{
m_pixels = NULL;
}
// copy color mapping
for (int i=0; i < 256; i++)
{
m_colorMapping[i] = imageToCopyFrom.m_colorMapping[i];
}
}
Image::~Image()
{
if (m_pixels != NULL)
{
delete [] m_pixels;
m_numRows = 0;
m_numCols = 0;
}
}
const Image &Image::operator=(const Image &imageOnRight)
{
// avoid self-assignment
if (&imageOnRight != this)
{
// if images have different sizes, delete old space and allocate new space
if (m_numRows != imageOnRight.m_numRows || m_numCols != imageOnRight.m_numCols)
{
if (m_pixels != NULL)
{
delete [] m_pixels;
m_pixels = NULL;
}
m_numRows = imageOnRight.m_numRows;
m_numCols = imageOnRight.m_numCols;
if (m_numRows*m_numCols > 0)
{
m_pixels = new int[m_numRows*m_numCols];
}
}
// now copy pixels
for (int i = 0; i < m_numRows*m_numCols; i++)
{
m_pixels[i] = imageOnRight.m_pixels[i];
}
// now copy color mapping
for (int i=0; i < 256; i++)
{
m_colorMapping[i] = imageOnRight.m_colorMapping[i];
}
}
return *this; // enables I1 = I2 = I3, for example
}
bool Image::readFromBMPFile(std::string inputFileName)
{
bool success = true;
// use BMP object to read image
BMP inputImage;
success = inputImage.ReadFromFile(inputFileName.c_str());
if (success)
{
// allocate memory for image (deleting old, if exists)
m_numRows = inputImage.TellHeight();
m_numCols = inputImage.TellWidth();
if (m_pixels != NULL) // deallocate old memory
{
delete [] m_pixels;
}
m_pixels = new int[m_numRows*m_numCols];
// copy pixels
for (int r = 0; r < m_numRows; r++)
{
for (int c = 0; c < m_numCols; c++)
{
RGBApixel pixelVal = inputImage.GetPixel(c, r);
int val = (int) pixelVal.Blue + (int) pixelVal.Green + (int) pixelVal.Red;
val = (int)(val/3.0 + 0.5);
// clamp value to be in range 0-255
if (val < 0)
{
val = 0;
}
if (val > 255)
{
val = 255;
}
m_pixels[r*m_numCols + c] = val;
}
}
}
return success;
}
bool Image::writeToBMPFile(std::string outputFileName)
{
bool success = true;
if (m_pixels != NULL)
{
// create bitmap image
BMP outputImage;
outputImage.SetSize(m_numCols, m_numRows);
outputImage.SetBitDepth( 24 );
for (int r = 0; r < m_numRows; r++)
{
for (int c = 0; c < m_numCols; c++)
{
// get pixel value and clamp between 0 and 255
int val = m_pixels[r*m_numCols + c];
if (val < 0)
{
val = 0;
}
if (val > 255)
{
val = 255;
}
// set output color based on mapping
RGBApixel pixelVal = m_colorMapping[val];
outputImage.SetPixel(c, r, pixelVal);
}
}
// write to file
success = outputImage.WriteToFile( outputFileName.c_str() );
}
else
{
success = false;
}
return success;
}
int Image::getPixel(int r, int c) const
{
int val = 0;
if (isInBounds(r,c))
{
val = m_pixels[r*m_numCols + c];
}
return val;
}
bool Image::isInBounds(int r, int c) const
{
return (r >= 0 && r < m_numRows && c >=0 && c < m_numCols);
}
int Image::getNumRows() const
{
return m_numRows;
}
int Image::getNumCols() const
{
return m_numCols;
}
void Image::setPixel(int r, int c, int val)
{
if (isInBounds(r,c))
{
m_pixels[r*m_numCols + c] = val;
}
}
void Image::setAllPixels(int val)
{
for (int i=0; i < m_numRows*m_numCols; i++)
{
m_pixels[i] = val;
}
}
void Image::setAllPixelsWithOldValToNewVal(int oldVal, int newVal)
{
for (int i=0; i < m_numRows*m_numCols; i++)
{
if (m_pixels[i] == oldVal)
{
m_pixels[i] = newVal;
}
}
}
void Image::switchToGrayColorMapping()
{
RGBApixel currPix;
for (int i=0; i < 256; i++)
{
currPix.Blue = i;
currPix.Green = i;
currPix.Red = i;
currPix.Alpha = 255;
m_colorMapping[i] = currPix;
}
}
void Image::switchToRandomColorMapping()
{
// everything is a random color EXCEPT the first color (black)
srand(time(NULL));
RGBApixel currPix;
for (int i=1; i < 256; i++)
{
currPix.Blue = rand() % 256;
currPix.Green = rand() % 256;
currPix.Red = rand() % 256;
currPix.Alpha = 255;
m_colorMapping[i] = currPix;
}
}
//-----------------------------------------------------------------------------
// Programmer: Mona K. Garvin
// Name: Image.h
// Description: Header file for Image class for homework 5. This class
// represents a grayscale image that can be read from a bmp file
// and written to a bmp file in two ways (grayscale mapping and
// randomized color mapping)
//-----------------------------------------------------------------------------
#ifndef IMAGE_H
#define IMAGE_H
#include <string>
#include "EasyBMP/EasyBMP.h"
class Image
{
public:
//--------------------------------------
// GROUP: Construction/destruction/copy
//--------------------------------------
// default constructor
Image();
// constructor to specify size
Image(int numRows, int numCols);
// copy constructor
Image(const Image &imageToCopyFrom);
// destructor
~Image();
// assignment operator
const Image &operator=(const Image &imageOnRight);
//-----------------------------------
// GROUP: Image input (from file)
//-----------------------------------
// create image from file, given filenmame of .bmp file
// the image is converted to grayscale
bool readFromBMPFile(std::string inputFileName);
//-----------------------------------
// GROUP: Image output (to file)
//-----------------------------------
// write image to file, given .bmp filename
// the mapping between intensity values and color
// values will be based on the current color mapping
// (see switchToGrayColorMapping() and switchToRandomColorMapping() functions)
bool writeToBMPFile(std::string outputFileName);
// switch color mapping to grayscale (call before writing to file)
void switchToGrayColorMapping();
// switch color mapping to "random colors" so that
// each intensity value will be assigned a random color
// (call before writing to file)
void switchToRandomColorMapping();
//-----------------------------
// GROUP: Data accessors
//-----------------------------
// get pixel value, given input row and column
int getPixel(int r, int c) const;
// determine whether given pixel location (row/column) is in bounds
bool isInBounds(int r, int c) const;
// get number of rows
int getNumRows() const;
// get number of columns
int getNumCols() const;
//-----------------------------
// GROUP: Data modification
//-----------------------------
// set pixel value at row r and column c to val
void setPixel(int r, int c, int val);
// set all pixel values to val
void setAllPixels(int val);
// set all pixel with the given oldVal to the given newVal
void setAllPixelsWithOldValToNewVal(int oldVal, int newVal);
private:
int m_numRows; // number of rows
int m_numCols; // number of columns
int * m_pixels; // pointer to first pixel in image
RGBApixel m_colorMapping[256]; // color mapping for output
};
#endif // IMAGE_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment