位图的光栅操作及ROP码解析

本文详细介绍了Windows图形编程中使用的二元、三元和四元光栅操作码(ROP2、ROP3、ROP4),包括它们的编码方式、操作原理以及如何在GDI函数中应用。

From: http://blog.youkuaiyun.com/snowstart/archive/2005/03/22/326715.aspx

 

(SnowStart于2005年3月22日)

位图是windows 图形编程中非常重要的一个方面。在进行普通的位图操作中,如GDI 函数BitBltStretchBlt , StretchDIBits ,都会用到一个光栅操作码,即ROP 码,像SRCCOPYPATPAINTSRCAND 等,由于最近在开发图形驱动,涉及了许多的ROP2ROP3ROP4 的操作,对ROP 码进行了深入的研究,以下详细介绍之以和大家分享。

二元光栅操作: 我们在使用GDI 画线和填充区域时,GDI 使用二元光栅操作码ROP2 组合画笔或画刷像素和目标像素以得到新的目标像素。如SetROP2 函数和GetROP2 函数支持16 种二元光栅操作,如:( 具体见wingdi.h)

#define R2_NOT              6   // Dn

#define R2_XORPEN           7   // DPx

三元光栅操作: 对于图像有同样的光栅操作用于生成各种特殊效果,我们要处理的有三种像素,源图像像素、目标图像像素和画刷像素(模板图像像素),称之为三元光栅操作,使用的是ROP3 ,如:( 更多的参见wingdi.h)

#define SRCPAINT (DWORD)0x00EE0086 // dest = source OR dest          

#define SRCAND   (DWORD)0x008800C6 // dest = source AND dest         

四元光栅操作: 是混合了源图像像素,目标图像像素和模板画刷像素外,又增加了一个掩码位图,用到4 个变量形成了四元光栅操作,相应的为ROP4 ,GDI 函数中MaskBlt 函数使用的是ROP4 ,也是唯一接受四元光栅操作的API 函数

光栅操作的编码:

一个字节可以编码256 种光栅操作,假定P 为画笔或画刷的位,S 为源图像的位,D 为目标图像的位。如果操作的结果和P 一样,编码为0xF0 ,如果操作的结果和S 一样,编码为0xCC ,如果操作的结果和D 一样,编码为0xAA

Const BYTE rop_P  =0xF0; // 1 1 1 1 0 0 0 0

Const BYTE rop_S  =0xCC; // 1 1 0 0 1 1 0 0

Const BYTE rop_D  =0xAA; // 1 0 1 0 1 0 1 0

所有其他的光栅操作可以基于这三个常量的布尔操作,如定义源图像S 和画刷P 的逻辑与AND ,计算rop_S&rop_P=0xC0 即可

GDI 中光栅操作实际上使用32 位的DWORD 编码的,而不是简单的0-255 单个字节编码,双字节中高8 位表示上述的256 种单字节光栅操作编码的一种,低字节16 位定义了光栅操作的运算式的编码。

低字节16 位被分成两部分:操作符和操作数,具体如下:

低字节高11 位表示操作符

两位表示一个逻辑操作(00-NOT01-XOR10-OR11-AND ),共5 种逻辑操作,剩下一位表示最后的操作是否为NOT 操作

低字节低5 位表示操作数

3 位指定分析串,后2 位指定分析串的偏移(8 种分析串如下)

000:SPDDDDDD

001:SPDSPDSP

010:SDPSDPSD

011:DDDDDDDD

100:DDDDDDDD

101:S+SP-DSS

110:S+SP-PDS

111:S+SD-PDS

分析串中的“+ ”和“- ”被称为特殊操作数。在256 种光栅操作中有16 种复杂的操作无法用单个累加器的机制表示,需要临时存储操作数,“+ ”表示压入堆栈,“- ”表示出栈,且是成对出现的,

注意: 分析串读时要从后往前读,移位时也是往前移的

 

Op5

Op4

Op3

Op2

Op1

Not

分析串

偏移

1. 编码光栅运算式(光栅编码的低16 位)

举例说明:如光栅操作编码为0x00E20746 ,低位字节为0x0746 ,二进制为0000 0111 0100 0110

显然Op5=NOT,Op4=NOT,Op3=XOR,Op2=AND,Op1=XOR ,而Not=0 表示不需要额外的NOT

