Sunday, August 19, 2007

Windows GDI - Part 1 - Device Context & Usage..

Here we will try to answer some questions related to Device context & Windows GDI.

What is GDI ?
GDI means Graphic device interface.


How we are able to draw on devices ?
Applications can draw and print output on a variety of devices. The software that supports this device independence is contained in two dynamic-link libraries. The first, Gdi.dll, is referred to as the graphics device interface (GDI); the second is referred to as a device driver. The name of the second depends on the device where the application draws output. For example, if the application draws output in the client area of its window on a VGA display, this library is Vga.dll; if the application prints output on an Epson FX-80 printer, this library is Epson9.dll.

What is a DC?
A DC is a structure that defines a set of graphic objects and their associated attributes, and the graphic modes that affect output.

Why DC is used ?

To do all the drawings on a window --like drawing a bitmap, drawing an icon etc. we need device context of the window. So we have to get the DC for that particular window before we do any such operations.


What are the different components of a DC? Explain in detail?

DC has mainly two components
1. Graphic objects
The following table will give info on various graphic objects...

2. Graphic Modes


What is the need of SetBkMode Function? Why SetBkMode(TRANSPARENT) is used?

Background mode is set to OPAQUE by default. So when text is drawn on a particular area, the back ground rectangle, which we specify for Draw Text() API, will be filled by background color. The background will have a default color & can be changed using SetBkColor (). SetBkMode function is used, when we need to draw a text on some background, without filling the bounding rectangle . There we need to change the BkMode to TRANSPARENT, by calling
SetBkMode(TRANSPARENT)..

Types of DC
-------------------
There are 4 types of DC

1. Display DC
2. Memory DC
3. PrintDC
4. Infomation DC

Here we will be concentrating on first two DC's..

Display DC is the most common DC, which we use in OnPaint function. OnPaint function is the message handler of WM_PAINT function. When we say CPaintDC dc(this); as the first statement of OnPaint function, we obtain Display DC & that is dc.. Inside the constructor of CPaintDC BeginPaint() is called, which actually returns the device context. After getting the dc, all the drawing functions available in CDC class can be used since CPaintDC is inherited from CDC.

Memory DC is a temporary place holder in memory. Instead of drawing directly into device we may choose to draw in memory and later draw it onto device. Here a portion of memory act as a virtual device.

How Memory DC is created ?
by calling the CreateCompatibleDC function.

How Memory DC stores the drawings ?

Memory DC stores the everything as a bitmap.
Before an application can begin drawing, it must select a bitmap with the appropriate width and height into the DC by calling the SelectObject function. To create a bitmap of the appropriate dimensions, use the CreateBitmap, CreateBitmapIndirect, or CreateCompatibleBitmap function.When an application passes the handle returned by CreateCompatibleDC to one of the drawing functions, the requested output does not appear on a device's drawing surface.

How final output is rendered onto device using MemoryDC ?

When an application passes the handle returned by CreateCompatibleDC to one of the drawing functions, the requested output does not appear on a device's drawing surface. Instead, the system stores the color information for the resultant line, curve, text, or region in the array of bits. The application can copy the image stored in memory back onto a drawing surface by calling the BitBlt function, identifying the memory DC as the source device context and a window or screen DC as the target device context

Give examples where Memory DC comes handy over Display DC?
Suppose we are drawing lot of things in OnPaint and we need to invalidate the screen often. In this case display DC will cause lot of flicker. So if we do all the drawing in Memory DC and render it at the end of OnPaint(), it will remove the flicker.

Best example is
BufferDC class which uses the concept.

What are the basic steps for any drawing?

First step is to get the DC for the particular window. Then we need to create the bitmap/pen/brush/palette as per our needs. Or we can load a bitmap/icon from resource file using LoadImage () function. Once this is done, we have a handle for the Graphic object. (Handle can be of type hBitmap, hIcon etc.) Using this handle we can draw the object. On the other hand we can use the handle to select the object also. Then we can draw the same onto device. After drawing we need to delete the handle. For Windows the following code illustrates how to draw the bitmap on to screen.

Desktop MFC (Windows)

CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here

// Do not call CWnd::OnPaint() for painting messages
// TODO: Add your message handler code here

CBitmap Bitmap; // Bitmap class to load the bitmap

CPoint pt; // start point of drawing
pt.x = pt.y = 10;

CSize size; // size of bitmap

size.cx = 320;
size.cy = 240;

// load the bitmap into application
Bitmap.LoadBitmap(MAKEINTRESOURCE(IDB_STARTUPSCREEN));

//Get the bitmap handle
HBITMAP bitmap = Bitmap.operator HBITMAP();

// draw the Bitmap..
dc.DrawState(pt,size,bitmap,DST_BITMAP);

//delete handle
BOOL retvalue = Bitmap.DeleteObject();


But for WinCE DrawState() API is not supported..So we need to copy the bitmap into memory dc ie, using SelectObject API() and the draw the same.

void DrawBitmap(CPaintDC *device context, int BitmapID,CRect* rect)
{


CDC memoryDC;
HANDLE hBitmap; // Handle
CBitmap bmpImage;
BITMAP bitmpImage;

devicecontext->SetBkMode(TRANSPARENT);

// Get compatible device context
memoryDC.CreateCompatibleDC(devicecontext);

//Load the bitmap
hBitmap = LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(BitmapID),
IMAGE_BITMAP,ZERO,ZERO,LR_DEFAULTCOLOR);

//Attach the bitmap
if(hBitmap)
{
bmpImage.Detach();
bmpImage.DeleteObject();
bmpImage.Attach(hBitmap);
}

// select the bitmap to DC
bmpImage.GetObject(sizeof(BITMAP),&bitmpImage);
CBitmap *pOldBmp = (CBitmap*)memoryDC.SelectObject(&bmpImage);

// Draw the bitmap on screen
devicecontext->StretchBlt(rect->left,rect->top,rect->Width(),rect->Height(),
&memoryDC, ZERO, ZERO, bitmpImage.bmWidth,
bitmpImage.bmHeight, SRCCOPY);

// Delete the bitmap attached to the object from memory by
// freeing all system storage associated with the object.

memoryDC.SelectObject(pOldBmp);
DeleteObject(bmpImage.Detach());
}

Similarly we can draw icon/ draw pattern brushes etc. which i will elaborate more in upcoming blogs. I will try to cover more details about bitmaps / brushes / pens etc. as separate blogs in Windows GDI Section.

Pls feel free to comment..

No comments: