EasyX绘制透明背景图的方法详解

 更新时间:2023年01月06日 10:28:52   作者:Bluemultipl  
这篇文章主要为大家详细介绍了EasyX绘制透明背景图的方法,文中的示例代码讲解详细,对我们深入了解EasyX有一定的帮助,需要的可以参考一下

三元光栅操作

根据在网上的搜索总结得到两种方案,最常见的绘制带有透明背景的图像的方案都是采用如下的源图像和掩码图像叠加来消去边缘部分:

IMAGE img[2];

loadimage(&img[0], "sun1.png", 100, 100); // 掩码图像
loadimage(&img[1], "sun0.png", 100, 100); // 源图像

putimage(0, 0, &img[0], NOTSRCERASE);   // 掩码图与背景或取反
putimage(0, 0, &img[1], SRCINVERT);     // 源图像与背景异或

直观理解:由于按位运算是依次对某一位做运算,因此只需要考察一位数字的变化

// 不妨假设白色为 1,黑色为 0

// 需要变成透明的部分,需要显示最初的背景色
// 背景色为 a,~a 表示反 a,掩码此部分是黑色 0,源图像此部分是白色 1
~ (a | 0); //-> ~a 或取反
(~a) ^ 1; //-> a 异或
// 结果仍为背景色

// 需要显示源图像的部分
// 背景色为 a,源图像此部分为 b,掩码此部分是白色 1
~ (a | 1); //-> 0 或取反(可以看到第一部分与 a 无关)
0 ^ b; //-> b 异或
// 结果为源图像

然而,上面的方案虽然足够解决问题,但是未免太过繁琐,不仅需要源图像,还需要花时间来制作掩码图。最糟糕的就是技术问题导致掩码图和原图不能完全重合,绘制出的图像有黑边。

于是,经过长期搜索,终于找到一种不需要掩码图,而是直接对图像进行处理的方案。

优化方案

此方案使用了贝叶斯定理来对图像的每个像素进行计算,原版代码的具体来源因为时间比较久,已经找不到了。这里的方案和原版本有所不同,因为实际需求,我根据原版本添加了透明度参数 AA ,并且修改了部分代码使得它与我的需求相契合。

函数声明为:

void drawAlpha(
    IMAGE* image, 			// 图像指针
    int x, int y, 			// 输出坐标
    int width, int height, 	 // 输出尺寸
    int pic_x, int pic_y, 	 // 图像中的位置
    double AA = 1			// 透明度
);

也就是说它会在 x,y 位置输出从图像中 pic_x,pic_y 位置开始,宽高为 width,height 的部分,且透明度为 AA 。

函数定义部分:

// 绘图函数,补充透明度 AA
void drawAlpha(IMAGE* image, int x, int y, int width, int height, int pic_x, int pic_y, double AA = 1)
{
	// 变量初始化
	DWORD* dst = GetImageBuffer();			// GetImageBuffer() 函数,用于获取绘图设备的显存指针, EasyX 自带
	DWORD* draw = GetImageBuffer();
	DWORD* src = GetImageBuffer(image);		// 获取 picture 的显存指针
	int imageWidth = image->getwidth();		// 获取图片宽度
	int imageHeight = image->getheight();	// 获取图片宽度
	int dstX = 0;							// 在 绘图区域 显存里像素的角标
	int srcX = 0;							// 在 image 显存里像素的角标

	// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
	for (int iy = 0; iy < height; iy++)
	{
		for (int ix = 0; ix < width; ix++)
		{
			// 防止越界
			if (ix + pic_x >= 0 && ix + pic_x < imageWidth && iy + pic_y >= 0 && iy + pic_y < imageHeight &&
				ix + x >= 0 && ix + x < WindowWidth && iy + y >= 0 && iy + y < WindowHeight)
			{
				// 获取像素角标
				int srcX = (ix + pic_x) + (iy + pic_y) * imageWidth;
				dstX = (ix + x) + (iy + y) * WindowWidth;

				int sa = ((src[srcX] & 0xff000000) >> 24) * AA;			// 0xAArrggbb; AA 是透明度
				int sr = ((src[srcX] & 0xff0000) >> 16);				// 获取 RGB 里的 R
				int sg = ((src[srcX] & 0xff00) >> 8);					// G
				int sb = src[srcX] & 0xff;								// B

				// 设置对应的绘图区域像素信息
				int dr = ((dst[dstX] & 0xff0000) >> 16);
				int dg = ((dst[dstX] & 0xff00) >> 8);
				int db = dst[dstX] & 0xff;
				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg
					| (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db
			}
		}
	}
}

注意其中 WindowWidth 和 WindowHeight 都是预先定义的全局变量。实际应用时,先在头文件中定义窗口尺寸,然后就可以直接使用

IMAGE img;
loadimage(&img, "sun.png", 100, 100);

int x = 100, y = 100;
int width = 50, height = 50;
int pic_x = 50, pic_y = 50;

drawAlpha(img, x, y, width, height, pic_x, pic_y, 0.8);

还可以调整透明度为 0.8 ,比方案 1 更为实用。

到此这篇关于EasyX绘制透明背景图的方法详解的文章就介绍到这了,更多相关EasyX绘制透明背景图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈C++如何求等差素数列

    浅谈C++如何求等差素数列

    这篇文章主要介绍了浅谈C++如何求等差素数列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • C++数据结构之实现循环顺序队列

    C++数据结构之实现循环顺序队列

    这篇文章主要介绍了 C++数据结构之实现循环顺序队列的相关资料,需要的朋友可以参考下
    2017-01-01
  • C语言超详细讲解队列的实现及代码

    C语言超详细讲解队列的实现及代码

    队列(Queue)与栈一样,是一种线性存储结构,它具有如下特点:队列中的数据元素遵循“先进先出”(First In First Out)的原则,简称FIFO结构。在队尾添加元素,在队头删除元素
    2022-04-04
  • C++ continue和break语句

    C++ continue和break语句

    这篇文章主要介绍了C++ continue和break语句,文章围绕continue和break语句的相关资料展开详细内容,需要的朋友可以参考一下,希望对大家有所帮助
    2021-11-11
  • c++利用vector创建二维数组的几种方法总结

    c++利用vector创建二维数组的几种方法总结

    这篇文章主要介绍了c++利用vector创建二维数组的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C语言数据结构与算法之链表(二)

    C语言数据结构与算法之链表(二)

    在这篇文章中,我们将抛开令人头秃的指针和结构体,我们将另外使用一种数组来实现的方式,叫做模拟链表。让来跟随小编一起学习学习吧
    2021-12-12
  • C语言详解关键字sizeof与unsigned及signed的用法

    C语言详解关键字sizeof与unsigned及signed的用法

    这篇文章主要为大家详细介绍了C语言关键字sizeof&&unsigned&&signed,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++简明讲解缺省参数与函数重载的用法

    C++简明讲解缺省参数与函数重载的用法

    所谓缺省参数,顾名思义,就是在声明函数的某个参数的时候为之指定一个默认值,在调用该函数的时候如果采用该默认值,你就无须指定该参数。C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载,借助重载,一个函数名可以有多种用途
    2022-06-06
  • Qt5连接并操作PostgreSQL数据库的实现示例

    Qt5连接并操作PostgreSQL数据库的实现示例

    本文主要介绍了Qt5连接并操作PostgreSQL数据库的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • 超级详细讲解C++中的多态

    超级详细讲解C++中的多态

    多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为,下面这篇文章主要给大家介绍了关于C++中多态的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05

最新评论