背景技术
一般显示设备用来向观察人再现图像。向观察人有效地再现图像对于电视和许多种计算技术都是很基础的。因此,显示设备与电视和许多计算系统紧密相关。
图像是使用分布在一台显示设备上的网格图形中分布的成千个像素来向观察者再现的。每个像素的色彩和/或亮度值都可以调整,以形成所需要的图像。在典型显示设备中,用户感知的从单个像素发出的色彩其实是由多个移位的色彩分量来表示的。举例来说,在RGB显示设备中,有一个光源专门发出红色光,另一个单独的光源专门发出绿色,还有一个单独的光源则专门发出蓝色。这些光源在此称为像素的红、绿、蓝色彩分量。
对任何特定的像素而言,这些色彩分量是在空间上偏移的。但是,这种空间偏移足够的小,使一般的用户无法分辨一个像素中单独的色彩分量。相反,来自这些色彩分量的光混合在一起,使该像素被感知成只有单种颜色。这单种颜色可以通过调整该像素的红、绿、蓝色彩分量的亮度来调整,这样该像素就可以获得很宽范围的被感知的颜色。通过使红、绿、蓝色彩分量的亮度最大,可以获得白色,而通过使红、绿、蓝色彩分量的亮度最小,可以获得黑色。
典型的电视显示屏和计算机监视器依赖于每个具有多个空间移位的可寻址分量的像素,无论这些分量是红、绿、蓝色彩分量,还是其它分量。液晶显示器(LCD)就是利用多个不同可寻址元素(在此称为像素的子元素或像素的子分量)来表示一幅所显示图像的每个像素的显示设备的例子。举例来说,图1说明了一种传统的便携计算机100,包含外壳101、盘驱动器102、键盘103和显示屏104。该显示屏104就可以是例如一个LCD显示屏。
一般情况下,彩色LCD显示屏上的每个像素是由单一像素元素来表示的,该像素元素通常由三个非方形(non-square)的像素子分量组成,如一个红色像素子分量、一个绿色像素子分量和一个蓝色像素子分量。这样,一组RGB像素子分量就一起组成了单一的像素元素。传统的LCD显示屏由一般排列成沿着显示屏的栅条的一系列RGB像素组成。这些RGB栅条一般从一个方向跨过整个显示屏的长度。所形成的RGB栅条有时候被称为“RGB条纹”。用于计算机应用的普通LCD监视器(其宽度大于高度)倾向于有垂直方向的RGB栅条。
图2A说明了一种已知的由可以在显示屏104上表示的多行(R1-R12)与多列(C1-C16)组成的LCD屏200。每个行/列的交叉都形成了表示一个像素元素的方块(或一个高和宽几乎一样的矩形)。图2B详细说明了该已知显示屏200的左上部分。
请注意在图2B中每个像素元素(如像素元素[R2,C1])是如何由三个不同子分量(一个红色子分量206、一个绿色子分量207和一个蓝色子分量208)组成的。每个已知的像素子分量206、207和208都大约是一个像素的三分之一宽,而在高度上与一个像素的高度相等。如在图2A和图2B中所说明的那样,RGB像素子分量的一种已知排列形成了看上去顺着显示屏200的垂直彩色栅条。因此,以在图2A和图2B中所说明的已知方式的1/3宽彩色子分量206、207和208的排列有时候称为“垂直栅条”。尽管在图2A中为说明目的仅显示了12行和16列,但普遍的列×行比例包括如640×480、800×600和1024×768。
除垂直栅条以外,LCD还以几种另外的图案排列的像素子分量来制造,这些图案包括如在摄像机探视镜中很普遍的之字形和三角形图案,或水平的栅条,在水平情况,每个RGB像素子分量具有三分之-整个像素的高度,具有和像素一样的宽度。可以用这样的像素子分量排列来使用本发明的特征。但是,由于RGB垂直栅条的配置更为普遍,所以本发明的实施例都将按使用RGB垂直栅条化的显示屏来讲解。
传统上,一个像素元素的每组像素子分量都是作为一个单独的像素单元来对待的。因此,在已知的系统中,一个像素元素的所有像素子分量的光亮度值都是从一幅图像的同一部分产生的。作为例子,请考虑由在图2C中所说明的栅格220所表示的图像。在图2C中,每个方块都表示由单一像素元素表示的图像的一个区域,该像素元素包括栅格220相应方块的红、绿、蓝像素子分量。
在图2C中,用一个阴影圆来表示产生光亮度值的单个图像样本。请注意在已知系统中怎样用图像220的单个样本222来产生每个红、绿、蓝像素子分量232、233、234的光亮度值。这样,在已知系统中,RGB像素子分量一般是作为一组来产生对应于所表示单个图像样本的单个色彩像素。
来自每个像素子分量组的光有效地叠加到一起,以产生单种色彩的效果,该单种色彩的色度、饱和度和强度依赖于三个像素子分量中每个分量的值。也就是,举例来说,每个像素子分量都具有介于0和255之间的某个可能亮度。如果所有三个像素子分量的亮度都是255,则眼睛感觉该像素为白色。但如果所有三个像素子分量的亮度都是0,则眼睛感觉该像素为黑色。通过变化各个像素子分量的强度,就可能产生介于这两个极端间的上百万种颜色。
如此,单一样本就映射成三个像素子分量,每个分量在宽度上各是一个像素的三分之一,左边和右边像素子分量所产生的空间位移是由于这些元素的中心偏离样本中心1/3。作为例子,请考虑,要表示的一幅图像是一个红色立方体,其绿色和蓝色分量为零。该样本与绿色图像子分量间位移的结果是,当在图2A中所说明的LCD显示屏上显示时,该立方体在显示屏上看到的位置从其实际位置向左平移了三分之一个像素。类似地,一个蓝色立方体将显示成向右位移三分之一个像素。因此,传统的用于LCD屏幕的成像技术可能导致不希望的图像位移误差。
文本字符代表了一种在分辨率为每英寸72或96点(像素)(dpi)的典型平面显示屏上特别难以准确显示的图像类型。这样的显示分辨率远远低于大多数打印机所支持的600dpi,以及在大多数商业印刷的文本如书籍和杂志中所使用的更高的分辨率。因此,在图像分辨率受像素分辨率限制时,较小的可视对象如文本字符就可能显示得很粗糙。
确实,传统的学识认为图像分辨率必定受像素分辨率的限制。然而,在2001年2月13日颁布给William Hill等人的名为“用于显示如文本之类图像的方法和设备”的美国专利申请序列号US6,188,385B1(此后称为“Hill等的专利”,在此完整附入以作参考)中描述了一种改善像素子分量分辨率的技术。结合了在Hill等的专利中所描述的至少某些技术的显示技术通常称为CLEARTYPE,该术语是Microsoft Corporation的经注册商标。
Hill等的专利描述了一种将每个像素子分量作为独立的光亮度源处理的技术。这与将给定像素的RGB像素子分量组作为单一光亮度源处理的传统技术形成对照。
换句话说,Hill等的专利描述了用每个图像样本为单个像素子分量产生光亮度值。这与用单个图像样本为给定像素产生所有像素子分量的值的传统技术形成对照。这样,Hill等的专利所描述的技术使具有RGB垂直栅条的显示设备能具有比水平像素分辨率高至三倍的有效水平分辨率。
图3说明了一个可以用Hill等的专利所描述的技术,由计算机100实现在显示屏104上再现和光栅化文本图像的一般功能流程。为讨论起见,假设在计算机100上运行的某个应用程序通知该计算机的操作系统要在显示屏104上再现和光栅化具有特定字体和点大小的字母i。在标题“功能流程”下标注的图3的左边一列说明了用这一技术实现再现文本字符的一般功能。在标题“例子”下的图3的右边一列表示了在实现了左边的相应功能后字符i的状态。
该过程从描述字符外形的字符描述301开始。这可以使用矢量图形、直线、点和曲线来实现,从中可以得到该字符的一个高分辨率数字表示。一个典型的操作系统会有许多不同的字符描述,对应于每个字符的每个字体。元素311显示了对字母i的字符描述的可视化表示。除了文本信息外,操作系统还能够使用用于当前所显示的图像的背景色和布局信息,以及在再现中将运用于该文本字符的刷色和透明度信息。
有了这个字符和显示信息,操作就前进到缩放302,其中以方向和/或在每个像素元素中所包含的像素子分量的数量的某个函数来实现非方形的缩放。具体来说,将在字符描述中所描述的字符的垂直方向进行缩放来满足由应用程序所规定的点大小的高度要求。但是,水平方向会以比垂直方向大三倍的比例来缩放。这使后续的图像处理操作可以利用较高程度的水平分辨率,该分辨率可以通过在垂直栅条显示上将各个像素子分量作为独立的光亮度源来实现。
在最简单的情况下,水平方向的缩放是以与特定像素中的像素子分量的数量有关的相对比例来进行的。在RGB垂直栅条显示屏中,在任何给定像素中都有三个像素子分量。因此,在最简单的情况下,水平方向的缩放以垂直方向缩放比例的大约三倍的比例进行。这种缩放可以通过适当处理字符描述来进行。元素312显示了以缩放了的字符描述表示的字符状态。请注意在所说明的字符高度不变的情况下,字母i在缩放中以大约3的因子水平拉伸。
在缩放302后,操作前进到微调303。有时候用术语“网格拟合”来描述微调过程。微调包含了将缩放了的字符对齐到一个网格内,还包含扭曲图像的轮廓,使该图像更好地符合网格的形状。网格是作为显示设备的像素元素物理尺寸的一个函数来确定的。与无法在微调中考虑像素子分量边界的较早技术不同,微调303将像素子分量的边界作为字符可以且应当对齐的边界或字符轮廓应当调整到的边界来处理。
微调过程包含将字符已缩放了的表示以一种方式在网格内或像素和像素子分量边界内对齐,以便用可用的像素子分量来优化对字符的准确显示。在许多情况下,这包含将字符主干(stem)的左边缘与像素或像素子分量的左边界对齐,并将字符底部与像素或像素子分量的边界对齐。
实验结果显示,在垂直栅条的情况下,主干对齐使字符主干具有蓝色或绿色左边缘的字符一般比主干对齐成具有红色左边缘的字符更为清晰。因此,在微调要显示在具有垂直栅条的屏幕上的字符时,主干的蓝色或绿色左边缘比红色左边缘更为有利。
在微调303中,首先将已缩放的图像312放置在如网格布局313A所表示的一个网格图案上。该网格图案以从左到右标注为C1至C4的四列像素和从上到下标注为R1至R6的六行像素来表示。请注意,像素子分量间的边界以点划线来表示,除非那里也是像素间的边界。像素的边界则以实线来表示。注意每个像素子分量都有标题R、G或B,分别表示该列是代表红、绿还是蓝色。
在微调303中,将已缩放的字符i的左边缘与R/G像素子分量的边界对齐,这样所微调的字符312’的主干就具有绿色的左边缘,以提高清晰度。该字符的形状以及其在网格上的位置也都调整了。还进行了字符间距的调整。
一旦完成了微调303,操作就前进到扫描转换304,扫描转换包含将表示一个字符的缩放了的几何形状转换成一幅位图图像。传统的扫描转换操作将像素作为单独的单元对待,在其中已缩放图像的相应部分可以映射到这些单元中。然而,按照Hill等的专利,每个像素子分量被作为单独的光亮度分量来处理,已缩放图像的单独部分可以映射到这些光亮分量中。
参照图3,扫描转换操作产生位图图像314。请注意位图图像列C1-C4的每个像素子分量是如何从已缩放和微调的图像313B的相应列的不同段来确定的。这与传统技术形成对照,传统技术从一幅图像的单一部分产生一个给定像素的所有三个像素子分量值。还请注意位图图像314是如何由一个具有与红/绿像素边界对齐的左边缘的2/3像素宽的主干组成的。还请注意,使用了2/3像素宽度的点阵。将每个像素作为单一的光亮度分量来处理的传统文本成像技术会导致较不准确的图像,该图像具有全像素宽的主干和全像素大小的点阵。
一旦在扫描转换304中产生文本的位图表示(即位图图像314)后,就可以将其输出给显示适配器,或进一步处理以进行色彩处理操作和/或色彩调整,来增强图像品质。由于人眼对亮度边缘比对色彩(色度)边缘更为敏感,为图像再现目的而将RGB像素子分量作为独立的光亮元素来处理,会导致不希望的色彩边缘效应。例如,如果你从一个RGB组中去掉红色,就有可能导致青色(绿色和蓝色的叠加)的色彩边缘效应。
因此,可以将位图图像314提供给色彩处理305,在其中进行图像处理来确定该位图图像与所期望的刷颜色偏离多远。如果该位图图像的某些部分与所期望的刷颜色偏离大于一个预先选定量,就要对像素子分量亮度值进行调整,直至这些图像部分落入某个刷色与背景色间的可接受的平均值范围内。
而后将位图图像314通过一个混和操作运用于已存在的背景图像。具体来说,对于给定的像素,使红、绿、蓝色的颜色亮度由glyph.r、glyph.g和glyph.b来给出。字形(glyph)是一个表示关于所给定像素的该像素子分量的字符形状的术语。红、绿、蓝色彩分量的三值矢量由矢量glyph.rgb来表示。
由类似的矢量brush.rgb来表示刷或前景色彩分量。该画刷在每个色彩分量上的透明度的标量值由矢量brusha.rgb来表示。该像素的背景色由一个三值矢量dst.rgb来给出。为了将已刷色的字符混和到背景上,要运用以下的矢量公式(1):
DST.rgb=DST.rgb+(brush.rgb-dst.rgb)*glyph.rgb*brusha.rgb
(1)
在将每个像素子分量作为单独和不同的光亮度值处理的传统技术中,这一混和操作以及对字符的动画(如旋转和缩放)是在软件中进行的。执行混和对字符的动画的计算相当复杂。即使现代的计算系统,也会遇到将每个像素子分量作为独立光亮源处理的字符再现和动画的挑战。
因此,所希望的是以某种更高效的方式将每个像素子分量作为独立光亮源处理的字符再现和动画的系统和方法。
具体实施方式
本发明提供了用于加速字符再现和动画的方法、系统和计算机程序产品,将每个像素子分量作为不同光亮源来处理。将每个像素子分量作为不同光亮源来处理的字符,或者换句话说,其中每个像素子分量从一个样本产生的字符,在本描述和权利要求中将称为“面向子分量的字符”。面向子分量的字符与一般图像形成对照,在一般图像中用单个样本来产生一个特定像素的所有像素子分量值。
通过用单个图像样本来产生每个像素子分量,从而产生面向子分量的字符的一个位图表示。举例来说,这可以通过将字符的表示放大,将放大了的字符表示放置在一个网格上,而后根据在该网格位置上的放大了的字符的属性为每个网格位置分配一个亮度及可能的透明度值。而后,通过与一个进行最后的字符再现和动画的硬件图形单元对接,对字符进行再现。对前期以软件进行再现和动画而言,这种再现和动画的速度已经大大增加。下面将演示在用传统硬件图形单元动画面向子分量的字符时的实质性困难。用本发明的原理能够克服这些困难。
本发明范围内的实施例可以由一种专用或通用的计算设备组成,包括多种计算机硬件,下面将更详细地讨论。本发明范围内的实施例还包括承载或具有存储在其上的计算机可执行指令或数据结构的计算机可读取媒体。这样的计算机可读取媒体可以是可由通用或专用计算机存取的任何可用媒体。举例来说,但非限制,这样的计算机可读取媒体可以包含物理存储媒体,如RAM、ROM、EEPROM、CD-ROM或其它光盘存储器、磁盘存储器或其它磁盘存储器,或任何可用来承载或存储所期望的程序代码的媒体,所述程序代码为计算机可执行指令或数据结构形式,并可由通用或专用计算机存取。
当经过一个网络或其它通信连接(硬连线的、无线的或硬连线与无线的组合)向一台计算机传送或提供信息时,该计算机可以适当地将该连接看作一种计算机可读取媒体。因此,任何这样的连接都可以适当地称作计算机可读取媒体。上面这些组合也可以包括到计算机可读取媒体的范围内。举例而言,计算机可执行指令包含让通用计算机、专用计算机或专用处理设备执行某些功能或功能组的指令和数据。
尽管并不要求,但本发明仍将以由计算设备执行的计算机可执行指令(如程序模块)的一般上下文来描述。一般来说,程序模块包括执行特定任务或实现特定抽象数据类型的例行程序、程序、对象、组件、数据结构等等。用于执行此处披露的方法的步骤和动作的程序代码示例由计算机可执行指令、相关数据结构和程序模块来表示。
相关领域的技术人员可以了解,本发明可以在具有许多类型计算机系统配置的网络计算环境中实施,这些计算机系统配置包括个人计算机、手持设备、多处理器系统、基于微处理器或可编程的消费电子产品、网络PC、小型计算机、大型计算机,等等。本发明还可以在由通过一个通信网络联接(可通过硬连线链路、无线链路或硬连线与无线链路的组合)的本地和远端处理设备执行任务的分布计算环境中实施。在一个分布计算环境中,程序模块可以位于本地和远端的存储设备上。
参照图4,实现本发明的一个示例系统包括了计算机420形式的通用计算设备。计算机420包括处理单元421、系统存储器422和连接包括系统存储器422到处理单元421的多种系统部件的系统总线423。系统总线423可以是几种总线结构中的任何一种,包括存储器总线或存储器控制器、外设总线和使用多种总线结构中任何一种的局部总线。系统存储器包括只读存储器(ROM)424和随机存取存储器(RAM)425。在ROM 424中可以存储一个基本输入/输出系统(BIOS)426,它包含帮助在计算机420内元件间传送信息的基本例行程序。
计算机420还可以包括用于读写磁硬盘439的磁硬盘驱动器427、读写可移动磁盘429的磁盘驱动器428,和用于读写可移动光盘431(如CD-ROM)或其它光学媒体的光盘驱动器430。磁硬盘驱动器427、磁盘驱动器428和光盘驱动器430分别通过硬盘驱动器接口432、磁盘驱动器接口433和光学驱动器接口434连接到系统总线423。这些驱动器及与其相联系的计算机可读取媒体提供了对计算机可执行指令、数据结构、程序模块和用于计算机420的其它数据的非易失存储。尽管在此处所描述的示例性环境中使用的是磁硬盘439、可移动磁盘429和可移动光盘431,但其它种类的用于存储数据的计算机可读取媒体也可以使用,包括磁带、闪存卡、数字万用盘、Bernoulli盒带、RAM、ROM,等等。
程序代码由可以存储在硬盘439、磁盘429、光盘431、ROM 424或RAM 425中的一个或多个程序模块组成,包括一个操作系统435、一个或多个应用程序436、其它程序模块437和程序数据438。用户可以通过键盘440、指点设备442或其它输入设备(未示出),如话筒、游戏杆、游戏手柄、卫星天线、扫描仪或诸如此类,来将命令和信息输入进计算机420。这些以及其它的输入设备通常是通过连接系统总线423的串口端口446连接到处理单元421的。或者,输入设备也可以由其它接口来连接,如并口、游戏口或通用串行总线(USB)。监视器447或其它显示设备也通过接口(如视频适配器448)连接到系统总线423。除监视器以外,个人计算机一般还包括其它外围输出设备(未示出),如扬声器和打印机。
计算机420可以使用与一台或多台远端计算机(如远端计算机449a和449b)的逻辑连接,在一个联网环境中运行。远端计算机449a和449b都可以是另一个人计算机、服务器、路由器、网络PC、对等设备或其它公共网络节点,并且一般包括在上面关于计算机420所描述的多个或所有元件,尽管在图4中只说明了存储设备450a、450b以及它们所联系的应用程序436a和436b。在图4中所描述的逻辑连接包括局域网(LAN)451和广域网(WAN)452,这些在此作为示例表现出来,但并非限制。在办公室范围或企业范围的计算机网络、内联网和互联网中,这样的联网环境是很平常的。
在LAN联网环境中使用时,计算机420通过网络接口或适配器453连接到局域网451。在WAN联网环境中使用时,计算机420可以包括调制解调器454、无线链路或用于在广域网452(如互联网)上建立通信的其它方法。调制解调器454(可以是内置的或外置的)通过串口接口446连接到系统总线423。在一个已联网的环境中,关于计算机420或其部分所描述的程序模块可以存储在远端存储设备中。可以了解,所示出的网络连接是示例性的,还可以使用在广域网452上建立通信的其它方法。
计算机420仅仅是可以实现本发明原理的通用计算设备的一个示例。在实施例中,计算机420可以按为图1的计算机100所示来物理构架。在那种情况下,监视器447可以是,例如显示设备104。
图5说明了一个包含了用以在监视器447上遵循本发明再现字符图像的多种元件的系统500。应用程序436和操作系统435在系统存储器422中实现,而处理器421则执行与该应用程序和操作系统相联系的多种方法。因此,应用程序436和操作系统435是以软件实现的。系统500还包含硬件图形单元512。
操作系统435进行函数调用,从而控制硬件图形单元512。控制可用的函数调用的架构的一套规则通常称为应用程序接口或API。因此,应用程序接口511被说明是在操作系统435和硬件图形单元512之间,显示着函数是遵循由应用程序接口511所定义的一组规则来调用和返回。
在操作中,应用程序436将文本信息输出到操作系统435,以便在监视器447上再现。举例来说,该应用程序可以是字处理应用、网页设计应用或任何需要显示文本的其它可列举的应用程序。举例来说,输出文本信息包括标识所需再现的字符的信息,在再现中所需使用的字体,字符的点阵尺寸,以及在再现字符时所需运用的画刷纹理(即色彩和透明度值)。
操作系统435包含负责在监视器447上显示文本的多种组件。这些组件包括显示信息501和图形接口502。举例来说,显示信息501包括在再现中所需运用的缩放信息和/或背景色彩信息。
图形接口502包括用于处理图形的程序以及用于处理普遍出现的字符如文本的程序,如字样栅条化器503。字样栅条化器503包括字符表示504和再现与栅条化程序505。举例来说,字符表示504可以包括关于字符轮廓的信息,例如矢量图形、直线、点和曲线。有多种用于表示字符轮廓的传统技术。可以用轮廓信息来产生字符在变动的所期望分辨率水平的位图表示。
再现与栅条化程序505包括缩放子程序506、微调子程序507、扫描转换子程序508和色彩补偿子程序509。这些多种用以产生面向像素子分量的子程序506、507、508和509的操作可以与上面关于Hill等的专利所描述的一样。但是,图形接口502不象Hill等的专利那样,而是与硬件图形单元512相接口。具体来说,图形接口502使用应用程序接口511向硬件图形单元512发出函数调用,并潜在地接收从硬件图形单元512回来的响应。
配置图形接口502以与硬件图形单元512相互动,并不是微不足道的问题。毕竟,已经构造了所期望再现和动画的字符,这样就从不同的采样点产生了各个像素子分量。然而,传统的硬件图形单元是配置成从一个共同的采样点产生特定的像素中每个像素子分量,只对该采样点的像素外观起作用。遵循本发明的原理,可以用传统的硬件图形单元来再现和动画面向像素子分量的字符,即使与这些硬件图形单元相应的应用程序接口或API并不是为将每个像素子分量作为单独的光亮源处理而设计的。
为了适当地修改面向子分量的字符,并且向硬件图形单元512发出适当的函数调用,图形接口502包括了一个自适应模块510。自适应模块510接收字符的位图表示,以及需要运用于该字符的画刷的位图表示。画刷的位图表示包括了对每个像素子分量的光亮度值及透明度值。如此,每个RGB像素就包括六个值:用于红色像素子分量的一个光亮度值(brush.r)和一个透明度值(brush.ar)、用于绿色像素子分量的一个光亮度值(brush.g)和一个透明度值(brush.ag)、用于蓝色像素子分量的一个光亮度值(brush.b)和一个透明度值(brush.ab)。因此,一个面向像素子分量的字符的每个像素都包括三个光亮度值和三个透明度值。
用于与许多种硬件图形单元对接的一种传统的应用程序接口(API)称为MICROSOFTDIRECTX。DirectX能够对具有红、绿、蓝各一的三个画刷色彩亮度值的像素进行操作。DirectX还允许总体上对应于该像素处透明度的一个透明度值。然而,如前面所提到的那样,面向像素子分量的字符潜在地包括每个像素的三个透明度值,以提升对字符的更高分辨率感知。
自适应模块510补偿了传统硬件API与遵循本发明处理的面向子分量像素之间看上去的这种不兼容。图6说明了多种数据结构,用来进行在非实心的背景图像(如使用非实心半透明画刷的已存在的图像)上再现文本的相对复杂操作。这种操作有时候成为“混和”。
参照图6,有四种相关的数据结构能使混和在面向子分量的基础上进行。这些数据结构中的三种作为输入提供给自适应模块510。它们包括一种定义字符形状的数据结构(即字形)、一种定义画刷的数据结构和一种定义背景的数据结构(即DST),在此背景上将运用画刷以形成一幅新的图像。第四种称为NewDST的数据结构定义了进行混和操作后的新图像。
字形数据结构是通过参照已微调的字母i(见图3网格图案313B的字符312’)的第五行R5的C1至C4四列而获得的。假设该字母i是形成在黑色背景上的一个白色字母i。参照元素313B,第5行的第4列是简单的黑色背景。因此,在图6中的字形数据结构的第4列含有对于该像素的红、绿、蓝子分量的每种都为零的值来表示黑色背景。同样地,参照元素313B,在列C1中的第一个像素的红、绿色子分量,以及在列C3中的第三个像素的蓝色子分量,都是黑色背景的一部分。因此,这些相应的像素子分量在图6的字形数据结构中也都赋零值。
参照元素313B,在列C2中的像素的绿色和蓝色子分量完全映射在白色字母i内。因此,这些像素子分量赋最大值。在用8位对光亮度赋整数值的情况下,可以为光亮度赋0和255之间的整数值。因此,这些在图6的字形数据结构中相应的像素子分量都赋值255。
再参照元素313B,剩下的像素子分量(即列C1的蓝色子分量、列C2的红色子分量和列C3的红色和绿色子分量)都包含一些黑色背景和一些白色字符部分。为在图6的字形字符中相应像素子分量赋0和255之间的某个值,与由白色字符所覆盖的区域百分比大致成比例。举例来说,列C1的蓝色子分量和列C3的绿色子分量由白色字符部分覆盖大约155/255比例。因此,这些像素子分量在图6的字形字符中都赋值155。列C2的红色子分量和列C3的红色子分量由白色字符部分覆盖大约231/255比例。因此,这些像素子分量在图6的字形字符中都赋值231。
如前面所描述的那样,图6的字形数据结构描述了在图3的网格结构313B中第5行的C1至C4四列中的字母i的形状。为清晰起见,就关于这一限定的区域来描述混和操作,尽管该字符的其它部分也都将以类似的方式处理。其它数据结构为清晰起见也限定在字符的这一小区域内描述。
图6的示例画刷数据结构包括用于各个RGB像素的六个值,三个RGB像素子分量中的每个各有一个光亮度值和一个透明度值。光亮度值以大约4个像素列为周期在0与255之间大致正弦地变化。透明度值从255开始,并线性下降到2。画刷透明度值0表示该画刷完全透明,而值255表示该画刷完全不透明。
图6的示例DST数据结构描述了将要运用画刷的背景。如果该背景仅是一种实心的颜色,每个像素在其每个红、绿、蓝像素子分量将具有相同的值。然而,在本示例中,背景是非实心的,是将在一幅已存在的图像上再现字符的情况。
根据以下混和公式计算(2)对每个像素子分量计算NewDST数据结构:
NewDST=DST+(Brush.c-DST)*Glyph(F)*Brush.a(F) (2)其中:
Brush.c是子分量的画刷色彩值;
Brush.a是子分量的画刷透明度值;
Brush.a(F)是归一化到零与一之间的Brush.a的浮点值;
Glyph(F)是归一化到零与一之间的Glyph的浮点值。
为完成该示例,要对本示例中的十二个子分量中的每一个执行本公式,以产生在新图像NewDST中的十二个像素子分量的值。
这些运算对每个像素子分量进行混和。但是,传统的硬件API并不是为将每个像素子分量作为单独的具有自己相应采样点的光亮度源处理而设计的。因此,自适应模块510对图6的输入数据结构进行某些修改,然后发出一系列非传统的函数调用,以“诱骗”硬件API来进行面向子分量的混和操作。
具体来说,字形数据结构放大了三倍。而后,对像素将光亮度值赋予一个透明度“alpha”值。在图7的第一个箭头701中说明了这一修改。像素列的数量大了三倍,达到十二。但是,在字形中每个像素只有一个透明度值。这符合DirectX的要求。
为了消除色彩边缘效应,色彩转换子程序509可能随后对每个列重新赋一个新的值,该值等于该列以前值、其左边列以前值和右边列以前值的平均值。举例来说,在列C8的像素可能重新赋值129,该值是231、155和0的平均值。这一平均操作由图7的第二个箭头702说明。尽管该平均操作是说明成发生在放大操作后的,但也可以发生在放大操作前,而不会改变结果。
接着,可以进行三通路再现:一个通路产生红色子分量的帧缓冲703,一个通路产生绿色子分量的帧缓冲704,一个通路产生蓝色子分量的帧缓冲705。为了将这三个色彩通道锁定在输出再现器中,自适应模块510可以向硬件图形单元512进行以下的三个DirectX 8.1函数调用:
IDirect3DDevice8∷SetRenderState(D3DRS_COLORWRITEENABLE,COLORWRITEENABLE_RED)
IDirect3DDevice8∷SetRenderState(D3DRS_COLORWRITEENABLE,COLORWRITEENABLE_GREEN)
IDirect3DDevice8∷SetRenderState(D3DRS_COLORWRITEENABLE,COLORWRITEENABLE_BLUE)
“SetRenderState”方法设置一个单独的设备再现状态参数。状态变量“D3DRS_COLORWRITEENABLE”能够实现对特定目标色彩缓冲的每通道写入。第一、第二和第三个函数调用分别指定了红、绿、蓝色的色彩缓冲作为目标色彩缓冲。
然后,再现每个色彩。对于红色,用以前对应于红色子分量的字形透明度值(即列C1、C4、C7和C10)来填充红色目标缓冲703。类似地,用列C2、C5、C8和C11来填充绿色目标缓冲704,用列C3、C6、C9和C12来填充蓝色目标缓冲705。
可以以许多方式用DirectX 8.1函数调用将色彩再现到其不同的色彩缓冲。举例来说,画刷可能是一种实心颜色,其中每个像素都用同样的颜色。或者,画刷也可以构造成其中每个像素可以用不同的颜色。画刷还可以是不透明的或半透明的。背景平面可以是要反映在显示屏上的最终平面,也可以是一个中间平面。中间背景平面不仅可以包含每个像素的RGB色彩值,也可以包含其透明度值。
本描述的下一部分描述了一个称为“DrawGlyphExample”的C++程序,该程序执行一种再现技术,在其中目标平面只有RGB色彩值,没有透明度值,而画刷构造成每个像素包含四个值:RGB色彩的每一种有一个值,和整个像素共有一个透明度值。程序DrawGlyphExample运作来画出图7对应于列C1至C4的四个像素。为清晰起见,代码部分将一段一段来演示。
首先,将简述代码中所用的不同段落。“pDev”是一个指向“IDirect3DDevice8”的指针,它是实现DirectX 8.1作图API的许多部分的一个基本DirectX 8.1对象。“pGlyphTexture”是一个指向纹理的指针,它包含已备好的字形数据。为清晰起见,该纹理假设为256*256大小,并包含对应于在屏幕左上角的列C1至C12的字形透明度数据,如元素[0][0]到[0][11]。“pBrushTexture”是一个指向纹理的指针,它包含已备好的画刷数据。为清晰起见,该纹理假设为256*256大小,并包含对应于在左上角的列C1至C4的画刷色彩与透明度数据,如元素[0][0]到[0][3]。
以下的代码示例开始了DrawGlyphsExample程序:
Void DrawGlyphsExample(IDirect3DDevice8*pDev,
IDirect3DTexture8*pGlyphTexture,
IDirect3DTexture8*pBrushTexture)
{
为了定义字形的形状和其在屏幕上的位置,还有画刷画面应当如何在屏幕上拉伸和定位,DirectX坐标信息存在于以下称为“TheVertex”的结构中:
struct TheVertex
{
public:
float x,y,z,w;
float bx,by;
float gx,gy;
}vertices[4];
这里,“x”和“y”表示在屏幕上的一个点。“z”和“w”在这个两维的示例中不使用,但可以用于三维的图形。“bx”和“by”表示在画刷纹理平面上的一个点。“gx”和“gy”表示在字形纹理平面上的一个点。
字形的形状是矩形的,所以完整的坐标定义需要一个四个顶点的数组。以下的运算符以符合图7上示例的特定坐标填充了这四个顶点。
#define X 0
#define Y 0
#define W 4
#define H 4
vertices[0].x=X;vertices[0].y=Y;
vertices[1].x=X+W;vertices[1].y=Y;
vertices[2].x=X+W;vertices[2].y=Y+H;
vertices[3].x=X;vertices[3].y=Y+H;
在这一段中,“X”是放置于屏幕窗口中的结果字形图像的左上角的X坐标。“Y”是放置于屏幕窗口中的这个角的Y坐标。“W”是屏幕窗口中的结果字形矩形的宽度。“H”是屏幕窗口中的结果字形矩形的高度。
以下的两行用以排除第三维:
vertices[0].z=vertices[1].z=vertices[2].z=vertices[3].z=0;
vertices[0].w=vertices[1].w=vertices[2].w=vertices[3].w=1;
以下定义了字形纹理的顶点:
#define GWT 256.f
#define GHT 256.f
#define GX 0
#define GY 0
#define GW 12
#define GH 1
vertices[0].gx=(GX)/GWT;vertices[0].gy=(GY)/GHT;
vertices[1].gx=(GX+GW)/GWT;vertices[1].gy=(GY)/GHT;
vertices[2].gx=(GX+GW)/GWT;vertices[2].gy=(GY+GH)/GHT;
vertices[3].gx=(GX)/GWT;vertices[3].gy=(GY+GH)/GHT;
在这一段中,“GWT”是整个字形纹理的宽度,“GHT”是整个字形纹理的高度,“GX”是在该纹理平面内的字形信息的X坐标,“GY”是在该纹理平面内的字形信息的Y坐标,“GW”是放大了的字形数据矩形的宽度,而“GH”是该字形数据矩形的高度。
以下定义了画刷纹理的顶点:
#define BWT 256.f
#define BHT 256.f
#define BX 0
#define BY 0
#define BW 12
#define BH 1
vertices[0].bx=(BX)/BWT;vertices[0].by=(BY)/BHT;
vertices[1].bx=(BX+BW)/BWT;vertices[1].by=(BY)/BHT;
vertices[2].bx=(BX+BW)/BWT;vertices[2].by=(BY+BH)/BHT;
vertices[3].bx=(BX)/BWT;vertices[3].by=(BY+BH)/BHT;
在这一段中,“BWT”是整个画刷纹理的宽度,“BHT”是整个画刷纹理的高度,“BX”是在该纹理平面内的画刷信息的X坐标,“BY”是在该纹理平面内的画刷信息的Y坐标,“BW”是要映射到字形的画刷平面上的矩形的宽度,而“BH”是要映射到字形的画刷平面上的矩形的高度。
接着,进行一系列初步DirectX 8.1调整API调用。再现将包括两个纹理阶(texture stage)。纹理阶是硬件的一部分,能够从纹理中取出数据并操作这些数据。所有纹理阶都并行工作。纹理阶在流程中对每个像素执行相同的操作。传统的硬件可以包含多达八个纹理阶,以数字0至7来区别。
在本示例中,纹理阶0将处理画刷纹理数据。以下的DirectX 8.1函数调用命令纹理阶0使用画刷纹理:
pDev->SetTexture(0,pBrushTexture);
以下的DirectX 8.1函数调用指示纹理阶0从纹理中取出数据,而不进行任何计算,这样纹理阶0的输出寄存器就包含有brush.rgb和brush.a的值:
pDev->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDev->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
pDev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
pDev->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
以下的DirectX 8.1函数调用指示纹理阶0使用TheVertex结构的第一组(bx,by):
pDev->SetTextureStageState(0,D3DTSS_TEXCOORDINDEX,0);
以下的DirectX 8.1函数调用告知纹理阶0该纹理坐标是二维的:
pDev->SetTextureStageState(0,D3DTSS_TEXTURETRANSFORMFLAGS,
D3DTTFF_COUNT2);
纹理阶1将处理字形纹理数据。因此,以下的DirectX 8.1函数调用命令纹理阶1处理字形纹理数据:
pDev->SetTexture(1,pGlyphTexture);
以下的DirectX 8.1函数调用指示纹理阶1的色彩通道从纹理阶0中取出数据,而不进行任何进一步的计算:
pDev->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
pDev->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_SELECTARG2);
以下的DirectX 8.1函数调用指示纹理阶1的alpha通道从纹理阶0中取出第一个alpha数据,从纹理中取出第二个alpha数据,然后将这两个值相乘并将结果传入输出寄存器:
pDev->SetTextureStageState(1,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
pDev->SetTextureStageState(1,D3DTSS_ALPHAARG2,D3DTA_CURRENT);
pDev->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
以下的DirectX 8.1函数调用指示纹理阶1使用TheVertex结构的第二组(gx,gy):
pDev->SetTextureStageState(1,D3DTSS_TEXCOORDINDEX,1);
以下的DirectX 8.1函数调用告知纹理阶1该纹理坐标是二维的:
pDev->SetTextureStageState(1,D3DTSS_TEXTURETRANSFORMFLAGS,
D3DTTFF_COUNT2);
纹理阶1的输出寄存器将提供到目前为止的四个值:brush.rgb和brush.a*glyph.a。
以下的DirectX 8.1函数调用关闭纹理阶2:
pDev->SetTextureStageState(2,D3DTSS_COLOROP,D3DTOP_DISABLE);
其结果是,纹理阶1的输出寄存器将被导向到输出栅条化器去。
输出栅条化器也是硬件的一部分,能够从目标像素缓冲中取出数据,从特定的纹理阶状态接收数据,执行混和操作,并将结果存回目标缓冲。输出栅条化器也需要初步调整。
以下的DirectX 8.1函数调用实现混和:
pDev->SetRenderSrate(D3DRS_ALPHABLENDENABLE,TRUE);
以下的DirectX 8.1函数调用指示栅条化器将从目标缓冲取出的色彩值与从纹理阶1获得的反转alpha值相乘:
pDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
“反转alpha”值意为1减去alpha值。
以下的DirectX 8.1函数调用指示栅条化器将从纹理阶1获得的色彩值与也是从纹理阶1获得的alpha值相乘:
pDev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
其结果是,栅条化器将执行公式newdst.rgb=dst.rgb*(1-stage.a)+stage.rgb*stage.a,其中stage.rgb=brush.rgb和stage.a=brush.a*glyph.a是由纹理阶1所计算的值,而“dst”和“newdst”意为目标缓冲的像素值。
最后这就得出newdst.rgb=dst.rgb+(brush.rgb-dst.rgb)*brush.a*glyph.a。从而栅条化器将计算三个数值,对红、绿、蓝每个分量分别计算一个数值。但是由于下面阐明的另外设置,这三个数值不是都会存储下来。
以下的DirectX 8.1函数告知Direct3D设备TheVertex结构的格式:
SetVertexShader(D3DFVF_XYZRHW|D3DFVF_TEX2);
而后,该程序对色彩分量:红、绿、蓝中的每一个进行三通路。
以下的代码段再现红色分量。代码中包含了解释有关该代码的功能的注释。
{
//将字形顶点向左平移1个放大的像素。这将有效地移动字形数据,使得屏幕像素的中心映射到具有下标0、3、6、9的字形像素。
for(int i=0;i<4;i++)vertices[i].gx-=1/GWT;
//指示栅条化器只存储红色值
pDev->SetRenderState(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_RED);
//将矩形画成一组相邻的两个三角形
pDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,vertices,
sizeof(TheVertex));
}
以下的代码段再现绿色分量。
{
//将字形顶点向右平移1个像素。这将有效地移动字形数据,使得屏幕像素的中心映射下标1、4、7、10的字形像素。
for(int i=0;i<4;i++)vertices[i].gx+=1/GWT;
//指示栅条化器只存储绿色值
pDev->SetRenderState(D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_GREEN);
//将矩形画成一组相邻的两个三角形
pDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,vertices,
sizeof(TheVertex));
}
以下的代码段再现蓝色分量。
{
//将字形顶点向右平移超过1个像素。这将有效地移动字形数据,使得屏幕像素的中心映射下标2、5、8、11的字形像素。
for(int i=0;i<4;i++)vertices[i].gx+=1/GWT;
//指示栅条化器只存储蓝色值
pDev->SetRenderState(D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_BLUE);
//将矩形画成一组相邻的两个三角形
pDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,vertices,
sizeof(TheVertex));
}
这样,在这种三通路再现技术中,公式newdst.rgb=dst.rgb+(brush.rgbdst.rgb)*brush.a*glyph.a被计算了三次。每一次都使用了同样的画刷值,但每次都以不同的glyph.a值。为完整起见,以下行的代码(即结束括号)简单地结束该过程:
}//结束示例程序
这样,用某些预先的字形数据结构处理,并通过三通路进行再现(每一遍都以非标准的方式再现),可以让硬件图形单元512来进行面向像素子分量的再现,即使应用程序接口并不是设计来将每个像素子分量作为单独的光亮源处理。因此,本发明的原理提供了再现显示屏的较高分辨率显示,在其中将每个像素子分量作为从不同采样点产生的单独光亮源来处理。而且,可以由硬件图形单元来进行如混和的操作,从而加速再现处理。在回顾了这一描述后,在相关领域中的普通技术人员会认识到也可以用硬件图形单元512在面向子分量的图像上进行其它操作。具体来说,本发明的原理可以用来用硬件加速缩放和旋转在背景上的给定字符。
使用刚才描述的示例子过程,人们可以利用本发明的原理,通过改变值vertices[i].x和vertices[i].y来获得如旋转和缩放的效果。字形可以放置在屏幕窗口上的所期望的区域,而用于字形和画刷变换的所有计算由DirectX8.1使用如上面所列的示例程序所控制的硬件来自动提供。对于屏幕上的每个像素,该硬件都将计算字形和画刷纹理中相应的点。
为了能任意地仿射变换,顶点的坐标一般不会是某个整数值。在这种情况下,传统的硬件可能使用最近的整数作为下标来从纹理中取出相应的点值。但是,这种取整会产生一幅多少有点粗糙的画面。可以通过用DirectX 8.1设置强制硬件使用对四个最近点间双线性插值而计算的纹理坐标的小数部分来改善画面。这可以通过以下的DirectX 8.1设置来获得:
pDev->SetTextureStageState(1,D3DTSS_MAGFILTER,D3DTFG_LINEAR);
pDev->SetTextureStageState(1,D3DTSS_MINFILTER,D3DTFG_LINEAR);
双线性插值提供了平滑的拉伸并改善了动画字形图像的视觉吸引力。尽管双线性插值需要大量的计算,但当使用了传统硬件时,再现速度并未受实质影响。这是因为这些计算是在硬件的单独部分中进行,这些部分与满足在示例子程序中所列出的DirectX 8.1函数调用的硬件部分并行运行。
上面所提到的缩放变换不需要重建字形和画刷纹理。在产生下一帧时,只改变了坐标信息。然而,缩放与如何准备字形纹理有关。在不需要变换时,将使用图5的色彩补偿程序509,而不使用由图7中箭头702所表示的平均步骤。相反,在运用和动画(在每个帧上变化)了变换时,可以由前面的色彩补偿程序509来减少色彩边缘效应,并使用箭头702所表示的平均步骤来代替。某种意义上,平均程序702是一种特殊的色彩补偿程序,在缩放字形时提供色彩平衡。
由于多种操作如混和、缩放和旋转都可以在硬件图形单元的辅助下进行,而硬件图形单元进行这样的操作一般比用软件更快,那么对给定字符的再现和动画可以显著地改善。
本发明可以以其它特殊的形式来实施,而不背离其精神或基本特征。所描述的实施例应当只是说明性的,而不是限制性的。所以,本发明的范围由所附权利要求而不是由前面的描述来指明。在等价于这些权利要求的含义和范围内的所有改变,都应当包括在其中。