夏树的C语言篇 – 修改控制台窗口大小

夏树的C语言篇 – 基于GDI的控制台贴图

0.写在前面

这篇文章主要整理介绍了关于VC6.0使用GDI对控制台进行贴图的内容, 需要引入头文件windows.h

1.获取上下文句柄(GetDC)

1.1.函数原型

HDC GetDC(HWND hWnd);

1.2.函数介绍

GetDC函数是用来获取显示设备的上下文环境DC的句柄(HDC, 显示设备可以是某个窗口或者是整个屏幕), 之后可以使用GDI函数通过这个句柄对显示设备进行绘图操作。

1.3.函数封装

在向控制台贴图之前, 需要先向GetDC函数传入控制台窗口句柄(hWnd)来获得DC的句柄(HDC); 而为了获得控制台窗口句柄, 可以通过GetConsoleTitle取得控制台窗口的标题之后, 再使用FindWindow根据窗口标题获得HDC。

下面可以把这些步骤封装成一个函数来实现, 便于之后的调用:

HDC NtkGetDC()
{
    TCHAR title[256];
    HDC hdc = NULL;

    GetConsoleTitle(title,256);
    hdc = GetDC(FindWindow(0,title));
    return hdc;
}

2.装载位图(LoadImage)

2.1.函数原型

HANDLE LoadImage(HINSTANCE hinst,LPCTSTR lpszName,UINT uType,int cxDesired,int cyDesired,UINT fuLoad);

2.2.函数介绍

LoadImage函数用来装载图标,光标,或位图。

2.3.函数封装

因为本文的主题是介绍VC6.0的控制台贴图, 那么接下来的使用以装载.bmp位图为例。

同样的, 可以将其封装为一个函数: 传入HBITMAP *pImg来存储加载的位图数据, filename为需要加载位图的文件路径(使用绝对路径或相对路径均可), widthheight为将位图拉伸或者收缩的宽高尺寸(若要按原图载入则都传入0即可)

void NtkLoadImage(HBITMAP* pImg, char* filename, int width, int height)
{
    *pImg = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,width,height,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
}

如果要了解LoadImage的详细参数可以参考网上的文档

3.输出位图到控制台前的准备

3.1.概念明确

Windows系统是不允许直接访问硬件的, 因此对于屏幕的操作(绘图等)是通过上下文环境DC来实现的, 不能直接将位图数据拷贝至表示控制台窗口的DC。但由于DC之间的数据是可以相互拷贝的, 在输出位图到控制台窗口之前, 可以建立不属于控制台窗口的DC用于存储位图数据, 在通过DC间的拷贝间接将位图输出到控制台窗口。

3.2.创建兼容的上下文环境(CreateCompatibleDC)

CreateCompatibleDC函数用于创建一个与指定设备兼容的内存设备上下文环境(DC)。

函数原型为: HDC CreateCompatibleDC(HDC hdc);
使用时只需要传入GetDC函数所获得的DC句柄(HDC)即可。

hdcMem = CreateCompatibleDC(hdc);

hdcMem使用完成后可通过DeleteDC(hdcMem);进行删除。

4.输出位图到控制台

有了之前的准备, 现在可以使用GDI函数在控制台窗口上贴图了, 常用的贴图GDI函数有BitBltStretchBltTransparentBlt这三个。

4.1.BitBlt

4.1.1.函数原型

BitBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, hdc hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
hdcDest为标题1GetDC函数所获得的HDC, nXDest和nYDest为输出的坐标(矩形左上角点坐标), nWidth和nHeight为输出的宽高(小于位图的宽高时会隐藏多余的部分), nXSrc和nYSrc通常填0即可(后面会讲到特殊用法), dwRop为光栅操作符(有点类似于PS图层混合模式中的一些选项, 仅贴图通常填SRCCOPY即可)

4.1.2.使用举例

#include <windows.h>

int main()
{
    TCHAR title[256];
    HDC hdc,hdcMem;
    HBITMAP img,hOldBmp;

    GetConsoleTitle(title,256);
    hdc = GetDC(FindWindow(0,title));
    hdcMem = CreateCompatibleDC(hdc);

    img = (HBITMAP)LoadImage(NULL,"image.bmp",IMAGE_BITMAP,226,229,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);

    hOldBmp = (HBITMAP)SelectObject(hdcMem,img);
    BitBlt(hdc,12,13,226,229,hdcMem,0,0,SRCCOPY);
    SelectObject(hdcMem,hOldBmp);
    DeleteDC(hdcMem);

    return 0;
}

2020_03_04_Bitblt.jpg

4.2.StretchBlt

4.2.2.与Bitblt的关系

StretchBltBitblt的参数其实是类似的, 但不同的是当设置的宽高与图片自身宽高不一致时, StretchBlt不会隐藏掉图片多余的部分(不会对图片进行裁剪), 而是对图片进行拉伸或者收缩。

4.2.2.函数原型

StretchBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop);
参数与Bitblt是类似的, 而需要对图片进行拉伸时, nWidth和nHeight是拉伸后的宽高(目标矩形的宽高), nWidthSrc和nHeightSrc则是位图自身的宽高

4.2.3.使用举例

将原图宽为226px高为229px的图像拉伸到宽100px高300px:

#include <windows.h>

int main()
{
    TCHAR title[256];
    HDC hdc,hdcMem;
    HBITMAP img,hOldBmp;

    GetConsoleTitle(title,256);
    hdc = GetDC(FindWindow(0,title));
    hdcMem = CreateCompatibleDC(hdc);

    img = (HBITMAP)LoadImage(NULL,"image.bmp",IMAGE_BITMAP,226,229,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);

    hOldBmp = (HBITMAP)SelectObject(hdcMem,img);
    StretchBlt(hdc,12,13,100,300,hdcMem,0,0,226,229,SRCCOPY);
    SelectObject(hdcMem,hOldBmp);
    DeleteDC(hdcMem);

    return 0;
}

2020_03_04_StretchBlt.jpg

4.3.TransparentBlt

4.3.1.函数介绍

当需要以某个颜色作为背景色透明时, TransparentBlt是一个不错的选择, 根据不同的参数,它也可以像Bitblt或者StretchBlt那样对位图进行裁剪或者是拉伸和收缩。但是TransparentBlt没有光栅操作符的参数dwRop

4.3.2.函数原型

TransparentBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, int nWidthSrc, int nHeightSrc, UINT crTransparent);
crTransparent参数是用来指定以某个颜色作为背景色透明的, 该颜色可通过RGB函数得到。

4.3.3.可能遇到的问题

在使用MARKDOWN_HASH0eabf4fc8c988228ba9ef479040f99ddMARKDOWNHASH函数编译时, VC6.0可能会提示如下错误: error LNK2001: unresolved external symbol __imp\_TransparentBlt@44

此时打开项目设置, 为链接器添加Msimg32.lib库即可:

Project_Setting.jpg
Add_Msimg32.lib.png

4.3.4.使用举例

以品红(RGB(255,0,254))为透明色:

#include <windows.h>

int main()
{
    TCHAR title[256];
    HDC hdc,hdcMem;
    HBITMAP img,hOldBmp;

    GetConsoleTitle(title,256);
    hdc = GetDC(FindWindow(0,title));
    hdcMem = CreateCompatibleDC(hdc);

    img = (HBITMAP)LoadImage(NULL,"image.bmp",IMAGE_BITMAP,226,229,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);

    hOldBmp = (HBITMAP)SelectObject(hdcMem,img);
    TransparentBlt(hdc,12,13,226,229,hdcMem,0,0,226,229,RGB(255,0,254));
    SelectObject(hdcMem,hOldBmp);
    DeleteDC(hdcMem);

    return 0;
}

TransparentBlt_example.png

5.nXSrc和nYSrc

(待编写…)

发布者

《夏树的C语言篇 – 基于GDI的控制台贴图》上有2条评论

  1. Note: 如果GetDC函数的HWND hWnd参数传入NULL, 则将会获得整个屏幕的上下文句柄(HDC), 之后GDI函数可以通过该HDC针对整个屏幕进行绘制操作。

  2. Note: 为了使用TransparentBlt其实也可以不修改链接器设置, 使用#pragma comment(lib,"Msimg32.lib")为Msimg32.lib添加引用即可(注意语句末尾无分号)。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注