GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。GDI的使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。
GDI+ (Graphics Device Interface plus)是2000年后windows发展出来的新技术。GDI+ 是一组通过C++类实现的应用程序编程接口。GDI+是以前版本GDI的继承者,出于兼容性考虑,Windows XP仍然支持以前版本的GDI,但是在开发新应用程序的时候,开发人员为了满足图形输出需要应该使用GDI+,因为GDI+对以前的Windows版本中GDI进行了优化,并添加了许多新的功能。
作为图形设备接口的GDI+使得应用程序开发人员在输出屏幕和打印机信息的时候无需考虑具体显示设备的细节,他们只需调用GDI+库输出的类的一些方法即可完成图形操作,真正的绘图工作由这些方法交给特定的设备驱动程序来完成,GDI+使得图形硬件和应用程序相互隔离.从而使开发人员编写设备无关的应用程序变得非常容易。
1998年诞生的 VC++6.0 支持GDI编程。但默认不支持GDI+。需要用户安装新的windows SDK才行。但VC 2010 版直接支持GDI+ 编程。
GDI只支持bmp等少数图像格式读取,GID+ 支持大多数常见图像格式(如jpg,png, tif,gif等等)。为了方便读取多种格式的图像文件并显示,下面的实验以VS2010为开发平台,讲解如何利用GDI+ 来读取图像文件,并显示在控制台窗口中。(关于如何利用MFC在新建窗口或对话框窗口中应用GDI+的文章很多了,本文就不涉及)。
【注】VS2010 绿色版参见:
VS2010 绿色版下载
使用GDI+,需引入gdiplus.h
并链接gdiplus.lib
库。GDI+的函数在名字空间Gdiplus
中,也要以using namespace Gdiplus;
引入。否则需在GDI+函数前加上Gdiplus::
前缀。
#include
#pragma comment(lib,"gdiplus.lib")
//#define ULONG_PTR ULONG
using namespace Gdiplus;
【注】:在VC6中编译,如出现ULONG_PTR ULONG
未定义,可加上
#define ULONG_PTR ULONG
因为GDI+是WIndows Platform SDK不是MFC的一部分,而ULONG_PTR在SDK中的定义与MFC中的定义相冲突,所以,会出现此问题。
然后,在主程序中用GdiplusStartup
函数启动GDI+ :
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
通过FromFile
打开图像文件。
Image* pImage = Image::FromFile(L"wtclablogo.png");
也可这样:
Image* pImage = new Image(L"testfile.jpg");
其中,L"testfile.jpg"
是将字串转为宽字符的。因为Image类只接受宽字符串WCHAR
。
【注】从字符串char *
到宽字符串类型WCHAR
还可用如下函数来转换。
WCHAR * charToWCHAR(char *s) {
int w_nlen = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
WCHAR *ret;
ret = (WCHAR*)malloc(sizeof(WCHAR)*w_nlen);
memset(ret, 0, sizeof(ret));
MultiByteToWideChar(CP_ACP, 0, s, -1, ret, w_nlen);
return ret;
}
例如,要从main函数的命令行参数中读取文件名(设在argv[1]
中),需做如下转换:
WCHAR * filename;
filename =charToWCHAR(argv[1]);
Image* pImage = new Image(filename);
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
main(){
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
}
构建Graphics
对象,并绑定在显示区hdc
上。(这里没有用双缓冲)
Graphics graphics(hdc);
DrawImag
方法将图像显示出来最后,通过Graphics
对象的DrawImage
方法在屏幕上作图。其中,用pImage->GetWidth()和pImage->GetHeight()
可取出图像的宽和高(像素数)。
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth(), pImage->GetHeight());
程序执行的最后可关闭GDI+ (在控制台窗口程序中,不关闭就退出也可)
GdiplusShutdown( m_gdiplusToken );
本例读取了png图片,并以2倍放大后显示。
#include
#include
#include
#pragma comment(lib,"gdiplus.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
using namespace Gdiplus;
int main() {
Gdiplus::GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
Image* pImage = Image::FromFile(L"wtclablogo.png");
if ((pImage==NULL)||(pImage->GetLastStatus()!=Ok))
{
if (pImage)
{
printf("无法打开图片");
delete pImage;
pImage = NULL;
}
return FALSE;
}
Graphics graphics(hdc);
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
return 0;
}
以上代码在VS2010和VC++6(补充了GDI+)的集成环境中下都可编译。运行结果如下:
从运行结果看,wtclablogo.png
图片中透明部分也正确显示了。
【注】对于gif格式这种以多帧构成的图像,要在VS2010版中自带的GDI+才支持分帧解析。所以以下读取gif图像的实验都要在VS2010中编译完成。
为了使图像显示后能重绘刷新,可用while循环(Ctrl+C退出)结合Sleep函数来实现,如前一篇文件所述。
while(TRUE){
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
Sleep(100);
}
完整代码:
#include
#include
#include
#pragma comment(lib,"gdiplus.lib")
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
using namespace Gdiplus;
int main() {
Gdiplus::GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
HWND hWnd = GetConsoleWindow();
HDC hdc = GetDC(hWnd);
Image* pImage = Image::FromFile(L"wtclablogo.png");
if (!pImage) {
printf("无法打开图片");
return -1;
}
Graphics graphics(hdc);
while(TRUE){
graphics.DrawImage(pImage, 0, 0, pImage->GetWidth()*2, pImage->GetHeight()*2);
Sleep(100);
}
GdiplusShutdown( m_gdiplusToken );//关闭GDI+,可略此句
return 0;
}