/* Main program for testing Bitmap class.
* Output currently gives bitmap without data.
* Try editing write method.
*/
#include
#include
#include
#include "bitmap.h"
//using namespace std;
int main()
{
cout << "\"Oh, I hadn't thought of that,\" says God, and promptly vanishes in a puff of logic.\n";
int clrVal;
int shiftr;
int shiftg;
int shiftb;
bitmap TestImg;
TestImg.openBitmap ("after.bmp");
cout << "File loaded.\n";
cout << "File size: " << TestImg.getFSize() << endl;
cout << "Data size: " << TestImg.getDSize() << endl;
cout << "Compression byte pair: " << TestImg.getCompr() << endl;
cout << "Plane quantity: " << TestImg.getPlanes() << endl;
cout << "BPP:" << TestImg.getBPP() << endl;
TestImg.invert();
/*cout << "Input ColorShiftRed" << endl;
cin >> shiftr;
cout << endl;
cout << "Input ColorShiftGreen" << endl;
cin >> shiftg;
cout << endl;
cout << "Input ColorShiftBlue" << endl;
cin >> shiftb;
cout << endl;
TestImg.colorshift(shiftr, shiftg, shiftb);*/
/*cout << "Input new bits per pixel: ";
cin >> clrVal;
if (clrVal == 1) TestImg.binarize();
else {
if (!TestImg.changeClrs (clrVal)) cout << "Failed to change colors.\n";
}
if (TestImg.checkbw(1,1) == true)
{
cout << "Pixel (1,1) is white.\n";
}
else if (TestImg.checkbw(1,1) == false)
{
cout << "Pixel (1,1) is black.\n";
}
if (TestImg.checkbw(1,2) == true)
{
cout << "Pixel (1,2) is white.\n";
}
else if (TestImg.checkbw(1,2) == false)
{
cout << "Pixel (1,2) is black.\n";
}
else
{
cout << "Something unexpected occurred.\n";
}*/
if (!TestImg.saveBitmap ("after2.bmp")) cout << "Failed to save bitmap file.\n";
getch();
return 1;
}
bitmap.cpp
/* Bitmap class implementation.
* Currently under debugging.
* Fix the following:
* -Bit order seems off
* Suggestion: Try reading/writing backwards.
*/
#include
#include
#include
#include
#include "bitmap.h"
using namespace std;
bitmap::bitmap()
{
colors = 0; // set pointer to null
bits = 0; // set pointer to null
}
bitmap::~bitmap()
{
delete[] colors;
delete[] bits;
}
bool bitmap::openBitmap (char const *filename)
{
ifstream input;
input.open (filename, ios::in | ios::binary);
if ( input.is_open() == 0 )
{
cout << "Open of " << filename << " failed." << endl;
return false;
}
else
{
cout << "Open of " << filename << " succeeded." << endl;
}
cout << "Input stream opened.\n";
// Read File Header data
input.read( FileHeader.bmType, 2 );
cout << "FileHeader.bmType read. (Read two bytes.)\n";
cout << FileHeader.bmType << endl;
input.read( (char*)&FileHeader.filesize, 4 );
cout << "FileHeader.filesize read. (Read four bytes.)\n";
input.read( (char*)&FileHeader.reserved1, 2 );
cout << "FileHeader.reserved1 read. (Read two bytes.)\n";
input.read( (char*)&FileHeader.reserved2, 2 );
cout << "FileHeader.reserved2 read. (Read two bytes.)\n";
input.read( (char*)&FileHeader.offset, 4 );
cout << "FileHeader.offset read. (Read four bytes.)\n";
// Read Information Header data
input.read( (char*)&InfoHeader.infoHeadLength, 4 );
cout << "InfoHeader.infoHeadLength read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.width, 4 );
cout << "InfoHeader.width read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.height, 4 );
cout << "InfoHeader.height read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.planes, 2 );
cout << "InfoHeader.planes read. (Read two bytes.)\n";
input.read( (char*)&InfoHeader.bitsPerPixel, 2 );
cout << "InfoHeader.bitsPerPixel read. (Read two bytes.)\n";
input.read( (char*)&InfoHeader.compressionType, 4 );
cout << "InfoHeader.compressionType read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.dataLength, 4 );
cout << "InfoHeader.dataLength read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.deviceXPPM, 4 );
cout << "InfoHeader.deviceXPPM read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.deviceYPPM, 4 );
cout << "InfoHeader.deviceYPPM read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.colorQuant, 4 );
cout << "InfoHeader.colorQuant read. (Read four bytes.)\n";
input.read( (char*)&InfoHeader.importantQuant, 4 );
cout << "InfoHeader.importantQuant read. (Read four bytes.)\n";
colors = new rgbQuad[InfoHeader.dataLength/3];
cout << "colors pointer assigned.\n";
bits = new char[3*InfoHeader.dataLength];
cout << "bits pointer assigned.\n";
streampos here;
for (long i = 0; i < InfoHeader.dataLength/3; i++)
{
//here = input.tellg();
//cout << here;
input.read( (char*)&colors[i].r, 1 );
input.read( (char*)&colors[i].g, 1 );
input.read( (char*)&colors[i].b, 1 );
// input.seekg(-3,ios::cur);
input.seekg( FileHeader.offset+i*3 );
//here = input.tellg();
//cout << " " << here << endl;
input.read( (char*)&bits[3*i], 1);
input.read( (char*)&bits[3*i+1], 1 );
input.read( (char*)&bits[3*i+2], 1 );
}
cout << "Bits and colors assigned.\n";
input.close();
cout << "Input stream closed.\nNow returning.\n";
return true;
}
bool bitmap::saveBitmap (char const *filename)
{
ofstream output;
output.open (filename, ios::out | ios::binary);
if (output.is_open() == 0)
{
cout << "Out stream didn't open correctly.\n";
return false;
}
else
{
cout << "Output stream opened.\n";
}
// write File Header data
output.write( FileHeader.bmType, 2 );
// cout << "FileHeader.bmType written. (Wrote two bytes.)\n";
// cout << FileHeader.bmType << endl;
output.write( (char*)&FileHeader.filesize, 4 );
// cout << "FileHeader.filesize read. (Read four bytes.)\n";
output.write( (char*)&FileHeader.reserved1, 2 );
// cout << "FileHeader.reserved1 read. (Read two bytes.)\n";
output.write( (char*)&FileHeader.reserved2, 2 );
// cout << "FileHeader.reserved2 read. (Read two bytes.)\n";
output.write( (char*)&FileHeader.offset, 4 );
// cout << "FileHeader.offset read. (Read four bytes.)\n";
// Read Information Header data
output.write( (char*)&InfoHeader.infoHeadLength, 4 );
// cout << "InfoHeader.infoHeadLength read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.width, 4 );
// cout << "InfoHeader.width read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.height, 4 );
// cout << "InfoHeader.height read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.planes, 2 );
// cout << "InfoHeader.planes read. (Read two bytes.)\n";
output.write( (char*)&InfoHeader.bitsPerPixel, 2 );
// cout << "InfoHeader.bitsPerPixel read. (Read two bytes.)\n";
output.write( (char*)&InfoHeader.compressionType, 4 );
// cout << "InfoHeader.compressionType read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.dataLength, 4 );
// cout << "InfoHeader.dataLength read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.deviceXPPM, 4 );
// cout << "InfoHeader.deviceXPPM read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.deviceYPPM, 4 );
// cout << "InfoHeader.deviceYPPM read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.colorQuant, 4 );
// cout << "InfoHeader.colorQuant read. (Read four bytes.)\n";
output.write( (char*)&InfoHeader.importantQuant, 4 );
// cout << "InfoHeader.importantQuant read. (Read four bytes.)\n";
for (long i = 0; i < InfoHeader.dataLength/3; i++)
{
output.write( (char*)&colors[i].r, 1 );
output.write( (char*)&colors[i].g, 1 );
output.write( (char*)&colors[i].b, 1 );
}
cout << "Colors written.\n";
output.close();
cout << "Output stream closed.\nNow returning.\n";
return true;
}
long bitmap::go (int xpos, int ypos) //Returns binary array position of the byte holding data relevant to (xpos, ypos)
{
if (!binarized) binarize();
long pos;
pos = (ypos * InfoHeader.width) - xpos;
return pos;
}
bool bitmap::checkbw (int xpos, int ypos)
{
long pos = go (xpos, ypos);
if (colors[pos].r == 0 && colors[pos].g == 0 && colors[pos].b == 0)
{
return true;
}
if (colors[pos].r == 255 && colors[pos].g == 255 && colors[pos].b == 255)
{
return false;
}
else
{
return false;
}
}
long bitmap::getFSize ()
{
return FileHeader.filesize;
}
long bitmap::getDSize ()
{
return InfoHeader.dataLength;
}
long bitmap::getCompr ()
{
return InfoHeader.compressionType;
}
short bitmap::getPlanes ()
{
return InfoHeader.planes;
}
short bitmap::getBPP ()
{
return InfoHeader.bitsPerPixel;
}
bool bitmap::changeClrs (short bitTotal)
{
InfoHeader.bitsPerPixel = bitTotal;
return true;
}
bool bitmap::binarize ()
{
int clrAvg = 0;
long nwhite=0;
long nblack=0;
for (int i=0; i < InfoHeader.dataLength/3; i++)
{
clrAvg = (colors[i].r + colors[i].g + colors[i].b)/3;
if (clrAvg < 128)
{
nblack++;
colors[i].r=0;
colors[i].g=0;
colors[i].b=0;
}
if (clrAvg >= 128)
{
colors[i].r=255;
colors[i].g=255;
colors[i].b=255;
nwhite++;
}
}
cout << "nblack=" << nblack << endl;
cout << "nwhite=" << nwhite << endl;
binarized = true;
return true;
}
bool bitmap::invert()
{
if (!binarized) binarize();
for (int i=0; i < InfoHeader.dataLength/3; i++)
{
if (colors[i].r == 255 && colors[i].g == 255 && colors[i].b == 255)
{
colors[i].r = 0;
colors[i].g = 0;
colors[i].b = 0;
}
else if (colors[i].r == 0 && colors[i].g == 0 && colors[i].b == 0)
{
colors[i].r = 255;
colors[i].g = 255;
colors[i].b = 255;
}
}
return true;
}
bool bitmap::colorshift(int shiftr, int shiftg, int shiftb)
{
for (int i=0; i
if (colors [i].r < 255-shiftr )
{
colors[i].r = colors[i].r+shiftr;
}
else if (colors [i].r > 255-shiftr)
{
colors[i].r = colors[i].r-shiftr;
}
if (colors [i].g < 255-shiftg )
{
colors[i].g = colors[i].g+shiftg;
}
else if (colors [i].g > 255-shiftg)
{
colors[i].g = colors[i].g-shiftg;
}
if (colors [i].b < 255-shiftb )
{
colors[i].b = colors[i].b+shiftb;
}
else if (colors [i].b > 255-shiftb)
{
colors[i].b = colors[i].b-shiftb;
}
}
return true;
}
/*bool bitmap::thin ()
{
//case 1 checking variables
short ur=0; //x+1 y+1
short mr=0; //x+1 y
short lr=0; //x+1 y-1
short lm=0; //x y-1
short ll=0; //x-1 y-1
short ml=0; //x-1 y
short ul=0; //x-1 y+1
short u=0; //x y+1
short ur2=0; //x+2 y+2
short mr2=0; //x+2 y
short lr2=0; //x+2 y-2
short lm2=0; //x y-2
short ll2=0; //x-2 y-2
short ml2=0; //x-2 y
short ul2=0; //x-2 y+2
short u2=0; //x y+2
short layer2 = 0;
short edgeCount[InfoHeader.dataLength];
int y = 1;
bool edgeArray[8];
for (int x 0; x <= InfoHeader.dataLength; x++)
{
if (x > InfoHeader.width)
{
x = 0;
y++;
}
if (x > 1 && y > 1) edgeArray[0] = checkbw (x-1, y-1);
if (y > 1) edgeArray[1] = checkbw (x, y-1);
if (x < InfoHeader.width && y > 1) edgeArray[2] = checkbw (x+1, y-1);
if (x > 1) edgeArray[3] = checkbw (x-1, y);
if (x < InfoHeader.width) edgeArray[4] = checkbw (x+1, y);
if (x < InfoHeader.width && y < InfoHeader.height) edgeArray[5] = checkbw (x+1, y+1);
if (y < InfoHeader.height) edgeArray[6] = checkbw (x, y+1);
if (x > 1 && y < InfoHeader.height) edgeArray[7] = checkbw (x-1, y+1);
for (int i; i < 8; i++)
{
if (edgeArray[i] == true) edgeCount[x]++;
}
if (checkbw (x, y))
{
switch (edgeCount[x])
{
case 0: colors[x].r = 255;
colors[x].g = 255;
colors[x].b = 255;
break;
case 1:
//get first layer of surrounding pixels
if (checkbw(x+1,y+1);) {ur = 1; }
if (checkbw(x+1,y);) {mr = 1;}
if (checkbw(x+1,y-1);) {lr = 1;}
if (checkbw(x,y-1);) {lm = 1;}
if (checkbw(x-1,y-1);) {ll = 1;}
if (checkbw(x-1,y);) {ml = 1;}
if (checkbw(x-1,y+1);) {ul = 1;}
if (checkbw(x,y+1);) {u = 1;}
//get second layer of surrounding pixels
if (checkbw(x+2,y+2);) {ur2 = 1; layer2++;}
if (checkbw(x+2,y);) {mr2 = 1; layer2++;}
if (checkbw(x+2,y-2);) {lr2 = 1; layer2++;}
if (checkbw(x,y-2);) {lm2 = 1; layer2++;}
if (checkbw(x-2,y-2);) {ll2 = 1; layer2++;}
if (checkbw(x-2,y);) {ml2 = 1; layer2++;}
if (checkbw(x-2,y+2);) {ul2 = 1; layer2++;}
if (checkbw(x,y+2);) {u2 = 1; layer2++;}
//leave it alone
if ( layer2 == 0 ) break;
//extend along axis
else if ( layer2 == 1 )
{
if(mr2==1){colors[go(x+1, y)].r = 0; colors[go(x+1, y)].g = 0; colors[go(x+1, y)].b = 0;} //extend right
if(ml2==1){colors[go(x-1, y)].r = 0; colors[go(x-1, y)].g = 0; colors[go(x-1, y)].b = 0;} //extend left
if(u2==1){colors[go(x, y+1)].r = 0; colors[go(x, y+1)].g = 0; colors[go(x, y+1)].b = 0;} //extend up
if(lm2==1){colors[go(x, y-1)].r = 0; colors[go(x, y-1)].g = 0; colors[go(x, y-1)].b = 0;} //extend down
break;
}
else if ( layer2 == 2 )
}
*/
bmFileHead.cpp
// Implementation of Bit Map File Header Class
#include "bmFileHead.h"
bmFileHead::bmFileHead()
{
bmType = new char[2];
filesize = 0;
reserved1 = reserved2 = 0;
offset = 0;
}
bmFileHead::~bmFileHead()
{
delete[] bmType;
}
bmInfoHead.cpp
// Bit map information header implementation
#include "bmInfoHead.h"
bmInfoHead::bmInfoHead()
{
infoHeadLength = 0;
width = 0;
height = 0;
planes = 0;
bitsPerPixel = 0;
compressionType = 0;
dataLength = 0;
deviceXPPM = 0;
deviceYPPM = 0;
colorQuant = 0;
importantQuant = 0;
}
rgbQuad.cpp
// Class implementation for rgbQuad
#include "rgbQuad.h"
rgbQuad::rgbQuad()
{
r = 0;
g = 0;
b = 0;
reserved =0;
}
bitmap.h
/* Class to manage standard bitmaps.
*/
#include
#include
#include "rgbQuad.h"
#include "bmInfoHead.h"
#include "bmFileHead.h"
//using namespace std;
class bitmap {
public:
long getFSize ();
long getDSize ();
long getCompr ();
short getPlanes ();
short getBPP ();
bool binarize ();
bool invert ();
bool colorshift (int shiftr, int shiftg, int shiftb);
bool changeClrs (short bitTotal);
bool checkbw (int xpos, int ypos);
bitmap(); // Constructor
~bitmap(); // Destructor
bool openBitmap (const char *filename);
bool saveBitmap (const char *filename);
private:
bmFileHead FileHeader;
bmInfoHead InfoHeader;
rgbQuad* colors;
char* bits;
long go (int xpos, int ypos);
bool binarized;
};
bmFileHead.h
// Class for Bit Map File Header
class bmFileHead
{
//short bmType; //Equal to "BM"
public:
char* bmType;
unsigned long filesize; // Complete file size in bytes
unsigned short reserved1, reserved2; // Always zero
unsigned long offset; // Number of bytes between the beginning of the file and the data
bmFileHead(); // Constructor
~bmFileHead(); // Destructor
};
bmInfoHead.h
// Bit Map Information Header Class
class bmInfoHead
{
public:
unsigned long infoHeadLength; // Length of the information header in bytes
unsigned long width; // Horizontal width of bitmap in pixels
unsigned long height; // Veritcal height of bitmap in pixels
unsigned short planes; // Number of planes in the bitmap, must be zero
unsigned short bitsPerPixel; // Bits per pixel
unsigned long compressionType; // Compression specifications
unsigned long dataLength; // Length of the data, rounded to nearest 4-byte boundary
unsigned long deviceXPPM; // The targer device's pixels per meter horizontally
unsigned long deviceYPPM; // The targer device's pixels per meter vertically
unsigned long colorQuant; // Number of colors used in the bit map
unsigned long importantQuant; // Number of "important" colors
bmInfoHead(); // Construtor
};
rgbQuad.h
// Class for bit map colors
class rgbQuad
{
public:
unsigned char r; // red
unsigned char g; // green
unsigned char b; // blue
unsigned char reserved; // Reserved space
rgbQuad(); // Constructor
};