Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Combining Bitmaps and Masking

Combining Bitmaps and Masking

by  J111  Posted    (Edited  )
The code below is as simple as it gets, when you want one bitmap to be partially covered by another one. Maybe you have information that you want covered up after a certain time duration, or you want to place one object in front of another. A little creativity can go a long way to dazzle, and still use very basic Builder canvas concepts.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
Graphics::TBitmap *board = new Graphics::TBitmap;
Graphics::TBitmap *cover = new Graphics::TBitmap;
board->LoadFromFile("base.bmp");
cover->LoadFromFile("partial1.bmp");
board->Canvas->Font->Color = clYellow;
board->Canvas->Font->Size = 15;
board->Canvas->Font->Style = board->Canvas->Font->Style<<fsBold;
board->Canvas->Brush->Style = bsClear;
board->Canvas->TextOut(8,25,"Yes it is!");

Canvas->CopyRect(Rect(0,0,Width,Height),board->Canvas,
Rect(0,0,board->Width,board->Height));

Sleep(1000);
board->Canvas->CopyMode = cmSrcPaint;
board->Canvas->CopyRect(Rect(0,0,board->Width,board->Height),
cover->Canvas,Rect(0,0,cover->Width,cover->Height));
Canvas->CopyRect(Rect(0,0,Width,Height),board->Canvas,
Rect(0,0,board->Width,board->Height));
}

Start a new project in a folder of your choosing, and place a button control on the main form. In using File | Save Project as, I leave the default names for the main form window and project name. I identify the project by the name of the project folder, like "combinebitmaps".Double click the button to expose its event handling function. Create two bitmap objects by typing in by typing in the first two lines of the function as above. These are two Builder style bitmap objects with their properties and functions to handle, the corresponding bitmap data member, a "*.bmp" file which we are about to prepare.
From the menu, select Tools | Image Editor. You are now into a new application, the "Image Editor", which we are going to use to create a bitmap data file -complete with an image [well, kind of ]. From the Image Editor select File | New | Bitmap File. Leave the default settings. Select View | Zoom In, and pull down the bottom of the window to get a complete view of this bitmap object. We're going to change the background color for this bitmap. Right mouse click the green color; left mouse click the Fill icon, the dripping pail; and right mouse click again over your image to change the background color of the bitmap to green. You set the foreground color of a bitmap image by left clicking a color from the color toolbar. You set the background color of your bitmap by right clicking over the color, and then right clicking the image. This is our background picture! Save your file. File | Save As ... Make sure you have the Bitmap type selected. Navigate to your project directory so your project will be able to find the file. Also call the file "base.bmp". Don't forget the ".bmp" extension or you won't have a bitmap file.
Next we have to create the "partial1.bmp". Again, using the Image Editor, close the existing file. Select File | New | Bitmap File. Select View | Zoom In to enlarge the new bitmap, and again pull down the lower window to make the bitmap fully visible. To be clear, only the view is enlarged. The bitmap itself still has the same dimensions. Again, change the background color to the same green color selected for your first bitmap. Right click the color ... At this point the partial1 bitmap should be identical to the base.bmp. Left click the yellow color, left click the Filled Ellipse icon. Near the upper mid center of your bitmap shape, left click and drag down almost to the bottom of your bitmap, to make a narrow, yellow elliptical shape. This shape should be approximately a fifth the width of the bitmap, and pretty well go from top to bottom. It doesn't have to be exact! Again, save to your directory with the name "partial1.bmp". Close the Image Editor.
Add lines 3 and 4 to load these bitmap files into their corresponding Builder bitmap objects, for manipulation.
Board and cover store their data images in memory. These data images are not visible! They each have a Canvas member - a virtual non visual surface to represent the placement of the image. The next five lines, none of which is essential for the program to function, represent properties and functions of the board Canvas object, to set and place the text message. These properties, with the exception of the TextOut statement, have default settings. We changed the font's color to yellow and its size to 15. Block out the font style line and see what effect it has on the display. You can check out the other available font properties by viewing the drop down list which displays after you complete typing the arrow. You can also get further information by placing the cursor over the property and pressing F1. Another important property is Brush, which sets the default background color for the Canvas. Canvas and Brush are members of several components, including the Form and the Canvas. Notice the TextOut member of Canvas, pastes text on the board->Canvas member, at the 8, 25, x y location on the Canvas. This memory canvas image is just not visible until it is actually transferred to the Canvas that is a member of the window form. The Canvas->CopyRect( .....); line does this. Here Canvas is understood to be a member of the main object window Form1. You could also type in Form1->Canvas->CopyRect( .[complete]....); The suggestion "CopyRect" is really not about rectangles. It is about copying a bitmap image from one Canvas, in this case, the bitmap image included in the board bitmap object, to the owner of the CopyRect function, the main form Canvas, the visible Canvas, the Form1 canvas. The bitmap is now visible! Notice how the "Rect" structure is used. This object lays out rectangles. Here the Rect constructor is used to lay out a rectangle. The first Rect structure designates the size of the targeted Canvas. Because we want the drawing to fill all the Form Canvas, we designate 0,0 as the upper left hand corner of the Canvas, and we designate Width, [or Form1->Width] as the width of the rectangle and Height or [ ... ]as the height of the form Canvas. Similarly, the second Rect specifies the rectangular area of the board->Canvas to be copied from, in this case all of it. If you didn't type any more and ran the program, you would see the very plain "base.bmp" with "Yes it is!"text, after you clean up your typos.
The Sleep(1000) is a windows function, not a Builder function. It pauses execution of the program, and allows the texted base.bmp to show itself for one second. Because we want to combine two bitmaps, we use the board->Canvas->CopyMode statement to specify how one bitmap is to be combined with another. Place your cursor over CopyMode and press F1 to find a list of the different copy modes that can be used. Here we are using CopyRect from the board's Canvas member to actually copy over the board's canvas with the cover's canvas - the image in the cover's canvas is combined with the image that is already in the board's canvas. The board's canvas data is now a combination of both images. Again, notice the destination Rect, the first one and the source Rect, the last parameter of the function, and how each rectangle is sized according to the size of the corresponding canvas. You could also designate different areas. Finally, this image is made visible by copying the revised board canvas into the main form canvas. Build and Run after copying the code into Button1Click, as above.

