Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Bitmap Handler in C++ (BASICS Series)

0.00/5 (No votes)
2 Feb 2006 2  
BitmapHandler is a component written in C++ which goes into the basics of reading & creating Bitmaps

General Introduction

With this article, I am starting a series of write ups on the BASICS of programming in Turbo C++. Several professional developers out there might question the need for such articles as Turbo C++ is quite outdated and is no longer used for commercial development. My retort to such questions raised is simply the fact that the BASICS which are learnt about programming & computer systems by working on Turbo C++ are invaluable and every budding developer must have an insight of how things are actually working under the hood of the powerful development IDE out in the market nowadays. Those who are not beginners may also get a previously unknown insight into the operations of some basic operations.

Introduction to the BitmapHandler

Developers who started with Visual Studio .NET or previous versions of Visual Studio might be familiar with the PictureBox component available in the tool box. The BitmapHandler provides a look at what goes on with the Bitmap Handling portion of the PictureBox. In primitive DOS based IDEs, there is no direct method by which the user can load Bitmaps on to the display screen. Several cumbersome lines of code have to be written to open and correctly display the Bitmap. The BitmapHandler uses the readily available BGI graphics library which provides up to 16 colors. The availability of only 16 colors limits the Bitmaps to be only of 16 colors. The BitmapHandler also provides a unique feature to create Bitmaps. The display area of a graphics program can be taken and converted into a Bitmap which is otherwise not possible by using the Print Screen button. The user can also Rotate, Pan and even change selective colors of the Bitmap before loading it.

Inside the BitmapHandler

Well if you are a hard core Visual Studio developer like me and have been so far not interested in this article, I would urge you to look away as what follows is a lot of code written in pure C++. BitmapHandler is one big class and I will explain it thoroughly.

Understanding the BitmapHandler Variables

Shown below are some private variables found in the class with a line or two of explanation for each of them.

String fileName;

Contains the File Name of the Bitmap that is to be opened and manipulated.

double rotation;

Holds the amount by which the bitmap image is to be rotated on its own axis.

int xShift;int yShift; 

Holds the amount by which the bitmap image is to be panned (translated) from 0,0 when it is to be displayed on the screen.

COLORS monochromeColor 

COLORS mappingColor;

The monochrome color variable replaces wherever the mapping color is found in the image.

Constructor Logic

BitmapHandler::BitmapHandler(String iFileName,double iRotation,int iX,int iY)

BitmapHandler::BitmapHandler(String iFileName,double iRotation)

BitmapHandler::BitmapHandler(String iFileName)

The 3 different constructors are available to construct an object of the BitmapHandler class. One only takes in the filename, the second one takes an angle for rotation as well and the last well also takes information for panning the image. Wherever any information is not passed into the constructor, default values are assumed.

Turbo C++ Equivalent of a Set Property in C#

void BitmapHandler::operator () (double iRotation) 
{ 
rotation = iRotation; 
}  

void BitmapHandler::operator () (String iFileName) 
{
 fileName = iFileName;
 }  

 void BitmapHandler::operator () (Coordinate shiftedCoordinate) 
{
 xShift = shiftedCoordinate[X];
 yShift = shiftedCoordinate[Y]; 
} 

If we take a look at the above code snippet, the operator() has been overloaded and the code snippet shown below can be used to alter the private variables. Although this is also a function call, it somehow replicates the Set property of C#.

/*Create a test object */
BitmapHandler testObject("filename.bmp"); 

/*Change the object source filename by an overloaded operator */
testObject("newFilename.bmp");

A Simple Enumeration

Shown below is the small enumeration used to choose between the 16 color mode or the monochrome mode:

enum ImageMode { MONOCHROME , BMP16 }; 

Inside the Functions

Get Color Mapping

The reason why we need a color mapping is that the color used by DOS or Windows differs from the color codes used inside Turbo C++ for displaying colors.

For example, in Turbo C++, the color BLUE is represented by the number 1 however in DOS or Windows the color BLUE is represented by 4. Hence we require a function that will map the DOS color scheme to the Turbo C++ color scheme.

/*RETURNS A MAPPING FOR A PARTICULAR COLOR FROM BITMAP TO DOS */
int BitmapHandler::getColorMapping(int colorNumber)
{

switch(colorNumber)
{
case 0: return 0;
case 1: return 4;
case 2: return 2;
case 3: return 6;
case 4: return 1;
case 5: return 5;
case 6: return 3;
case 7: return 7;
case 8: return 8;
case 9: return 12;
case 10: return 10;
case 11: return 14;
case 12: return 9;
case 13: return 13;
case 14: return 11;
case 15: return 15;
}

return colorNumber;
} 

Open and Load the Bitmap

Shown below is the function in which the Bitmap is opened and then it is manipulated by applying rotation and translation sequences. The file is opened in binary mode and is firstly tested, i.e. a test is done if the file path actually exists or not.

The next task that this function performs is calculating the height and the width of the image. The format for storing height and width inside a bitmap is not that simple. Firstly the fseek statement is used to traverse to the correct location inside the file. offset x inside a file means the location reached after x scans of one character each. After seeking to the correct offset for the width, 3 characters are scanned. The width is represented in multiples of 16, i.e. width = a*1 + b*256 + c*65536 where a,b,c represent 3 consequently scanned characters. The height is also calculated in a similar fashion at the offset 22.

