我前面提到过,您可以把整个视讯显示器看作是一幅大位图。您在屏幕上见到的图素由储存在视讯显示卡上内存中的位来描述。任何视讯显示的矩形区域也都是一个位图,其大小是它所包含的行列数。
让我们从将图像从视讯显示的一个区域复制到另一个区域,开始我们在位图世界的旅行吧!这个是强大的BitBlt函数的工作。
Bitblt(读作「bit blit」)代表「位块传输(bit-block transfer)」。BLT起源于一条汇编语言指令,该指令在DEC PDP-10上用来传输内存块。术语「bitblt」第一次用在图像上与Xerox Palo Alto Research Center(PARC)设计的SmallTalk系统有关。在SmallTalk中,所有的图形输出操作都使用bitblt。程序写作者有时将blt用作动词,例如:「Then I wrote some code to blt the happy face to the screen and play a wave file.」
BitBlt函数移动的是图素,或者(更明确地)是一个位映像图块。您将看到,术语「传输(transfer)」与BitBlt函数不尽相同。此函数实际上对图素执行了一次位操作,而且可以产生一些有趣的结果。
简单的BitBlt
程序14-1所示的BITBLT程序用BitBlt函数将程序系统的菜单图标(位于程序Windows的左上角)复制到它的显示区域。
BITBLT.C
/*----------------------------------------------------------------------
BITBLT.C -- BitBlt Demonstration
(c) Charles Petzold, 1998
-------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] = TEXT ("BitBlt") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_INFORMATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("BitBlt Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static int cxClient, cyClient, cxSource, cySource ;
HDC hdcClient, hdcWindow ;
int x, y ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_CREATE:
cxSource = GetSystemMetrics (SM_CXSIZEFRAME) +
GetSystemMetrics (SM_CXSIZE) ;
cySource = GetSystemMetrics (SM_CYSIZEFRAME) +
GetSystemMetrics (SM_CYCAPTION) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdcClient = BeginPaint (hwnd, &ps) ;
hdcWindow = GetWindowDC (hwnd) ;
for (y = 0 ; y < cyClient ; y += cySource)
for (x = 0 ; x < cxClient ; x += cxSource)
{
BitBlt (hdcClient, x, y, cxSource, cySource,
hdcWindow, 0, 0, SRCCOPY) ;
}
ReleaseDC (hwnd, hdcWindow) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
但为什么只用了一个BitBlt呢?实际上,那个BITBLT用系统菜单图标的多个副本来填满显示区域(在此情况下是信息方块中普遍使用的IDI_INFORMATION图示),如图14-1所示。
图14-1 BITBLT的屏幕显示 |
BitBlt函数从称为「来源」的设备内容中将一个矩形区的图素传输到称为「目的(destination)」的另一个设备内容中相同大小的矩形区。此函数的语法如下:
BitBlt (hdcDst, xDst, yDst, cx, cy, hdcSrc, xSrc, ySrc, dwROP) ;
来源和目的设备内容可以相同。
在BITBLT程序中,目的设备内容是窗口的显示区域,设备内容句柄从BeginPaint函数获得。来源设备内容是应用程序的整个窗口,此设备内容句柄从GetWindowDC获得的。很明显地,这两个设备内容指的是同一个实际设备(视讯显示器)。不过,这两个设备内容的坐标原点不同。
xSrc和ySrc参数指明了来源图像左上角的坐标位置。在BITBLT中,这两个参数设为0,表示图像从来源设备内容(也就是整个窗口)的左上角开始,cx和cy参数是图像的宽度和高度。BITBLT根据从GetSytemMetrics函数获得的信息来计算这些值。
xDst和yDst参数表示了复制图像位置左上角的坐标位置。在BITBLT中,这两个参数设定为不同的值以便多次复制图像。对于第一次BitBlt呼叫,这两个参数设制为0,将图像复制到显示区域的左上角位置。
BitBlt的最后一个参数是位映像操作型态。我将简短地讨论一下这个值。
请注意,BitBlt是从实际视讯显示内存传输图素,而不是从系统菜单图标的其它图像传输。如果您移动BITBLT窗口以使部分系统菜单图标移出屏幕,然后调整BITBLT窗口的尺寸使其重画,这时您将发现BITBLT显示区域中显示的是菜单图示的一部分。BitBlt函数不再存取整个图像。
在BitBlt函数中,来源和目的设备内容可以相同。您可以重新编写BITBLT以使WM_PAINT处理执行以下内容:
BitBlt (hdcClient, 0, 0, cxSource, cySource,
hdcWindow, 0, 0, SRCCOPY) ;
for (y = 0 ; y < cyClient ; y += cySource)
for (x = 0 ; x < cxClient ; x += cxSource)
{
if (x > 0 || y > 0)
BitBlt (hdcClient, x, y, cxSource, cySource,
hdcClient, 0, 0, SRCCOPY) ;
}
这将与前面显示的BITBLT一样产生相同的效果,只是显示区域左上角比较模糊。
在BitBlt内的最大限制是两个设备内容必须是兼容的。这意味着或者其中之一必须是单色的,或者两者的每个图素都相同的位数。总而言之,您不能用此方法将屏幕上的某些图形复制到打印机。
拉伸位图
在BitBlt函数中,目的图像与来源图像的尺寸是相同的,因为函数只有两个参数来说明宽度和高度。如果您想在复制时拉伸或者压缩图像尺寸,可以使用StretchBlt函数。StretchBlt函数的语法如下:
StretchBlt (hdcDst, xDst, yDst, cxDst, cyDst,
hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwROP) ;
此函数添加了两个参数。现在的函数就分别包含了目的和来源各自的宽度和高度。STRETCH程序展示了StretchBlt函数,如程序14-2所示。
程序14-2 STRETCH
STRETCH.C
/*--------------------------------------------------------------------------
STRETCH.C -- StretchBlt Demonstration
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] = TEXT ("Stretch") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_INFORMATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("StretchBlt Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxClient, cyClient, cxSource, cySource ;
HDC hdcClient, hdcWindow ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_CREATE:
cxSource = GetSystemMetrics (SM_CXSIZEFRAME) +
GetSystemMetrics (SM_CXSIZE) ;
cySource = GetSystemMetrics (SM_CYSIZEFRAME) +
GetSystemMetrics (SM_CYCAPTION) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdcClient = BeginPaint (hwnd, &ps) ;
hdcWindow = GetWindowDC (hwnd) ;
StretchBlt (hdcClient, 0, 0, cxClient, cyClient,
hdcWindow, 0, 0, cxSource, cySource, MERGECOPY) ;
ReleaseDC (hwnd, hdcWindow) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
此程序只有呼叫了StretchBlt函数一次,但是利用此函数以系统菜单图标填充了整个显示区域,如图14-2所示。
图14-2 STRETCH的屏幕显示 |
BitBlt和StretchBlt函数中所有的坐标与大小都是依据逻辑单位的。但是当您在BitBlt函数中定义了两个不同的设备内容,而这两个设备内容虽然参考同一个实际设备,却各自有着不同的映像模式,这时将发生什么结果呢?如果出现这种情况,呼叫BitBlt产生的结果就显得不明确了:cx和cy参数都是逻辑单位,而它们同样应用于来源设备内容和目的设备内容中的矩形区。所有的坐标和尺寸必须在实际的位传输之前转换为设备坐标。因为cx和cy值同时用于来源和目的设备内容,所以此值必须转换为设备内容自己的单位。
当来源和目的设备内容相同,或者两个设备内容都使用MM_TEXT图像模式时,设备单位下的矩形尺寸在两个设备内容中会是相同的,然后才由Windows进行图素对图素的转换。不过,如果设备单位下的矩形尺寸在两个设备内容中不同时,则Windows就把此工作转交给更通用的StretchBlt函数。
StretchBlt也允许水平或垂直翻转图像。如果cxSrc和cxDst标记(转换成设备单位以后)不同,那么StretchBlt就建立一个镜像:左右翻转。在STRETCH程序中,通过将xDst参数改为cxClient并将cxDst参数改成-cxClient,您就可以做到这一点。如果cySrc和cyDst不同,则StretchBlt会上下翻转图像。要在STRETCH程序中测试这一点,可将yDst参数改为cyClient并将cyDst参数改成-cyClient。
StretchBlt模式
使用StretchBlt会碰到一些与位图大小缩放相关的一些根本问题。在扩展一个位图时,StretchBlt必须复制图素行或列。如果放大倍数不是原图的整数倍,那么此操作会造成产生的图像有些失真。
如果目的矩形比来源矩形小,那么StretchBlt在缩小图像时就必须把两行(或列)或者多行(或列)的图素合并到一行(或列)。完成此操作有四种方法,它根据设备内容伸展模式属性来选择其中一种方法。您可使用SetStretchBltMode函数来修改这个属性。
SetStretchBltMode (hdc, iMode) ;
iMode可取下列值:
- BLACKONWHITE或者STRETCH_ANDSCANS(内定)如果两个或多个图素得合并成一个图素,那么StretchBlt会对图素执行一个逻辑AND运算。这样的结果是只有全部的原始图素是白色时该图素才为白色,其实际意义是黑色图素控制了白色图素。这适用于白背景中主要是黑色的单色位图。
- WHITEONBLACK或STRETCH_ORSCANS 如果两个或多个图素得合并成一个图素,那么StretchBlt执行逻辑OR运算。这样的结果是只有全部的原始图素都是黑色时才是黑色,也就是说由白色图素决定颜色。这适用于黑色背景中主要是白色的单色位图。
- COLORONCOLOR或STRETCH_DELETESCANS StretchBlt简单地消除图素行或列,而没有任何逻辑组合。这是通常是处理彩色位图的最佳方法。
- HALFTONE或STRETCH_HALFTONE Windows根据组合起来的来源颜色来计算目的的平均颜色。这将与半调调色盘联合使用, 第十六章将展示这一程序。
Windows还包括用于取得目前伸展模式的GetStretchBltMode函数。
位映像操作
BITBLT和STRETCH程序简单地将来源位图复制给了目的位图,在过程中也可能进行了缩放。这是把SRCCOPY作为BitBlt和StretchBlt函数最后一个参数的结果。SRCCOPY只是您能在这些函数中使用的256个位映像操作中的一个。让我们先在STRETCH程序中做一个别的实验,然后再系统地研究位映像操作。
尽量用NOTSRCCOPY来代替SRCCOPY。与它们名称一样,位映像操作在复制位图时转换其颜色。在显示区域窗口,所有的颜色转换:黑色变成白色、白色变成黑色,蓝色变成黄色。现在试一下SRCINVERT,您将得到同样效果。如果试一下BLACKNESS,正如其名称一样,整个显示区域都将变成黑色,而WHITENESS则使其变成白色。
现在试一试用下列三条叙述来代替StretchBlt呼叫:
SelectObject (hdcClient, CreateHatchBrush (HS_DIAGCROSS, RGB (0, 0, 0)));
StretchBlt (hdcClient, 0, 0, cxClient, cyClient,
hdcWindow, 0, 0, cxSource, cySource, MERGECOPY) ;
DeleteObject (hdcClient, GetStockObject (WHITE_BRUSH)) ;
这次,您将在图像上看到一个菱形的画刷,这是什么?
我在前面说过,BitBlt和StretchBlt函数不是简单的位块传输。此函数实际在下面三种图像间执行位操作。
- Source 来源位图,拉伸或压缩(如果有必要)到目的矩形的尺寸。
- Destination 在BitBlt或StretchBlt呼叫之前的目的矩形。
- Pattern 在目的设备内容中选择的目前画刷,水平或垂直地复制到目的矩形范围内。
结果是复制到了目的矩形中。
位映像操作与我们在第五章遇到的绘图模式在概念上相似。绘图模式采用图像对象的控件方式,例如一条线就组合成一个目的。我们知道有16种绘图模式-也就是说,对象中的0和1画出时,唯一结果就是目的中0和1的组合。
使用BitBlt和StretchBlt的位映像操作包含了三个对象的组合,这将产生256种位映像操作。有256种方法来组合来源位图、目的位图和图案。有15种位映像操作已经命名-其中一些名称其实还不能够清楚清楚说明其意义-它们定义在WINGDI.H里头,其余的都有数值,列在/Platform SDK/Graphics and Multimedia Services/GDI/Raster Operation Codes/Ternary Raster Operations之中。
有名称的15种ROP代码见表14-4。
表14-4 |
图案(P):1 1 1 1 0 0 0 0 来源(s):1 1 0 0 1 1 0 0 目的(D):1 0 1 0 1 0 1 0 | 布尔操作 | ROP代码 | 名称 | |
结果: | 0 0 0 0 0 0 0 0 | 0 | 0x000042 | BLACKNESS |
0 0 0 1 0 0 0 1 | ~(S?#160;D) | 0x1100A6 | NOTSRCERASE | |
0 0 1 1 0 0 1 1 | ~S | 0x330008 | NOTSRCCOPY | |
0 1 0 0 0 1 0 0 | S & ~D | 0x440328 | SRCERASE | |
0 1 0 1 0 1 0 1 | ~D | 0x550009 | DSTINVERT | |
0 1 0 1 1 0 1 0 | P ^ D | 0x5A0049 | PATINVERT | |
0 1 1 0 0 1 1 0 | S ^ D | 0x660046 | SRCINVERT | |
1 0 0 0 1 0 0 0 | S & D | 0x8800C6 | SRCAND | |
1 0 1 1 1 0 1 1 | ~S?#160;D | 0xBB0226 | MERGEPAINT | |
1 1 0 0 0 0 0 0 | P & S | 0xC000CA | MERGECOPY | |
1 1 0 0 1 1 0 0 | S | 0xCC0020 | SRCCOPY | |
1 1 1 0 1 1 1 0 | S?#160;D | 0xEE0086 | SRCPAINT | |
1 1 1 1 0 0 0 0 | P | 0xF00021 | PATCOPY | |
1 1 1 1 1 0 1 1 | P?#160; ~S?#160; D | 0xFB0A09 | PATPAINT | |
1 1 1 1 1 1 1 1 | 1 | 0xFF0062 | WHITENESS |
此表格对于理解和使用位映像操作非常重要,因此我们应花点时间来研究。
在这个表格中,「ROP代码」行的值将传递给BitBlt或StretchBlt的最后一个参数;在「名称」行中的值在WINGDI.H定义。ROP代码的低字组协助设备驱动程序传输位映像操作。高字组是0到255之间的数值。此数值与第2列的图案的位相同,这是在图案、来源和显示在顶部的目的之间进行位操作的结果。「布尔运算」列按C语法显示图案、来源和目的的组合方式。
要开始了解此表,最简单的办法是假定您正处理一个单色系统(每图素1位)其中0代表黑色,1代表白色。BLACKNESS操作的结果是不管是来源、目的和图案是什么,全部为零,因此目的将显示黑色。类似地,WHITENESS总导致目的呈白色。
现在假定您使用位映像操作PATCOPY。这导致结果位与图案位相同,而忽略了来源和目的位图。换句话说,PATCOPY简单地将目前图案复制给了目的矩形。
PATPAINT位映像操作包含一个更复杂的操作。其结果相同于在图案、目的和反转的来源之间进行位或操作。当来源位图是黑色(0)时,其结果总是白色(1);当来源是白色(1)时,只要图案或目的为白色,则结果就是白色。换句话说,只有来源为白色而图案和目的都是黑色时,结果才是黑色。
彩色显示时每个图素都使用了多个位。BitBlt和StretchBlt函数对每个颜色位都分别提供了位操作。例如,如果目的是红色而来源为蓝色,SRCPAINT位映像操作把目的变成洋红色。注意,操作实际是按显示卡内储存的位执行的。这些位所对应的颜色取决于显示卡的调色盘的设定。Windows完成了此操作,以便位映像操作能达到您预计的结果。不过,如果您修改了调色盘(我将在第十六章讨论),位映像操作将产生无法预料的结果。
如要得到位映像操作较好的应用程序,请参见本章后面的「非矩形位图图像」一节。
图案Blt
除了BitBlt和StretchBlt以外,Windows还包括一个称为PatBlt (「pattern block transfer:图案块传输」)的函数。这是三个「blt」函数中最简单的。与BitBlt和StretchBlt不同,它只使用一个目的设备内容。PatBlt语法是:
PatBlt (hdc, x, y, cx, cy, dwROP) ;
x、y、cx和cy参数字于逻辑单位。逻辑点(x,y)指定了矩形的左上角。矩形宽为cx单位,高为cy单位。这是PatBlt修改的矩形区域。PatBlt在画刷与目的设备内容上执行的逻辑操作由dwROP参数决定,此参数是ROP代码的子集-也就是说,您可以只使用那些不包括来源目的设备内容的ROP代码。下表列出了PatBlt支持的16个位映像操作:
表14-5 |
图案(P):1 1 0 0 目的(D):1 0 1 0 | 布尔操作 | ROP代码 | 名称 | |
结果: | 0 0 0 0 | 0 | 0x000042 | BLACKNESS |
0 0 0 1 | ~(P | D) | 0x0500A9 | ||
0 0 1 0 | ~P & D | 0x0A0329 | ||
0 0 1 1 | ~P | 0x0F0001 | ||
0 1 0 0 | P & ~D | 0x500325 | ||
0 1 0 1 | ~D | 0x550009 | DSTINVERT | |
0 1 1 0 | P ^ D | 0x5A0049 | PATINVERT | |
0 1 1 1 | ~(P & D) | 0x5F00E9 | ||
1 0 0 0 | P & D | 0xA000C9 | ||
1 0 0 1 | ~(P ^ D) | 0xA50065 | ||
1 0 1 0 | D | 0xAA0029 | ||
1 0 1 1 | ~P | D | 0xAF0229 | ||
1 1 0 0 | P | 0xF00021 | PATCOPY | |
1 1 0 1 | P | ~D | 0xF50225 | ||
1 1 1 0 | P | D | 0xFA0089 | ||
1 1 1 1 | 1 | 0xFF0062 | WHITENESS |
下面列出了PatBlt一些更常见用途。如果想画一个黑色矩形,您可呼叫
PatBlt (hdc, x, y, cx, cy, BLACKNESS) ;
要画一个白色矩形,请用
PatBlt (hdc, x, y, cx, cy, WHITENESS) ;
函数
PatBlt (hdc, x, y, cx, cy, DSTINVERT) ;
用于改变矩形的颜色。如果目前设备内容中选择了WHITE_BRUSH,那么函数
PatBlt (hdc, x, y, cx, cy, PATINVERT) ;
也改变矩形。
您可以再次呼叫FillRect函数来用画笔充满一个矩形区域:
FillRect (hdc, &rect, hBrush) ;
FillRect函数相同于下列代码:
hBrush = SelectObject (hdc, hBrush) ;
PatBlt (hdc, rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top, PATCOPY) ;
SelectObject (hdc, hBrush) ;
实际上,此程序代码是Windows用于执行FillRect函数的动作。如果您呼叫
InvertRect (hdc, &rect) ;
Windows将其转换成函数:
PatBlt (hdc, rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top, DSTINVERT) ;
在介绍PatBlt函数的语法时,我说过点(x,y)指出了矩形的左上角,而且此矩形宽度为cx单位,高度为cy单位。此叙述并不完全正确。BitBlt、PatBlt和StretchBlt是最合适的GDI画图函数,它们根据从一个角测得的逻辑宽度和高度来指定逻辑直角坐标。矩形边框用到的其它所有GDI画图函数都要求根据左上角和右下角的坐标来指定坐标。对于MM_TEXT映像模式,上面讲述的PatBlt参数就是正确的。然而对于公制的映像模式来说,就不正确。如果您使用一的cx和cy值,那么点(x,y)将是矩形的左下角。如果希望点(x,y)是矩形的左上角,那么cy参数必须设为矩形的负高度。
如果想更精确,用PatBlt修改颜色的矩形将通过cx的绝对值获得逻辑宽度,通过cy的绝对值获得逻辑高度。这两个参数可以是负值。由逻辑点(x, y)和(x + cx, y + cy)给定的两个角定义了矩形。矩形的左上角通常属于PatBlt修改的区域。右上角则超出了矩形的范围。根据映像模式和cx、cy参数的符号,矩形左上角的点应为(x, y)、(x, y + cy)、(x + cx, y)或者(x + cx, y + cy)。
如果给MM_LOENGLISH设定了映像模式,并且您想在显示区域左上角的一小块正方形上使用PatBlt,您可以使用
PatBlt (hdc, 0, 0, 100, -100, dwROP) ;
或
PatBlt (hdc, 0, -100, 100, 100, dwROP) ;
或
PatBlt (hdc, 100, 0, -100, -100, dwROP) ;
或
PatBlt (hdc, 100, -100, -100, 100, dwROP) ;
给PatBlt设定正确参数最容易的方法是将x和y设为矩形左上角。如果映像模式定义y坐标随着向上卷动显示而增加,那么请使用负的cy参数。如果映像模式定义x坐标向左增加(很少有人用),则需要使用负的cx参数。