Oh, you want more than having the bitmap backgrounds the same color, and the fonts and the blocking image the same color - as impressive as this is? Close the above project, and create a new project in its own folder. To be universal, find the "factory.bmp" in one of the Borland folders. Press Start menu Start | Find | Files or Folders. Enter "factory.bmp" in the named Edit box. You may also want to press the Browse button to navigate to the Program Files folder area. Right click the factory.bmp and select Copy from the context menu. Open the windows explorer and navigate to the folder where your placed your new project. Press Edit | Paste. Still in Explorer right click this newly place file and select Rename. Rename "factory.bmp" to "sceneobj.bmp". Again, don't forget the ".bmp" extension! You could also use your own image - a digital photograph - as long as it is a file saved as type *.bmp.

First of all we are going to display on the form window how an irregular shaped object is displayed on a background scene bitmap, with the object's background replaced by the scene bitmap. Go to Tools | Image Editor to create the object image that will look placed naturally in this sceneobj.bmp factory scene. In the Image Editor go to File | New | Bitmap Object. Go to Bitmap | Properties and change both the Width and Height to 15. Leave the color at its default VGA(16 colors). Go to View | Zoom In several times to enlarge the view of the bitmap. Left click the yellow color and left click the shaded circle to select the filled circle drawing tool. Left click near the upper left corner and drag down diagonally down and right to largely fill the bitmap. Edit | Undo Filled Ellipse until it looks the way you want it. Right click the black color, left click the Fill Icon, and right click anywhere on the white bitmap background. The background has to be black
Go to File | Save As, navigate to your current directory, and call the file name ballobj.bmp. Make sure the file type Bitmaps, is selected. After saving, we are going to create another bitmap for this object, called a bitmap mask. You can either close the ball bitmap and create a new one, or change the ball bitmap, and save to a different name. This creates another bitmap. Since the ball and the mask objects have to correspond exactly position and size wise, let's change and save again. Right click the black color, left click the Fill Icon, and right click on the background to change the background color of the ball bitmap from black to white. Left click the black color, left click the Fill Icon, and left click on the ball to change the color of the ball from yellow to black. The color of the ball mask is now black and its background is white. Go to File | Save As, and navigate to your project directory. Make sure you change the file name to ballmaskobj.bmp .

Right click on your Unit1.cpp file, and select Open Source | Header File. Add the following supporting variables to the header file of your main window class. Below Private: enter

Graphics::TBitmap* ball,*ballmask,*scene,*ballarea;
int x,y;
TRect ballrect;

Here you are declaring 4 Builder bitmap instances, which will be used to manipulate the actual bitmaps. X and y are used to locate the ball object on the scene. The rectangle object is used to mark on the scene the area of the ball object. The above objects could also have been declared in the Button1Click event handler, but then they would not have existed outside of pressing Button1. We want these variables to exist and be accessible from anywhere in the form.

Toggle to the main form. If the Object Inspector is not visible, press View | Object Inspector. Click on the main form, select the Events page, and double click on the column beside the OnCreate event. The FormCreate event handler function should now be visible. Enter the following code inside this function:

ball = new Graphics::TBitmap;
ballmask = new Graphics::TBitmap;
scene = new Graphics::TBitmap;
ballarea = new Graphics::TBitmap;
ball->LoadFromFile("ballobj.bmp");
ballmask->LoadFromFile("ballmaskobj.bmp");
scene->LoadFromFile("sceneobj.bmp");

ballarea->Width = ball->Width;
ballarea->Height = ball->Height;
ballrect = Rect(0,0,ball->Width,ball->Height);

Notice that ball, ballmask, and scene are loaded with their corresponding data file objects. Ballarea is another bitmap created to store that portion of the scene bitmap that will be destroyed when the ball object is pasted. If the ball is ever going to be moved, the scenery will have to be replaced! Notice the ballarea width and height is set to match the actual ball width and height. Similarly, the ballrect is a rectangular structure whose dimensions are set to match the size of the ball bitmap. CopyRect ............

