控制台应用程序下使用GDI在内存中画图
控制台应用程序下使用GDI在内存中画图
1 背景
以前写MFC应用程序的时候,就接触到GDI了。只不过那个时候,Visual Studio已经帮你生成了MFC应用的基本框架,在Visual Studio生成的View文件里,存在一个方法::OnDraw(CDC* /*pDC*/),Visual Studio会添加注释“// TODO: 在此处为本机数据添加绘制代码”,即是说,请在此处调用CDC进行绘制操作。CDC的创建和初始化MFC都帮你完成了,你只需要添加一些个性化代码即可,当然,这对于一个MFC应用来说,当然够了,但是如果你想写一个不使用MFC的应用,我该怎么获得CDC呢?
很多时候,我们并不需要将绘制的图像显示在窗口,只需要将图像绘制在内存中,然后将内存中的图像保存成图片文件。说到内存绘制,也许有人会说,我直接创建一块内存像素数据,然后计算每个图形的像素结构,填充内存像素数据不就可以了么,没有必要使用GDI呀,对于大部分几何图像来说,这么做完全没问题,但是如果你想绘制字符的时候,这么做就很困难了,因为你很难去计算一个字符的像素结构,所以当你需要绘制字符的时候,你还是得使用GDI。
接下来,我将介绍:(1)如何在控制台应用程序下使用GDI在内存中画图;(2)将内存中的图像存储为图片。
2 使用GDI在内存中画图
GDI是Windows API,因此只要是Win32程序(包括Win32应用程序和Win32控制台程序),都可以使用GDI。为了简单起见,如果你想运行本文介绍的代码,新建一个空的Win32控制台程序即可。我觉得在代码中加注释比在这描述更加明了,那么让我们看看代码吧:
[cpp]
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
/**
* 将HBITMAP保存为BMP图片,实现细节见第三节
*/
static void hbitmapToImage(HDC hdc, HBITMAP hbm);
int main(int argc, char *argv[])
{
// 创建绘制环境
HDC memDC = CreateCompatibleDC(NULL);
// 创建画布
HBITMAP hbm = CreateBitmap(100, 100, 1, 32, NULL);
// 创建一个字体,其中40是字体大小,参数可以根据自己需求调整
HFONT hfont = CreateFont(40, 0, 0, 0, FW_THIN, false, false, false,
DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, FF_MODERN, _T("宋体"));
// 选择画布和字体,你可以保存之前的画布和字体用于恢复,为了篇幅起见,在此就不这样做了
SelectObject(memDC, hbm);
SelectObject(memDC, hfont);
// 开始绘制操作
RECT imgRect = {0, 0, 100, 100};// 设置为画布的宽高
SIZE fontPixSize; // 字符的像素大小,对于一种字体来说,其字符的高是一致的,但是宽基本不同
// 将背景填充为黑色
FillRect(memDC, &imgRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
// 得到字符串的像素宽高,可以为任意字符串
GetTextExtentPoint32(memDC, _T("我"), 1, &fontPixSize);
SetTextColor(memDC, RGB(255, 255, 255)); // 设置文本颜色
SetBkMode(memDC, TRANSPARENT); // 设置背景模式
// 计算绘制起始位置,使字符在画布的中间;当然你也可以添加更多的绘制操作,如PolyDraw,LineTo等
TextOut(memDC, (100 - fontPixSize.cx) / 2, (100 - fontPixSize.cy) / 2, _T("我"), 1);
// 将HBITMAP保存为BMP图片
hbitmapToImage(memDC, hbm);
// 释放资源
DeleteObject((HGDIOBJ)hfont);
DeleteObject((HGDIOBJ)hbm);
DeleteDC(memDC);
return 0;
}
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
/**
* 将HBITMAP保存为BMP图片,实现细节见第三节
*/
static void hbitmapToImage(HDC hdc, HBITMAP hbm);
int main(int argc, char *argv[])
{
// 创建绘制环境
HDC memDC = CreateCompatibleDC(NULL);
// 创建画布
HBITMAP hbm = CreateBitmap(100, 100, 1, 32, NULL);
// 创建一个字体,其中40是字体大小,参数可以根据自己需求调整
HFONT hfont = CreateFont(40, 0, 0, 0, FW_THIN, false, false, false,
DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, FF_MODERN, _T("宋体"));
// 选择画布和字体,你可以保存之前的画布和字体用于恢复,为了篇幅起见,在此就不这样做了
SelectObject(memDC, hbm);
SelectObject(memDC, hfont);
// 开始绘制操作
RECT imgRect = {0, 0, 100, 100};// 设置为画布的宽高
SIZE fontPixSize; // 字符的像素大小,对于一种字体来说,其字符的高是一致的,但是宽基本不同
// 将背景填充为黑色
FillRect(memDC, &imgRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
// 得到字符串的像素宽高,可以为任意字符串
GetTextExtentPoint32(memDC, _T("我"), 1, &fontPixSize);
SetTextColor(memDC, RGB(255, 255, 255)); // 设置文本颜色
SetBkMode(memDC, TRANSPARENT); // 设置背景模式
// 计算绘制起始位置,使字符在画布的中间;当然你也可以添加更多的绘制操作,如PolyDraw,LineTo等
TextOut(memDC, (100 - fontPixSize.cx) / 2, (100 - fontPixSize.cy) / 2, _T("我"), 1);
// 将HBITMAP保存为BMP图片
hbitmapToImage(memDC, hbm);
// 释放资源
DeleteObject((HGDIOBJ)hfont);
DeleteObject((HGDIOBJ)hbm);
DeleteDC(memDC);
return 0;
}
3 将HBITMAP保存为BMP图片
第2节描述了如何使用GDI在内存中画图,本节介绍如何将HBITMAP保存为BMP图片。代码如下:
[cpp]
/**
* 将HBITMAP保存为BMP图片
*/
void hbitmapToImage(HDC hdc, HBITMAP hbm)
{
// 得到hbm中每个像素所占的位数
int bmPixBitCount = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
int wBitCount = 0;
if(bmPixBitCount <= 1)
wBitCount = 1;
else if(bmPixBitCount <= 4)
wBitCount = 4;
else if(bmPixBitCount <= 8)
wBitCount = 8;
补充:软件开发 , Vc ,