C/C++ GDI绘制位图(可替代图片框组件) 以及 图片失真 解决方法
位图图像(Bitmap),亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个
点组成的。BMP文件的图像深度(用多少个二进制位来表示每个点的颜色)可选1bit、4bit、8bit及24bit,
BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。
Windows下绘制位图使用双缓冲技术,直接将位图选到内存兼容DC中,然后一次显示到窗口DC上。
位图绘制步骤
第一步:
使用CreateCompatibleDC创建一个内存兼容DC,但这个DC尺寸很小,通常是1*1像素大小,不能直接绘制。
第二步:
使用Loadlmage或LoadBitmap加载现有位图,使用SelectObject将位图选入到兼容DC,这时位图尺寸大小就相当于了内存设备环境尺寸大小。
第三步:
使用BitBlt或StretchBlt将兼容DC一次性显示到窗口DC上。
步骤详细说明
绘制位图跟双缓冲绘制技术原理差不多,
所以,第一步,和第三步的函数介绍请参考:http://www.qingzhouquanzi.com/292.html
只不过 那个是创建位图,而这个是加载现有的位图,可以先看 那一篇再看这个 更容易理解
第二步加载位图函数说明:
HANDLE WINAPl LoadImage (
HINSTANCE hinst,//模块句柄,如果要加载独立资源,如c: \ my.bmp,那么此参数设为NULL
LPCTSTR lpszName,//图片路径或MAKEINTRESOURCE(iDB_XXX)宏产生的字符串
UINT uType,//IMAGE_BITMAP位图、IMAGE_CURSOR光标、IMAGE_ICON图标
int cxDesired,//图标或光标的宽度、如果此参数为零并且未使用LR_DEFAULTSIZE,
则该函数将使用实际的资源高度。
int cyDesired, //图标或光标的高度
UINT fuLoad //标识
) ;
fuLoad 可以是以下值
LR_CREATEDIBSECTION
当uType参数指定IMAGE_BITMAP时,会导致函数返回DIB段位图而不是兼容的位图。该标志对于加载位图而不将其映射到显示设备的颜色很有用。
LR_DEFAULTCOLOR
默认标志;它什么也没做。它的意思是“不是LR_MONOCHROME”。
LR_DEFAULTSIZE
如果cxDesired或cyDesired值设置为零,则使用游标或图标的系统度量值指定的宽度或高度。
如果未指定此标志且cxDesired和cyDesired设置为零,则该函数将使用实际的资源大小。如果资源包含多个图像,则该函数使用第一个图像的大小。
LR_LOADFROMFILE (一般这个用的比较多)
从由lpszName(图标,光标或位图文件)指定的文件加载独立映像。
返回值:
如果函数成功,则返回值是新加载的图像的句柄。
如果函数失败,返回值为NULL。要获得扩展的错误信息,请调用GetLastError。
备注:
使用完毕后调用DeleteObject释放位图,DestroyCursor释放光标,Destroylcon释放图标
代码例子
case WM_PAINT: { PAINTSTRUCT ps;//绘图结构体 HDC hdc=BeginPaint(hwnd, &ps); //第一步:=创建一个内存兼容DC,此时它的大小是1*1,很小,不能绘制 HDC hMenDC = CreateCompatibleDC(hdc); //第二步:加载现有位图 HBITMAP hMenBmp = (HBITMAP)LoadImage(NULL, TEXT("D:/c++练习/精通Windows API高级编程_练习/58GDI绘图 加载图片 显示到窗口上(可对图片进行绘制)/1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //并且把兼容位图选到兼容内存DC中,此时DC的大小与位图一致,可以绘制 SelectObject(hMenDC, hMenBmp); //第三步:在内存兼容DC上绘制各种图形 //SetTextColor(hMenDC,RGB(255, 0, 0)); //TextOut(hMenDC, 0, 0, TEXT("这是一个简单的绘图例子"), lstrlen(TEXT("这是一个简单的绘图例子"))); //Rectangle(hMenDC, 30, 30, 80, 80); //第四步 把内存中的图像一次性画到窗口DC上 //不拉伸 BitBlt(hdc, 0, 0, 100, 100, hMenDC, 0, 0,SRCCOPY); //拉伸 StretchBlt(hdc,0, 100, 200, 200, hMenDC, 0, 0, 800, 800, SRCCOPY); //缩放 StretchBlt(hdc, 300, 0, 50, 50, hMenDC, 0, 0, 800, 800, SRCCOPY); //最后不要忘记释放资源 DeleteDC(hMenDC); DeleteObject(hMenBmp); EndPaint(hwnd,&ps); break; }
运行结果(此时图片失真!):
图片失真解决方法:
StretchBlt会碰到一些与点阵图放大缩小缩放相关的一些问题:
操作会造成产生的图像有些失真。
1、在扩展一个点阵图时,StretchBlt必须复制图素行或列。如果放大倍数不是原图的整数倍,那么此
2、当目标矩形比源矩形小的时候,必须要将一些点去掉,默认做法是将要去掉的点与旁边的点做AND运算,所以导致像素错误,引起失真。
那么 可以使用 SetStretchBltMode函数可以设置指定设备环境中的位图拉伸模式解决失真问题。
int SetStretchBltMode(
HDC hdc,//设备上下文句柄
int iStretchMode //位图伸展模式
);
iStretchMode 可选值:
BLACKONWHITE: 使用消除和现在的像素颜色值进行逻辑AND(与)操作运算。如果该位图是单色位图,那么该模式以牺牲白色像素为代价,保留黑色像素点。
COLORONCOLOR:删除像素。该模式删除所有消除的像素行,不保留其信息。
HALFTONE:将源矩形区中的像素映射到目标矩形区的像素块中,覆盖目标像素块的一般颜色与源像素的颜
色接近。在设置完HALFTONE拉伸模之后,应用程序必须调用SetBrushOrgEx函数来设置刷子的起始点。如果没有成功,那么会出现刷子没对准的情况。
STRETCH_ANDSCANS: 与BLACKONWHITE一样。
STRETCH_DELETESCANS: 与COLORONCOLOR一样。
STRETCH_HALFTONE:与HALFTONE相同。
STRETCH_ORSCANS: 与WHITEONBLACK相同。
更多模式请参考msdn
返回值:
如果函数成功,返回值为非零。
如果函数失败,返回值为零,调用GetLastError获得扩展的错误信息.
代码实例,在拉伸之前设置拉伸模式
//解决拉伸失真问题 SetStretchBltMode(hdc, COLORONCOLOR); //不拉伸 BitBlt(hdc, 0, 0, 100, 100, hMenDC, 0, 0,SRCCOPY); //拉伸 StretchBlt(hdc,0, 100, 200, 200, hMenDC, 0, 0, 800, 800, SRCCOPY); //缩放 StretchBlt(hdc, 300, 0, 50, 50, hMenDC, 0, 0, 800, 800, SRCCOPY);
运行结果: