这个函数的作用是:根据指定的字符串,生成 LedBitmap;并返回 LedWidth (该图片的LED屏幕坐标的像素宽度);在这个函数里,临时位图实际上在使用完毕后清除,但我为了在PC上的范例的对话框上展示它,所以没有立即清除。
如下图所示,为 4 个 LED 的放大图形,上面两个为熄灭,下面两个为点亮状态;

【注意】我们绘制的原始图像特点是“白底黑字”,因此黑色映射到LED图像的“点亮”状态,白色映射到“熄灭”状态;在下面代码中可看到这一点;
下面是 CreateLedBitmap 的代码,在这段代码中,包含了前面所讲的对“像素定位”的非常重要的方法和信息,涉及了扫描行宽度,位图中的逆序扫描,在图像数据中的像素定位,在像素中的RGB通道定位,这些都是通过指针来完成的,需要务必小心以确保指针的指向合法和正确。
//根据指定的字符串创建实际的用于滚动的位图(比实际图像会增大4倍)
//返回创建的位图的未LED化像素长度(也就是实际字符串的绘制长度)
int CreateLedBitmap(HWND hWnd, TCHAR* text)
{
//创建字体
LOGFONT lf;
HFONT hFont = NULL, hOldFont = NULL;
SIZE size = {0,0};
BITMAPINFO bminfo;
HBITMAP hOldBitmap; //临时位图(为非LED化的实际像素大小)
HBRUSH hBrush =NULL;
RECT rc;
int i, j, stride, strideTemp;
//两个位图的像素数据地址
BYTE *lpBytes, *lpBytesTemp, *lpLed;
//设置位图信息
memset(&bminfo.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //40
bminfo.bmiHeader.biPlanes = 1;
bminfo.bmiHeader.biBitCount = 24;
//测量字符串的大小,其决定作用的还有当前HDC中的字体
HDC hWndDC = GetDC(hWnd);
HDC hDC = CreateCompatibleDC(hWndDC);
ReleaseDC(hWnd, hWndDC);
HFONT hSysFont = (HFONT)GetStockObject(DEVICE_DEFAULT_FONT);
GetObject(hSysFont, sizeof(LOGFONT), &lf);
lf.lfWeight = FW_NORMAL;
lf.lfHeight = (long) -((11.0 * (double)GetDeviceCaps(hDC, LOGPIXELSY) / 72.0) + .5);
//lf.lfHeight = 11;
wcscpy(lf.lfFaceName, _T("宋体"));
// create the font
hFont = CreateFontIndirect(&lf);
//创建背景刷
hBrush = CreateSolidBrush(BKCOLOR_LED);
hOldFont = (HFONT)SelectObject(hDC, hFont);
//测量字符串,得到的高度应该是14,宽度取决于字符串
GetTextExtentPoint32(hDC, text, wcslen(text), &size);
//计算扫描行宽度
stride = (24 * size.cx * LEDSIZE + 31)/32 * 4;
strideTemp = (24* size.cx + 31)/32 * 4;
bminfo.bmiHeader.biWidth = size.cx * LEDSIZE;
//去掉上下的2行像素
bminfo.bmiHeader.biHeight = size.cy * LEDSIZE; //(14-2)*4=48pixels,
bminfo.bmiHeader.biSizeImage = bminfo.bmiHeader.biHeight * stride;
//创建位图
if(g_BitmapLed != NULL)
DeleteObject(g_BitmapLed);
if(g_BitmapTemp != NULL)
DeleteObject(g_BitmapTemp);
//注意WinCe平台上不支持内存映射,所以无法提供我们自己的位图数据,而是由系统负责分配
g_BitmapLed = CreateDIBSection(hDC, &bminfo, DIB_RGB_COLORS, (VOID**)&lpBytes, NULL, 0);
//是否创建成功?
if(g_BitmapLed == NULL)
{
goto CLEARNUP_EXIT;
}
//创建实际大小的位图
bminfo.bmiHeader.biWidth = size.cx;
bminfo.bmiHeader.biHeight = size.cy;
g_BitmapTemp = CreateDIBSection(hDC, &bminfo, DIB_RGB_COLORS, (VOID**)&lpBytesTemp, NULL, 0);
if(g_BitmapTemp == NULL)
{
goto CLEARNUP_EXIT;
}
//在实际绘图上进行绘制
hOldBitmap = (HBITMAP)SelectObject(hDC, g_BitmapTemp);
rc.left = rc.top = 0;
rc.right = size.cx;
rc.bottom = size.cy;
//填充白色背景
FillRect(hDC, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
SetTextColor(hDC, RGB(0,0,0)); //黑色字体
SetBkMode(hDC, TRANSPARENT);
//绘制字符串
DrawText(hDC, text, wcslen(text), &rc, DT_LEFT | DT_VCENTER| DT_NOCLIP | DT_SINGLELINE);
//现在再把LED图选入DC中去刷一次背景
SelectObject(hDC, g_BitmapLed);
//rc设置为LED图的大小
rc.right = size.cx * LEDSIZE;
rc.bottom = size.cy * LEDSIZE;
FillRect(hDC, &rc,hBrush);
//复原DC
SelectObject(hDC, hOldBitmap);
SelectObject(hDC, hOldFont);
//现在根据它进行拷贝到新的位图中,去掉了上下两行像素,i,j是在 bitmaptemp中的坐标
//每个LED灯实际上是 4 * 4像素的小矩形块!设置6个像素即可
for(j = 0; j< size.cy; j++)
{
for(i = 0; i < size.cx; i++)
{
//把指针定位到LED灯的左上角!
//注意这里行是倒序的!(所以距离内存起始点的最远的哪一行才是LED第一行,逐行向内存起始处返回)
lpLed = lpBytes + stride*(j*LEDSIZE+3) + i*3*LEDSIZE;
if(lpBytesTemp[strideTemp * j + i*3] == 0) //即,该通道为黑色,表示这里是字迹(应该点亮这个灯)
{
//点亮 9 * 9
//第一行 0-Blue, 1-Green, 2-Red
lpLed[0]= 76, lpLed[1]=154, lpLed[2]=186;
lpLed[3]=130, lpLed[4]=207, lpLed[5]=236;
lpLed[6]= 56, lpLed[7]=145, lpLed[8]=204;
//第二行
lpLed -= stride;
lpLed[0]=127, lpLed[1]=214, lpLed[2]=245;
lpLed[3]=193, lpLed[4]=232, lpLed[5]=247;
lpLed[6]= 43, lpLed[7]=167, lpLed[8]=241;
//第三行
lpLed -= stride;
lpLed[0]= 56, lpLed[1]=144, lpLed[2]=204;
lpLed[3]= 43, lpLed[4]=160, lpLed[5]=231;
lpLed[6]= 43, lpLed[7]=125, lpLed[8]=207;
}
else
{
//熄灭 9 * 9
//第一行 0-Blue, 1-Green, 2-Red
lpLed[0]= 65, lpLed[1]= 65, lpLed[2]= 65;
lpLed[3]= 84, lpLed[4]= 84, lpLed[5]= 84;
lpLed[6]= 65, lpLed[7]= 65, lpLed[8]= 65;
//第二行
lpLed -= stride;
lpLed[0]= 84, lpLed[1]= 84, lpLed[2]= 84;
lpLed[3]= 66, lpLed[4]= 66, lpLed[5]= 66;
//lpLed[6]= 65, lpLed[7]= 65, lpLed[8]= 65;
//第三行
lpLed -= stride;
lpLed[0]= 65, lpLed[1]= 65, lpLed[2]= 65;
//lpLed[3]=130, lpLed[4]=207, lpLed[5]=236;
//lpLed[6]= 56, lpLed[7]=145, lpLed[8]=204;
}
}
}
CLEARNUP_EXIT:
//清理
if(hBrush !=NULL)
DeleteObject(hBrush);
if(hFont != NULL)
DeleteObject(hFont);
if(hDC != NULL)
DeleteDC(hDC);
return size.cx;
}