分析串=001 移位=2 ,实际串为SPDSPDSP 左移位2 个符号即DSPDSPSPOp1-Op3 是二元操作符,Op4-Op5 是一元操作符,所以只需4 个操作数,这样分析串被截断为DSPD ,光栅操作的后缀表示为DSPDxaxnm 简化为DSPDxaxGDI 定义的D^(S&(P^D))) 是一样的

    16 位的这种编码,实际上是早期时为了节省内存和汇编代码量而设计的编码,新的GDI 实现不再使用这种现在看来较慢的机制,因此通常情况下,丢掉三元光栅操作的低位字是安全的,但是很难说是否会有某个图形设备驱动去检查32 位光栅操作码的每一位匹配与否,为了安全起见,当用到新的光栅操作码时,应该检查和使用整个光栅操作编码。

    三元光栅操作码只使用32 位光栅码的24 位。光栅操作码的高8 位通常全为位0Windows2000 及以上版本,引入了两个新的标志用于控制位图传输操作CAPTUREBLTNOMIRRORBITMAP

    NOMIRRORBITMAP 标志(0x80000000 )防止位图被垂直或水平的镜像,因为源和目标矩形的轴的方向或其他方面有所不同

    CAPTUREBLT 标志(0x40000000 )用于重叠窗口操作。

 

四元光栅编码:

四元光栅操作中的第四个参与者是一个单色屏蔽位图,四元光栅代码由一个前景三元光栅代码和一个背景三元光栅代码组成。掩码像素为1 时,使用前景光栅操作代码,掩码像素为0 时,使用背景光栅操作代码,GDI 定义了宏MAKEROP4 用于将224 位的三元光栅操作码组合成32 位的四元光栅操作码ROP4 。定义如下:

#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))

背景ROP 索引(8)

前景ROP 索引(8)

前景ROP 公式的编码(ROP 的低16)

该宏取背景光栅操作码的高8 位光栅操作索引,左移8 位,然后和24 位的前景光栅操作代码组成32 位的ROP4

注意掩码在四元光栅操作中的地位和其他三个并不平等,它被限制在两个值: 1 (白色)和 0 (黑色)。不能是彩色位图,因为彩色位图可以和画刷、源及目标彩色位图组合。提供四元光栅操作的主要目的是提供简单和有效地实现透明位图的显示方法。

### 三元光栅操作编程实现方法 #### 定义与背景 三元光栅操作(Ternary Raster Operations),简称ROP3,在图形处理中用于定义源像素(Src)、目标像素(Dest)以及图案(Pattern)之间的组合方式。这些操作广泛应用于Windows GDI函数,如BitBlt和PatBlt。 对于32位的光栅操作而言,实际上只有低24位被利用来表示不同的光栅操作模式[^2]。这意味着高位8位通常设置为零,尽管如此,在某些特定场景下仍需关注全部32位以确保兼容性和安全性[^1]。 #### 实现逻辑 具体来说,三元光栅操作遵循如下公式: \[ \text{Dest} = ((\text{Src} \oplus \text{Pattern}) \land (\text{Dest} \oplus \text{Src})) \oplus \text{Src} \] 其中`⊕`代表按位异或(XOR),`\land`则指代按位与(AND)[^4]。此表达式描述了如何通过给定的目标图像数据(`Dest`)、源图像数据(`Src`)及可能存在的填充样式(`Pattern`)计算最终显示效果。 #### 使用示例 下面给出一段C++代片段展示怎样应用三元光栅操作进行简单的矩形绘制: ```cpp #include <graphics.h> int main(){ initgraph(800,600); setbkcolor(WHITE);cleardevice(); RECT rect={200,0,600,300}; solidrectangle(rect.left,rect.top,rect.right,rect.bottom); const char* str="你好"; drawtext(str,&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE); // 应用三元光栅操作 SetTextColor(hdc,COLORREF(0xFF00FF)); BitBlt(hdc, 50, 50, 100, 100, hdc, 0, 0, DSTINVERT); getchar();closegraph(); return 0; } ``` 上述例子中的`DSTINVERT`即是一个典型的三元光栅操作常量,它会反转目的地颜色而不改变其他属性。注意这里假设存在有效的设备上下文句柄`hdc`供调用者传递给API函数。 #### 注意事项 由于现代操作系统版本已经引入了一些新特性(比如CAPTUREBLT和NOMIRRORBITMAP),所以在编写涉及屏幕捕捉或者窗口映射的应用程序时应当特别留意所选的操作是否支持此类扩展标志。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值