The next main task is reading and decoding the 4 bit bitmap. Now as the image is a 4 Bit image…thus.. Every character that is scanned will contain the color information of 2 pixels not one. This is achieved by masking the bits. To remove this masking, the bitwise '&' operator is used. The & operation is between the first pixel and 240.

The bitwise operator & performs an AND operation on all the corresponding bits of both the number….

Example 5 & 6 = 4 … 101 & 110 = 100
1 AND 1 = 1
0 AND 1 = 0
1 AND 0 = 0

pixel1=pixel1&(240);

Then we perform a shift right on the pixel1.
This is equivalent of dividing the number by 2 ^ 4

pixel1=pixel1>>4;

and for pixel 2, we simply & it with 15

pixel2=pixel2 & (15);

Boolean BitmapHandler::openAndLoadBitmap(ImageMode imageOption)
{
FILE *pointerToBitmap=NULL;
int widthInPixels=0,heightInPixels=0,mainScannedData,pixel1,pixel2;
unsigned long scannedChar=0,i=0,j=0,modWidthInPixels;
double xTemp,yTemp,rotateX,rotateY,angle;
Coordinate centreOfImage;
pointerToBitmap=fopen(fileName.toCharArray(),"rb");

if(pointerToBitmap==NULL)
return FALSE;

fseek(pointerToBitmap,18,SEEK_SET);

for(i=1;i<=65536;i*=256)
{
scannedChar=fgetc(pointerToBitmap);
widthInPixels+=(scannedChar*i);
}

fseek(pointerToBitmap,22,SEEK_SET);

for(i=1;i<=65536;i*=256)
{
scannedChar=fgetc(pointerToBitmap);
heightInPixels+=(scannedChar*i);
}

modWidthInPixels=widthInPixels;

if(modWidthInPixels%2)
modWidthInPixels++;modWidthInPixels/=2;

if(modWidthInPixels%4)
modWidthInPixels=(modWidthInPixels/4)*4+4;

centreOfImage(widthInPixels/2 + xShift,heightInPixels/2 + yShift);

fseek(pointerToBitmap,119,SEEK_SET);

for(i=0;i<heightInPixels;i++)
for(j=0;j<modWidthInPixels;j++)
{

mainScannedData=fgetc(pointerToBitmap);

pixel1=mainScannedData;pixel2=mainScannedData;
pixel1=pixel1&(240);pixel1=pixel1>>4;
pixel2=pixel2&(15);

xTemp=j*2;yTemp=heightInPixels-1-i;

setviewport(320,0,639,240,0);
rotateX=xTemp-centreOfImage[X],rotateY=centreOfImage[Y]-yTemp,
		angle=rotation*3.142857143/180;
xTemp=rotateX*cos(angle)-rotateY*sin(angle);
yTemp=rotateX*sin(angle)+rotateY*cos(angle);
setviewport(0,0,639,240,0);

xTemp=xTemp+centreOfImage[X];
yTemp=centreOfImage[Y]-yTemp;

if(j*2<widthInPixels)
{
if(imageOption==BMP16)
putpixel(xTemp+xShift,yTemp+yShift,getColorMapping(pixel1));

if(imageOption==MONOCHROME)
{
if(getColorMapping(pixel1)==mappingColor)
putpixel(xTemp+xShift,yTemp+yShift,monochromeColor);
else
putpixel(xTemp+xShift,yTemp+yShift,getColorMapping(pixel1));
}
}

xTemp=j*2+1;yTemp=heightInPixels-1-i;
setviewport(320,0,639,240,0);
rotateX=xTemp-centreOfImage[X],rotateY=centreOfImage[Y]-yTemp;
xTemp=rotateX*cos(angle)-rotateY*sin(angle);
yTemp=rotateX*sin(angle)+rotateY*cos(angle);
setviewport(0,0,639,240,0);
xTemp=xTemp+centreOfImage[X];
yTemp=centreOfImage[Y]-yTemp;

if(j*2+1<widthInPixels)
{
if(imageOption==BMP16)
putpixel(xTemp+xShift,yTemp+yShift,getColorMapping(pixel2));

if(imageOption==MONOCHROME)
{
if(getColorMapping(pixel2)==mappingColor)
putpixel(xTemp+xShift,yTemp+yShift,monochromeColor);
else
putpixel(xTemp+xShift,yTemp+yShift,getColorMapping(pixel2));
}
}
}

fclose(pointerToBitmap);

return TRUE;
}

Conclusion

The BitmapHandler is not a very special or hard to code component. The provided source code is not copyrighted and can be used as a part or whole. The BASICS series is an initiative to instill a feeling of gratitude towards our forefathers whose coding heroics made sure that modern IDEs like Net Beans and Visual Studio make life for developers easy.

There is as such no provision for a property in C++. However by using some operator overloading, I managed to create a similar effect to that of a set property.

History

  • 2nd February, 2006: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here