1 Attachment(s)
Windows SDK GDI: How do I display text filled and in shape of a region?
Q: How do I display text filled and in shape of a region?
A: Displaying text as non-rectangular is a bit of tricky. Here, I will explain how the text can be displayed as deformed to take the shape of a region. I am presenting the code in the form of a function (I have used the familiar name 'DrawText()' for this function), whose parameters are handles to the device context (as 'HDC'), the string to be displayed (as 'LPSTR') and the handle to the region (as 'HRGN').
<br>
Code:
void DrawText(HDC hdc, LPSTR lpstring, HRGN hrgn)
{
// Creates a memory device context
HDC hMemDC = CreateCompatibleDC(hdc);
if (hMemDC)
{
// Memory device context is created successfully
// Gets the width and height of the string
DWORD Size = GetTabbedTextExtent(hMemDC, lpstring, strlen(lpstring), 0, NULL);
int Width = LOWORD(Size);
int Height = HIWORD(Size);
// Creates bitmap and selects to the memory device context
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, Width, Height);
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap);
// Paints memory device context in white
RECT Rect;
SetRect(&Rect, 0, 0, Width, Height);
FillRect(hMemDC, &Rect, (HBRUSH) GetStockObject(WHITE_BRUSH));
// Sets color and background mode
COLORREF Black = RGB(0, 0, 0);
SetTextColor(hMemDC, Black);
SetBkMode(hMemDC, TRANSPARENT);
// Displays string in memory device context
TextOut(hMemDC, 0, 0, lpstring, strlen(lpstring));
// Finds the text occupying area bounded by X0, Y0, X1, Y1
int X0 = -1;
int X1 = -1;
int Y0 = -1;
int Y1 = -1;
for (int iX = 0; iX <= Width; iX++)
for (int iY = 0; iY <= Height; iY++)
if (GetPixel(hMemDC, iX, iY) == Black)
{
X0 = X0 >= 0 ? (iX < X0 ? iX : X0) : iX;
Y0 = Y0 >= 0 ? (iY < Y0 ? iY : Y0) : iY;
X1 = X1 >= 0 ? (iX > X1 ? iX : X1) : iX;
Y1 = Y1 >= 0 ? (iY > Y1 ? iY : Y1) : iY;
}
// Computes bounds of region
GetRgnBox(hrgn, &Rect);
// Gets current text color of device context
COLORREF Color = GetTextColor(hdc);
// Scans the region in X direction
for (iX = Rect.left; iX <= Rect.right; iX++)
{
int X = X0 + (X1 - X0) * (iX - Rect.left) / (Rect.right - Rect.left);
int YMin = -1, YMax = -1;
// Computes bounds of Y for corresponding iX
for (int iY = Rect.top; iY <= Rect.bottom; iY++)
if (PtInRegion(hrgn, iX, iY))
{
YMin = YMin >= 0 ? (iY < YMin ? iY : YMin) : iY;
YMax = YMax >= 0 ? (iY > YMax ? iY : YMax) : iY;
}
// Scales string image for current Y limits
if (YMax != YMin)
for (iY = YMin; iY <= YMax; iY++)
{
int Y = Y0 + (Y1 - Y0) * (iY - YMin) / (YMax - YMin);
if (GetPixel(hMemDC, X, Y) == Black)
SetPixel(hdc, iX, iY, Color);
}
}
// Deselects bitmap and deletes device context
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
}
The method used here is quite simple. What I did is to write the string in a memory device context and scale it to the region according to its minimum and maximum 'Y' value at each 'X' position. Sample comments are given at each steps.
Here is a screen shot of what I got. Note that the region is shaded in gray for illustration.
<br><br><br>