实现透明位图

  Microsoft   网络开发技术小组   
    
  摘要   
    
  这篇文章讨论了在   Microsoft   Windows   图形环境中用位图达到透明和屏蔽效果的几种方法,包括通过仿真和使用特殊的驱动器功能。包含其中的一个小样本应用程序   TRANSBLT   详细阐明了这篇文章讨论的大多数方法。   
    
  介绍   
    
  使用透明(TRANSPARENT)背景模式(用SetBrMode函数设置),一个应用程序就可以用透明文本,透明风格的线条和透明形状的刷子。令人悲伤的是,Microsoft   Windows图形环境并没有为透明位图提供一个简单的接口。(是的,它提供了,但是并没有对它进行广泛的支持,就象在下文中“容易的位图透明性”中提到的)。幸运的是,通过使用一个屏蔽位图和几次调用具有经过仔细选择的光栅操作的BitBlt,一个应用出现可以模仿这种效果。   
    
  到底什么是透明的位图呢?它是一个位图,通过它目的文件的一部分仍然可以看得见。一个简单的例子就是类似于控制面板图象等基于Windows的图象。控制面板图象本身基本上是个长方形。当它被最小化时,通过这个长方形图象位图的部分可以看见桌面。从理想化的角度讲,这图象位图被设计成长方形其中有些象素被指定为透明的以至于当位图被使用,那些象素就不会挡住目的文件。透明的位图可以通过移动的、非矩形图象变得更为有趣。下面将要描述得模仿方式可以用来完成这些透明效果。   
    
  符号   
    
  这篇文章使用透明和不透明这两个词来描绘源位图中得象素。透明象素是那些不会影响目标文件的象素。不透明象素是那些画在目标文件上并取代该位置上原来的东西的象素。   
    
  白色和黑色分别被假定为全1和全0的值。这在所有已知的Windows显示驱动器上都是正确的,包括调色板设备。   
    
  基本的操作涉及到从源文件到目标文件   的块传递,额外的与单色屏蔽有关的块传递也是需要的。源文件和目标文件由他们的设备上下文代表hdcSrc和hdcDest即可以是位图也可以是设备表面本身。有hdcMask提到的屏蔽被假定为被选进兼容DC的单色位图。   
    
  背景概念   
    
  在讨论实际的透明模仿之前,我们应该定义和复习一些基本图形概念。   
    
  光栅操作   
    
  BitBlt函数的最后一个参数指定了一个光栅操作(ROP),它明确定义了如何将源文件、目标文件和模式(由现在选出的刷子画笔定义)的位组合去形成一个目标文件。因为一个位图只是一个位值的集合,光栅操作(ROP)只是一个在位上操作的布尔等式。相应使用的设备,位图中的代表不同的事物。   
    
    
  在多色设备上,每个象素由一个位集合代表,他们要么形成一个指向颜色的索引,要么直接代表一种颜色。     
    
    
  在单色设备上,每个象素由一个位来代表,0表示黑色并且1代表白色。     
    
  对于所有的设备类型,光栅操作(ROP)只简单地在位展示上进行而不考虑他们的实际意义。   
    
  有一个技巧,就是用一种有意义的方式合并位。在Windows3.1版软件开发包中的程序员参考,第三页:消息、结构和宏中的附录A列举了256种可能的三重光栅操作(ROP)。光栅操作(ROP)提供了多种合并位图数据的方法,而且你经常可以使用不只一种的方法得到你想要的效果。这篇文章只讨论其中的四种。   
    
  预先定义的名字   
    布尔操作   
    透明仿真中的用途   
      
  SRCCOPY   
    src   
    直接将源拷贝到目的   
      
  SRCAND   
    src   AND   dest   
    将目标文件中对应于源文件黑色区域的部分变黑,将对应于白色区域的部分留着不动   
      
  SRCINVERT   
    src   XOR   dest   
    将源插入到目标。二次使用时,将目标恢复到它原来的状态。在某种条件下可以代替SRCPAINT   操作   
      
  SRCPAINT   
    src   OR   dest   
    将源文件中的非白色区域刷到目标文件中。源中的黑色区域不转换到目标中。   
      
    
  一些打印机不支持某些光栅操作,尤其是那些涉及到目标文件的光栅操作。因为这一点,这篇文章中描写的技巧特地以显示为目的而且有可能在某些打印机设备上不能工作,比如PostScript打印机。   
    
  透明屏蔽   
    
  在这篇文章中,“面具”一词不是指蝙蝠侠戴在脸上的东西。它指的是一个限制其他位图可见部分的一个位图。“面具”有两个控件:不透明部分(黑色),在这一部分源位图是可见的和透明部分(黑色),在这一部分目标文件保持未动。因为“面具”只由两种颜色   组成,所以它可以很方便地由一种单色位图代表,虽然它可以是一个黑白色位图   。就象在下面的“真正的屏蔽方法”和“使源文件变黑的方法”中要讨论的,数据块传递屏蔽被用作多数数据块传递处理的一部分,它的源位图的最终透明数据块传递设置目标文件。TRANSBLT样本应用程序使用带设置为1的透明色素和设置为0的非透明色素的单色屏蔽。如果需要应用程序可以转换这两个值,并将在这一部分中的一些将要描述的单色到彩色的转换中进行补充。   
    
  除了为透明性提供方便以外,屏蔽在模仿复杂的剪裁操作时也很有用。这种剪裁操作不能被有效地在使用区域中处理。一个被屏蔽的数据块传递的网状效应将裁减掉源位图的一部分。比如:要只显示位图中的一个圆形区域,可创建一个象源文件一样大小的屏蔽并且在相应的区域画一个透明位的圆形。执行这一被屏蔽的数据块传递的机制将在后面的“真正的屏蔽方法”和“使源文件变黑的方法”中描述。   
    
  单色到   彩色的转换   
    
  透明仿真也牵涉到基于Windows的单色位图到彩色位图的转换机制。反之亦然。基于Windows的文本前景色和背景色的概念被用于在两种格式之间进行转换。在对一彩色目标文件进行位传递操作的时候,一个单色的源位图(和/或当可应用时一个画刷)在实际的光栅操作(ROP)中在这一位上实现之前被转换成背景色。相反的,当目标文件是单色时,Windows   把彩色源转换成单色。在这种情况下,彩色位图中所有和背景色一致的象素都变成1,其他的象素都被转换成0。因为下面所要涉及到的例子都使用单色屏蔽,所以对一个应用程序而言,在执行块操作之前正确地设置背景色和前景色是非常重要的。   
    
  性能和屏幕闪烁   
    
  增强的位图操作变得比较慢的原因完全是因为被影响的位的数目。而且当直接对屏幕进行操作导致闪烁的事实又使得这一点更为严重。当被影响的区域增大尺寸时,事情只会变得更加糟糕,虽然没有什么办法可以魔术般的提高速度,但是可以通过使用阴影位图来删除可见的闪烁   。首先,应用程序把将要被影响的屏幕区域复制到存储位图,然后应用程序在阴影位图而不是在屏幕上实现位操作(例如,透明效果   )。最后,阴影又被复制到屏幕上。结果只有一个块传递影响屏幕,所以闪烁没有了。很明显,两个额外的块操作引起了速度减慢(虽然在有些设备上存储器块传递能比已经访问了屏幕的块传递要块一些),但是依靠位图的尺寸和惊奇的操作,操作可能会因为闪烁消失而让人感觉到快了一些。事物也因为没有让人混乱的闪烁而变得更为清楚。阴影操作是否恰当取决于应用程序特定的需要。   
    
  真正的屏蔽块传递并不需要对即将有用的源位图的某部分做任何的修改。被屏蔽的块传递涉及到了步操作并且屏蔽把所有透明的元素都设置为1,所以不透明的元素设置为0。下面是有关基本代码:   
    
  //   Set   up   destination   for   monochrome   blt   (only   needed   for   monochrome     
  //   mask).   These   are   the   default   values   and   may   not   need   to   be     
  //   changed.   They   should   also   be   restored.   
  SetBkColor(hdcDest,   RGB(255,   255,   255));             //   1s   -->   0xFFFFFF   
  SetTextColor(hdcDest,   RGB(0,   0,   0));                     //   0s   -->   0x000000   
    
  //   Do   the   real   work.   
  BitBlt(hdcDest,   x,   y,   dx,   dy,   hdcSrc,   x0,   y0,   SRCINVERT);   
  BitBlt(hdcDest,   x,   y,   dx,   dy,   hdcMask,   0,   0,   SRCAND);   
  BitBlt(hdcDest,   x,   y,   dx,   dy,   hdcSrc,   x0,   y0,   SRCINVERT);   
  被屏蔽的块传递处理中的三步操作如下:   
    
    
  第一步(带SRCINVERT的位块传递)将源位图异或到目标文件。这看起来有点意思,但第二步异或有把目标文件恢复成原始状态的效果。     
    
    
  第二步(带SRCAND的位块传递)是一个屏蔽操作。当屏蔽与目标文件相与,所有的透明象素都不会改变目标文件的象素,而不透明象素则直接把目标文件变为黑。现在目标文件中有了一个源文件的不透明部分给勾勒出来的图象,而它自身在透明部分中的异或图象。     
    
    
  第三步(带SRCINVERT的位块传递)与源文件异或送到目标文件。透明象素被恢复成源状态(两步异或就能做到),不透明象素则季节从源文件上复制。     
    
  不幸的是,当三个步骤执行时,目标文件确实有一阵看起来相当难看,而直接对屏幕执行三次块传递又会引起屏幕闪烁。   
    
  使源文件变黑的方法   
    
  只要在创建源位图时稍稍计划一下,透明性块传递就可以减少到只有两个调用。屏幕仍和上面的例子一样保持不变,但是源文件则必须在屏蔽的块传递代码看起来象这样:   
    
  //   Set   up   destination   for   monochrome   blt.   These   are   the   default     
  //   values   and   may   not   need   to   be   changed.   They   should   also   be     
  //   restored.   
  SetBkColor(hdcDest,   RGB(255,   255,   255));         //   1s   -->   0xFFFFFF   
  SetTextColor(hdcDest,   RGB(0,   0,   0));                 //   0s   -->   0x000000   
    
  //   Do   the   real   work.   
  BitBlt(hdcDest,   x,   y,   dx,   dy,   hdcMask,   0,   0,   SRCAND);   
  BitBlt(hdcDest,   x,   y,   dx,   dy,   hdcSrc,   x0,   y0,   SRCPAINT);   
  屏蔽第二次用来使不透明的象素变黑而保持剩下的不变。然后源文件再这个的向上与之相或,并在目标文件现在为黑的部分上画画。因为源文件在想要透明的地方只有黑象素,或操作使得目标文件在那些透明区域保持不变。注意SRCINVERT   POP可以在第二个块传递调用时代替SRCPAINT并取得多样的效果。源屏蔽设置删除了的可能性,这是XOR不同于OR的唯一情形。   
    
  用这种方法屏幕闪烁变得不再那么引人注目,而且一旦源文件已经再正确的位置被设置为黑,透明性看起来非常好。Windows也使用这种机制在屏幕上显示图象。图标被分成两部分存储在.ICO文件中,这两部分“XOR   MASK”和位图本身。因为位图和图标一样小,所以实现透明性非常顺利。   
    
  位图透明性   
    
  位图透明性通常指的是一种处理,这种处理取出一幅位图,并使位图中的一种颜色变为透明,从而当位图被块传递到屏幕时,目标文件可以通

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值