Double click Button1. Enter the following code in the Button1Click message handler:

x=50;
y = 20;
TRect locationrect = Rect(x,y,x+ball->Width,y+ball->Width);
ballarea->Canvas->CopyRect(ballrect,scene->Canvas,locationrect);
scene->Canvas->CopyMode = cmSrcAnd;
scene->Canvas->CopyRect(locationrect,ballmask->Canvas,ballrect);
Canvas->CopyRect(Rect(0,0,Width,Height),scene->Canvas,
Rect(0,0,scene->Width,scene->Height));
Sleep(1000);

scene->Canvas->CopyMode = cmSrcPaint;
scene->Canvas->CopyRect(locationrect,ball->Canvas,ballrect);

Canvas->CopyRect(Rect(0,0,Width,Height),scene->Canvas,
Rect(0,0,scene->Width,scene->Height));
Sleep(1000);

Canvas->CopyRect(Rect(0,0,Width,Height),scene->Canvas,
Rect(0,0,scene->Width,scene->Height));

scene->Canvas->CopyMode = cmSrcCopy;
scene->Canvas->CopyRect(locationrect,ballarea->Canvas,ballrect);

Canvas->CopyRect(Rect(0,0,Width,Height),scene->Canvas,
Rect(0,0,scene->Width,scene->Height));

The x and y location variables are assigned to place the ball. A local rectangle structure, locationrect is also created and filled to mark out the boundary where the ball is currently located. Because this area of the scene will be destroyed by the ball, it is saved in the ballarea bitmap, so it can be restored when the ball moves. The CopyMode for the scene bitmap is changed to SrcAnd.
A CopyMode defines how a source bitmap will be combined with the destination bitmap, the owner of CopyRect. A color for each pixel is represented by a row of off and on bits. The length of the row depends upon the depth of color. In this case the source bitmap, the ballmask, is combined with the scene. The black ball portion of the mask combines with the scene. The black color is lined up toe to toe with the scene area colors. Because in black all the bits are 0, black is going to be the outcome color regardless of any 1s in the background color. Logical AND, 0 and 1 = 0 or black. Because the background of the mask is white, or all ones, any 0s expressed in the background color will be matched with a 1 from the white mask, which will also leave the same 0s expressed in the combination bitmap. The all 1s from the mask bitmap background will also combine with any 1s in the background. Thus the destination color for the background portion of combined bitmaps will be the same as the scene background.

Notice at each stage of development the results are displayed by using the visual Form Canvas. The CopyMode is now changed to cmSrcPaint, which logically ORS the two bitmaps. The ball bitmap combined with the black hole, produces the ball. 1 or 0 = 1. The ball background ored with the scene produces the scene. 0 OR 1 = 1. Finally the original scene area is simply pasted back into the scene, using cmSrcCopy. Run the program and press Button1 to see these changes.

Finally, we are going to throw the ball across the scene. Add a timer control from the System component page. Using the Object Inspector, set the Interval to 10(ms), and disable the control by double clicking the enable property.
Also add another button control on the form. Double click Button2, and add the following code in the Button2 event handler:

Timer1->Enabled = true;
x=0;
y=20;

This sets the ball at upper left edge of the scene, and activates the timer event handler to move the ball object.Access the Class Explorer, View | ClassExplorer. Right click on the form object in the class explorer, and select New Method. Call the method moveball. No parameters are needed, and set the return type as void. The method type is function and it can be in the private section of the Form1 class header. You can also add this function by simply typing "void moveball()" in the private section of the TForm1 class, and entering TForm1::moveball() { fill in the function statements ...} This function is activated by the timer event handler, each time the time event is called. Notice this is the same essential code that was set up in Button1, with the x position incremented on each call. Enter this code in the moveball function:

TRect locationrect = Rect(x,y,x+ball->Width,y+ball->Width);
ballarea->Canvas->CopyRect(ballrect,scene->Canvas,locationrect);
scene->Canvas->CopyMode = cmSrcAnd;
scene->Canvas->CopyRect(locationrect,ballmask->Canvas,ballrect);
scene->Canvas->CopyMode = cmSrcPaint;
scene->Canvas->CopyRect(locationrect,ball->Canvas,ballrect);

Canvas->CopyRect(Rect(0,0,Width,Height),scene->Canvas,
Rect(0,0,scene->Width,scene->Height));

scene->Canvas->CopyMode = cmSrcCopy;
scene->Canvas->CopyRect(locationrect,ballarea->Canvas,ballrect);
x = x + 3;


Double click the timer control to display the timer event handler function. Enter the timer code:

if (x > (scene->Width - ball->Width))
Timer1->Enabled = false;
else
moveball();

Do you see how you could also increment or decrement the y variable to have the ball bounce up or down. Do you see how the direction of the ball could also be reversed, ie

If ( x ==scene->Width - ball->Width) { ...[Decrement x]....}
Do you seen how you could make things happen, if two objects "collide"?
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top