Homework 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************* | |
* * | |
* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************* | |
* * | |
* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************* | |
* * | |
* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************* | |
* * | |
* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************* | |
* * | |
* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// 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