您的位置:首页 > 编程语言 > C语言/C++

VC++控制台应用程序下使用GDI在内存中画图

2012-11-05 13:55 876 查看
VC++控制台应用程序下使用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控制台程序即可。我觉得在代码中加注释比在这描述更加明了,那么让我们看看代码吧:

#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图片。代码如下:

/**
* 将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;
else
wBitCount = 24;
//////////////////////////////////////////////////////////////////////////
BITMAP bm;
GetObject(hbm, sizeof(bm), &bm);
int bmRowCount = ((bm.bmWidth * wBitCount + 31) / 32) * 4; // 一行所占的字节数,BMP像素数据按四字节对齐
int bmByteCount =  bmRowCount * bm.bmHeight; // 像素数据的大小
char *buf = new char[bmByteCount];
// 位图信息头结构,定义参考MSDN
BITMAPINFOHEADER bi;
bi.biSize= sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight =  bm.bmHeight;
bi.biPlanes =  1;
bi.biBitCount = wBitCount;
bi.biCompression= BI_RGB;
bi.biSizeImage=0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed =  0;
GetDIBits(hdc, hbm, 0, bm.bmHeight, buf, (BITMAPINFO*)(&bi), DIB_RGB_COLORS); // 得到像素值,保存在buf中
// 位图文件头结构,定义参考MSDN
BITMAPFILEHEADER bf;
bf.bfType = 0x4D42;	// BM
bf.bfSize = bmByteCount;
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// 写入文件
FILE *bmFile = fopen("demo.bmp", "w+b");
if (bmFile)
{
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, bmFile);	// 写入位图文件头
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, bmFile);	// 写入位图信息头
fwrite(buf, sizeof(char), bmByteCount, bmFile);		// 写入像素数据
fclose(bmFile);
}
delete []buf;
}


程序运行结果如图1所示:



图1:程序运行结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: