概述
EGE专栏:EGE专栏
目录
- 光栅操作
- (1) 光栅
- (2)二元光栅操作码
- (3) 三元光栅操作码
光栅操作
(1) 光栅
光栅图也叫做位图、点阵图、像素图。图像其实由一个个像素点组成,每个像素点都有自己的颜色。显示屏就是由一个个的小点组成,当这些点都很小,而且都很紧密地排在一起时。我们就看到一幅连续的图像。但靠近看时,还是能看到一一的小点。
输出时,是读取显存中的每一个点的颜色数据,然后根据颜色输出显示屏上。
点的颜色是用无符号整型表示的,绘图时就是在改变这些颜色数据。既然是改变颜色数据,那就有原有数据和新数据,所以改变就有很多种操作方式,一般是位操作。可以是直接赋值,也可以是保留原有数据,或者两个数值位与,位或,取反等。
(2)二元光栅操作码
二元光栅操作码就是用来控制改变像素时的位操作方式的。每个二元光栅操作码对应一种位操作方式。
设置位操作方式的函数为setwritemode
, 函数声明:
void setwritemode(int mode, PIMAGE pimg = NULL);
其中的mode就是二元光栅操作码, pimg是要设置的图像,为NULL时就是指的是窗口,当在pimg的图像上绘图时,就是根据二元光栅码表示的位操作模式来改变颜色。
EGE支持全部的16种操作码, 罗列如下
R2_BLACK 绘制出的像素颜色 = 黑色
R2_COPYPEN 绘制出的像素颜色 = 当前颜色(默认)
R2_MASKNOTPEN 绘制出的像素颜色 = 原有颜色 AND (NOT 当前颜色)
R2_MASKPEN 绘制出的像素颜色 = 原有颜色 AND 当前颜色
R2_MASKPENNOT 绘制出的像素颜色 = (NOT 原有颜色) AND 当前颜色
R2_MERGENOTPEN 绘制出的像素颜色 = 原有颜色 OR (NOT 当前颜色)
R2_MERGEPEN 绘制出的像素颜色 = 原有颜色 OR 当前颜色
R2_MERGEPENNOT 绘制出的像素颜色 = (NOT 原有颜色) OR 当前颜色
R2_NOP 绘制出的像素颜色 = 原有颜色
R2_NOT 绘制出的像素颜色 = NOT 原有颜色
R2_NOTCOPYPEN 绘制出的像素颜色 = NOT 当前颜色
R2_NOTMASKPEN 绘制出的像素颜色 = NOT (原有颜色 AND 当前颜色)
R2_NOTMERGEPEN 绘制出的像素颜色 = NOT (原有颜色 OR 当前颜色)
R2_NOTXORPEN 绘制出的像素颜色 = NOT (原有颜色 XOR 当前颜色)
R2_WHITE 绘制出的像素颜色 = 白色
R2_XORPEN 绘制出的像素颜色 = 原有颜色 XOR 当前颜色
所以二元操作码中的二元指的就是图像原来的颜色和当前颜色。
"当前颜色"是指通过 setcolor() 或 setfillcolor() 设置的用于当前绘制或填充的颜色。当我们在上面绘制时,就根据这两个颜色和位操作模式计算得出最终的颜色。 后面还有个三元光栅操作码,是用于图像处理的。
- 可以看到,默认的二元光栅操作码是 R2_COPYPEN, 就是直接用当前颜色来作为最终颜色,这也是我们熟悉的一种方式,也有不管两个是什么颜色,画上去都是黑色,或者都是白色。
- 更多的是对两个颜色进行 与、或、非、取反、异或 的位操作,例如,R2_MERGEPEN, 就是将两个颜色进行或运算。红色是0xFF0000, 蓝色是0x0000FF, 或运算之后,得到紫色0xFF00FF.
下面做个二元光栅操作码的示例:
#include <graphics.h>
int main()
{
initgraph(640, 320, 0);
setbkcolor(0x00FF00);
setcolor(0xFF0000);
setfillcolor(0X0000FF);
fillellipse(160, 160, 160, 160);
//颜色做位或
setwritemode(R2_MERGEPEN);
fillellipse(480, 160, 160, 160);
//改回原来的模式
setwritemode(R2_COPYPEN);
getch();
closegraph();
return 0;
}
可以看到修改位操作模式, R2_MERGEPEN, 代表做位或操作,就得到了一个不同的颜色。
(3) 三元光栅操作码
三元光栅操作码,是设置两个图像绘图时对像素的一种位操作方式。两个图像图像对应点上的两个像素颜色加上当前填充颜色一共三个,所以是三元。
三元光栅操作码其实是在绘制图像时设置的,来看看putimage() 的声明:
void EGEAPI putimage(int dstX, int dstY, const PIMAGE pSrcImg, DWORD dwRop = SRCCOPY);
-
最后面有个 DWORD 类型的参数 dwRop, 那个就是三元光栅操作码,默认是SRCCOPY,也就是直接用源图像覆盖原有图像。
-
三元光栅操作码有非常多,这里就不多说,可以查看官网说明
三元光栅操作码 http://xege.org/manual/api/img/rop.htm -
三元光栅操作码太多,所以用逆波兰表达式来表示操作名,也就是后缀表达式,平时我们使用的是中缀表达式,例如:中缀表达式的1 + 2,对应的后缀表达式就是 1 2 +, 把运算符放在后面,再如 1 + 2 * 3 ==> 1 + (2 * 3)⇒ 1 + (2 3 *) ⇒ 1 2 3 * +, 就是这么转换来的,看原来是怎么计算的,把那部分的运算符放在后面作为结果,当作一个整体再继续计算, 上面的那个先算 2 * 3, 本来应该得6,但是我们是要转成后缀表达式,所以结果是 (2 3 *), 把 (2 3 *)作为一个整体 在计算 1 + (2 3 *),那自然就是 1 (2 3 *) +了,因为后缀表达式运算符顺序就代表计算顺序,不需要括号来说明运算顺序,所以得到结果是 1 2 3 * +,按照这个我们可以根据我们需要的运算, 转成后缀表达式,再去资料里查对应的码值。
-
开始计算后缀表达式了,用一些大写字母代表颜色
-
用一些小写字母代表运算
觉得好我们要的操作后,转换成后缀表达式,到红色框圈出的一栏找, 找到后看蓝色一栏对应的码值是什么,是十六进制表示的,就可以拿来用了,用的时候别忘了 前面加个0x .右边紫色圈出的地方是一部分已经定义好的宏,记住后下次直接输入那个名称就行。
后缀表达式示例,假如我们要对源图像颜色取反,再和目标图像颜色位与操作, 那就是 D and (not S), 转成后缀,那就是D (S not) and, 按照上面表示那就是 D S n a, 所以在上面找到是在第22号那一列, 对应值是 00220326, 那么就是 0x00220326, 设置如下:
putimage(0, 0, pimg, 0x00220326);
如果在右边找到名字,可以直接使用名字,但这个没有。
三元光栅操作符的例子,抠图:
- 先将一张图片准备好,然后把一张掩膜图准备好,这里我们的图像和掩膜要一样大的(我这里是320x320) 掩膜就是把想要的部分填充上纯白色 0xFFFFFF, 把不想要的部分填充成纯黑 0x000000. 这个可以先创建一个空图像,设置好颜色后,在上面填充纯白,背景是纯黑。我们要在上面画四个圆,因为普通绘图函数的填充函数是带边框的,所以不仅填充颜色要设置成纯白,前景颜色也要纯白,背景颜色一开始其实就是纯黑,不设置也行。
PIMAGE mask = newimage(320, 320);
setbkcolor(BLACK, mask);
//颜色都是纯白
setcolor(0XFFFFFF, mask);
setfillcolor(0xFFFFFF, mask);
fillellipse(100, 160, 100,100, mask);
fillellipse(220, 160, 100, 100, mask);
fillellipse(160, 220, 100, 100, mask);
fillellipse(160, 100, 100, 100, mask);
- 然后就是操作了,接下来是要把绘制的区域中间扣个洞(就是把我们要画的地方涂上纯黑),比如,原来窗口是黄色的,那就把中间弄黑, 保留掩膜的黑色部分, 操作是 屏幕颜色 and (not 源图像颜色), 即刚才说的 DSna
putimage(0, 0, mask, 0x00220326);
- 然后我们再把我们要扣的图像留下中间部分, 操作是 目标图像 位与 源图像, 即 DSa, 名称是 SRCAND, 为了保留原来的图像,我们还是另外创建一个图像来保存吧。
PIMAGE temp = newimage(320, 320);
//先把原图复制到临时图像上
putimage(temp, 0, 0, pimg);
//做与操作
putimage(temp, 0, 0, mask, SRCAND);
这样我们就把中间的保留了,外面都变成了纯黑。因为纯黑就是0x000000, 所以接下来做或操作时,就相当于没有。
- 再然后将我们抠出来的图片与目标区域进行位或操作, 或操作三元光栅操作码名称是SRCPAINT,
putimage(0, 0, temp, SRCPAINT);
这样就成功了,别忘了,图像不用后要记得使用delimage()
delimage(temp);
delimage(mask);
delimage(pimg);
代码如下:
因为不知怎么回事,我测试的缩放putimage(),三元操作码失效,所以这个函数没写成缩放型
#include <graphics.h>
void cutoutImage(PIMAGE dest, int x, int y, int w, int h, PIMAGE src, PIMAGE mask);
//使用之前编写的从文件缩放加载图像函数
int getimage_zoom(PIMAGE& pDstImg, LPCSTR pImgFile, int zoomWidth, int zoomHeight);
int main()
{
initgraph(320, 320, 0);
setbkcolor(YELLOW);
setcolor(0xFF0000);
setfillcolor(0X0000FF);
int width = 320, height = 320;
PIMAGE pimg = newimage();
getimage_zoom(pimg, "girl.jpg", width, height);
PIMAGE mask = newimage(width, height);
setbkcolor(BLACK, mask);
//颜色都是纯白
setcolor(0XFFFFFF, mask);
setfillcolor(0xFFFFFF, mask);
fillellipse(100, 160, 100,100, mask);
fillellipse(220, 160, 100, 100, mask);
fillellipse(160, 220, 100, 100, mask);
fillellipse(160, 100, 100, 100, mask);
cutoutImage(NULL, 0, 0, pimg, mask);
delimage(mask);
delimage(pimg);
getch();
closegraph();
return 0;
}
//原图src, 和掩膜mask大小要一样, x, y, w, h, 为在deset上绘制的区域
//因为不知怎么回事,我测试的缩放putimage(),三元操作码失效,所以这个函数没写成缩放型
void cutoutImage(PIMAGE dest, int x, int y, PIMAGE src, PIMAGE mask)
{
int width = getwidth(src), height = getheight(src);
putimage(dest, 0, 0, mask, 0x00220326);
PIMAGE temp = newimage(width, height);
putimage(temp, 0, 0, src);
putimage(temp, 0, 0, mask, SRCAND);
putimage(dest, 0, 0, temp, SRCPAINT);
delimage(temp);
}
EGE专栏:EGE专栏
最后
以上就是安详白云为你收集整理的EGE基础:光栅操作篇光栅操作的全部内容,希望文章能够帮你解决EGE基础:光栅操作篇光栅操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复