GDI透明贴图
时间:2022-05-03
本文章向大家介绍GDI透明贴图,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
网上下载的图片,有一些会有水印。水印的实现可以用透明贴图来做。透明贴图就是让两张图片合并的时候,重叠的部分中使一些颜色不显示,从而达到透明的效果。
如果用GDI来实现的话,具体方法步骤可多可少,少的可以使用一个SDK函数就解决。
工程下载地址:点击打开链接
背景图片:
前景图片:
实现效果:
成功把星星画上去了。
先看下面的资料:
//如果一个单色位图向彩色位图转换,那么单色位图为1的部分(也就是白色部分),会转换为彩色位图的背景色,单色位图为0的部分(黑色部分),会转换为彩色位图的前景色。
//如果一个彩色位图向单色位图转换,那么彩色位图的背景色转换到单色位图中则为1(白色),其他的则转换为0(黑色)。
//当然上面的1和0都是指bit位的值,还有这些转换是在设备上下文间的块数据操作前就进行的。
//由于windows上所有的位图操作都是基于内存设备上下文的,所以我们还需要创建两个设备上下文分别用于存放源位图和“掩码”位图。
//位图在设备上下文之间块数据传递需要通过Biltblt实现,对于这个函数和关于bitblt的最后一个参数的光栅操作的具体含义的介绍,这里就不再赘述,具体可看MSDN上关于bilblt的描述。
//对一数据做两次异或操作,那么数据将恢复到原数据,跟没操作一样,透明贴图就是运用该原理。
/*核心代码:
dcImage.SetBkColor(crColour);
dcMask.BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCCOPY);
pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
pDC->BitBlt(x, y, nWidth, nHeight, &dcMask, 0, 0, SRCAND);
pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
*/
CBitmap btfile;
btfile.LoadBitmap(IDB_BITMAP1);
BITMAP btinfo;
btfile.GetBitmap(&btinfo); //获取源位图的大小等信息
CClientDC dcClient(this); // 当前绘画DC,以下表述中可能会称之为“底图”
CDC dcImage, dcMask; // 创建两个用于处理位图的兼容内存DC,MSDN指出图片处理需要在内存DC中进行
// dcImage 该兼容DC用于处理源彩色位图,而dcMask用于生成跟源图对应的黑白掩码位图
dcImage.CreateCompatibleDC(&dcClient); // 跟dcClient兼容
dcImage.SelectObject(&btfile); // 将源彩色位图选人“源图处理dc”
dcImage.SetBkColor(RGB(255, 255, 255));
// 设置背景色,也就是源位图的透明色,假设为白色,我们一般做素材时,将背景做成白色的,
// 在下面,生成掩码图时,跟背景相同的会转换为白色,其他颜色转换为黑色
CBitmap btSingleColor; // 声明位图对象
btSingleColor.CreateBitmap(btinfo.bmWidth, btinfo.bmHeight, 1, 1, NULL);// 设定该内存位图的大小,并设置为单色位图
dcMask.CreateCompatibleDC(&dcClient); // 跟dcClient兼容
dcMask.SelectObject(&btSingleColor); // 将黑白位图选人“掩码处理dc”
dcMask.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCCOPY);
//这里DC之间的块数据拷贝就用到了开头提到的知识点,从彩色位图向单色位图转换,
//源位图的背景图拷到掩码DC中后变为白色,其他则为黑色
dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCINVERT);
// 源图跟底图进行异或
// SRCINVERT:这个光栅操作码代表“异或”操作,SRCAND:代表“与”操作
// 如果对一数据做两次异或操作,那么数据将恢复到原数据,跟没操作一样
// 透明位图就是利用这个特性,将源位图异或的方式拷贝到显示DC两次
// 但是异或拷贝两次的话,那么源位图将不显示,换种说法就是整张位图都被透明了
// 这可不是我们想要的结果,我们的目的只是将背景色透明,所以我们还需要在这两次
// 异或操作中加入其他操作来实现我们想要的结果,这时候就需要上面准备的“掩码”DC来帮忙了
dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcMask, 0, 0, SRCAND);
// 掩码DC内的单色位图跟上面的结果进行与操作,目的是将需要透明的地方保留不变,这样下次再次用源图异或时
// 该部分就应为执行了两次异或而透明了;而最终结果中需要显示的部分,在本次掩码与操作中,
// 应当为清除为0,即黑色,这样下次异或时,将会原封不动的显示出来。
//掩码DC内的单色位图为1的部分,将会保留显示DC的原图,为0的部分将会清除对应区域为0,即为黑色
dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCINVERT);
// 最后在上面步骤的基础上,再次用源数据DC进行一下异或操作,
// 最终的结果,需要透明的部分,源图因为执行了两次异或,而透明了,直接显示底图的图案
// 需要显示的部分,因为是跟0异或,将得到完全的保留。
// 异或操作:(0^1 = 1) (0^0 = 0)
也就是说用对两个图片进行比较复杂的位操作(数学不好,真心觉得很难)。
下面是我的实现,与上面的资料略有不同。
//1 bk背景 fore前景 mask掩码
CDC* dc = GetDC();
CDC bk_DC,fore_DC,mask_DC;
bk_DC.CreateCompatibleDC(dc);
fore_DC.CreateCompatibleDC(dc);
mask_DC.CreateCompatibleDC(dc);
int j = SaveDC(bk_DC.m_hDC);
int i = SaveDC(fore_DC.m_hDC);
int k = SaveDC(mask_DC.m_hDC);
CBitmap bk_bmp,fore_bmp;
bk_bmp.LoadBitmap(IDB_BITMAP1);
fore_bmp.LoadBitmap(IDB_BITMAP2);
bk_DC.SelectObject(bk_bmp);
fore_DC.SelectObject(fore_bmp);
fore_DC.SetBkColor(fore_DC.GetPixel(2,2)); //设置背景颜色
HBITMAP mask_bmp = CreateBitmap(512,384,1,1,NULL);
mask_DC.SelectObject(mask_bmp);
//彩色位图贴到单色位图,彩色位图的背景色变成白色(1),其他变成黑色(0)
mask_DC.BitBlt(0,0,512,384,&fore_DC,0,0,SRCCOPY);
// dc->BitBlt(0,0,512,384,&mask_DC,0,0,SRCCOPY); //白底黑字
fore_DC.SetBkColor(RGB(0,0,0)); //设置背景颜色黑
fore_DC.SetTextColor(RGB(255,255,255)); //设置前景颜色白
//1(白) & x = x;
//0(黑) & x = 0; 背景(黑色)保留了
fore_DC.BitBlt(0,0,512,384,&mask_DC,0,0,SRCAND);
// dc->BitBlt(0,0,512,384,&fore_DC,0,0,SRCCOPY); //背景变为黑,前景没变
bk_DC.SetBkColor(RGB(255,255,255)); //设置背景颜色白
bk_DC.SetTextColor(RGB(0,0,0)); //设置前景颜色黑
bk_DC.BitBlt(0,0,512,384,&mask_DC,0,0,SRCAND);
// dc->BitBlt(0,0,512,384,&bk_DC,0,0,SRCCOPY);
bk_DC.BitBlt(0,0,512,384,&fore_DC,0,0,SRCPAINT);
dc->BitBlt(0,0,512,384,&bk_DC,0,0,SRCCOPY);
RestoreDC(fore_DC.m_hDC,i);
RestoreDC(bk_DC.m_hDC,j);
DeleteObject(mask_bmp);
DeleteDC(bk_DC);
DeleteDC(mask_DC);
DeleteDC(fore_DC);
写完这个代码之后,还不是很理解,尤其是SetBkColor、SetTextColor两个函数与BltBit的SRCAND操作的地方。暂且做个标记吧。
其实,实现透明贴图还可以用MaskBlt和TransparentBlt。MaskBlt最后的参数比较复杂,我还没搞懂就先放过了。而TransParentBlt的话,简单来说就是最快捷方便的方式了。
TransParentBlt可以指定要透明的颜色。
//2
CDC* dc = GetDC();
CDC bk_DC,fore_DC,mask_DC;
bk_DC.CreateCompatibleDC(dc);
fore_DC.CreateCompatibleDC(dc);
int j = SaveDC(bk_DC.m_hDC);
int i = SaveDC(fore_DC.m_hDC);
CBitmap bk_bmp,fore_bmp;
bk_bmp.LoadBitmap(IDB_BITMAP1);
fore_bmp.LoadBitmap(IDB_BITMAP2);
bk_DC.SelectObject(bk_bmp);
fore_DC.SelectObject(fore_bmp);
dc->BitBlt(0,0,512,384,&bk_DC,0,0,SRCCOPY);
dc->TransparentBlt(0,0,512,384,&fore_DC,0,0,510,380,fore_DC.GetPixel(2,2));
RestoreDC(fore_DC.m_hDC,i);
RestoreDC(bk_DC.m_hDC,j);
DeleteDC(bk_DC);
DeleteDC(fore_DC);
是不是觉得比第一种方法简单了十几万倍!
最后,希望看到文章的朋友留下你宝贵的意见或者经验,不胜感激
- 了解PHP中Stream(流)的概念与用法
- 动态绑定与静态绑定
- Android4.0 声卡配置-高通msm8916移植
- PHP安全:session劫持的防御
- 函数式非凡的抽象能力
- 设备树的interrupt
- gitignore文件的作用
- 《Redis设计与实现》读书笔记(十八) ——Redis客户端属性设计与原理
- 使用Python Pandas处理亿级数据
- PHP函数
- Spray中的Authentication和JMeter测试
- 《Redis设计与实现》读书笔记(二十一) ——Redis服务器定时函数serverCron详解
- Spark SQL访问Postgresql
- sysfs_create_group创建sysfs接口
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PAT (Basic Level) Practice (中文)1020 月饼 (25 分)
- 201709-2ccf计算机职业资格认证考试第二题公共钥匙盒
- SAP Spartacus里cx-carousel的实现
- 技术分享 | 改写 mysqldump 解决 DEFINER 问题
- CNS图表复现04—单细胞聚类分群的resolution参数问题
- 学习Vue3.0,先从搭建环境开始
- AIM Tech Round 5 (rated, Div. 1 + Div. 2)C. Rectangles
- PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(二)语法分析
- PAT (Basic Level) Practice (中文)1023 组个最小数 (20 分)
- Angular里使用createEmbeddedView动态加入新的模板元素
- PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
- [笔记整理]几个有点重要的知识点
- PAT (Basic Level) Practice (中文)1005 继续(3n+1)猜想 (25 分)
- PAT (Basic Level) Practice (中文)1033 旧键盘打字 (20 分)