第14章 位图和位块传输_14.1-14.3 位图基础

14.1 位图基础

(1)位图和图元文件的区别:位图是点阵图形;图元文件是矢量图形

(2)位图的缺点:

  ①受设备相关的影响(如色彩、分辨率、纵横比例)

  ②需要很大的存储空间:如640×480像素,16种颜色(4位),需要640*480*4/8/1024(即150KB);1024×768像素,24位图形需要1024*768*24/8/1024/1024(即2.25MB)。位图的存储空间是由图像大小和它所包含颜色的数目决定。而图元文件的存储空间是由图像的复杂度和它所包含的GDI命令的个数来决定的。

(3)位图的优点:速度快,将位图复制到视频显示器,通常比绘制一个图元文件要快得多。

14.2 位图尺寸

14.2.1 颜色和位图

 (1)颜色深度(Color Depth):每个像素需要的位的数目。也称位数(bit-count)或每像素位数(bits per pixel,bpp)。

(2)单色位图:每个像素只有1位,也称为“二级(bitlevel)”或“二色”位图。

(3)位数(n)和所能表示的颜色数目(m): m =2^n

14.2.2 现实世界的设备

(1)CGA和HGC显卡:单色(1位)

(2)EGA:16种颜色(4位)。EGA提供64种颜色的调色板,但应用程序只能选16种)。

     ①16色位图的色彩编码IRGB(强度—红—绿—蓝)

     ②EGA把内存分为4个“颜色平面”,分别是强度、红、绿、蓝。而每个像素颜色的定义是分别从这4个平面中取1位出来组合得一个IRGB值,然后将此值做为索引从下列表格中取出相应的RGB颜色。

     ③IRGB值与RGB颜色值的对应关系

IRGB

RGB颜色

颜色名称

IRGB

RGB颜色

颜色名称

0000

00-00-00

1000

80-80-80

深灰

0001

00-00-80

深蓝

1001

00-00-FF

0010

00-80-00

深绿

1010

00-FF-00

绿

0011

00-80-80

深青

1011

00-FF-FF

0100

80-00-00

深红

1100

FF-00-00

0101

80-00-80

深洋红

1101

FF-00-FF

洋红

0110

80-80-00

深黄

1110

FF-FF-00

0111

C0-C0-C0

浅灰

1111

FF-FF-FF

(3)VGA或SVGA显卡:256种颜色(每个像素用8位,不一定对应具体的颜色),显卡采用的是“调色板查找表”的方式。其中20种是保留颜色,其作236种可以自定义。

(4)全真彩显卡:16位或24位。现在一般用24位。即每个像素用3个字节表示。

14.3 位块传输

14.3.1 几个位块传输函数

(1)BitBlt函数:BitBlt(hdcDst,xDst,yDst,cx,cy,hdcSrc,xSrc,ySrc,dwROP);

  ①从“源”设备环境传输到“目标”设备环境(注意是从DC到DC的传输,源是来自DC而不是资源文件)。

  ②源和目标设备可以相同

  ③最重要限制是两个设备一定要“兼容”,如无法从屏幕的东西blt到打印机DC中。

  ④坐标单位和尺寸是基于逻辑单位的。而图像的尺寸cx和cy是源和目标设备共用的参数。如果当源和设备的逻辑单位不同(即映射模式不同)时,图像会被缩放,相当于StretchBlt函数,但其灵活性不如StretchBlt。

【BitBlt程序】注意由于Win7的Aero特性,标题栏等非客户区会出现毛玻璃效果,从而使该程序不能正常运行!
效果图

/*------------------------------------------------------------
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;
    WNDCLASSEX     wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_INFORMATION);
    wndclass.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("BitBlt Demo"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    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=边框+标题栏中图标按钮的宽度
        cxSource = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE);
        //cySource=边框+标题栏高度
        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); //整个窗口含非客户区的dc

        for (int y = 0; y < cyClient; y += cySource)
            for (int 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);
}

(2)StretchBlt函数:——拉伸位图

  StretchBlt(hdcDst,xDst,yDst,cxDst,cyDst,hdcSrc,xSrc,ySrc,cxSrc,cySrc, dwPOP);

  ①除拉伸外,还可以镜像图像或翻转图像。如将cxSrc或cxDst符号

  ②拉伸模式:SetStreatchBltMode(hdc,iMode)——拉伸或缩小时,像素的复制或合并

   模式

说明

BLACKONWHITE

STRETCH_ANDSCANS(默认)

如果两个或多个像素必须结合与一个像素,则进行逻辑与操作。像素都是白是,结果才是白。也就是合并的结果一般给出黑色,只有都是白色是才为白。这对白底黑色图案的单色位图来说比较好。

WHITEONBLACK

STRETCH_ORSCANS

逻辑或运算。当像素都是黑时,才是黑色。也就是合并的结果一般给出白色,只有像素都是黑色是才是黑的。这对黑底白色图像的单色位置比较好。

COLORONCOLOR

STRETCH_DELETESCANS

简单地去掉像素行或列。这对彩色位图常是最佳的方法。

HALFTONE

STRETCH_HALFTONE

结合源的颜色,计算平均目标颜色。一般和半色调色板一起使用(见第16章)

【StretchBlt程序】——注意在Win7下会出现与BitBlt程序一样的问题
效果图

/*------------------------------------------------------------
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("StretchBlt");
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX     wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_INFORMATION);
    wndclass.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("StretchBlt Demo"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    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=边框+标题栏中图标按钮的宽度
        cxSource = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE);
        //cySource=边框+标题栏高度
        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); //整个窗口含非客户区的dc

        StretchBlt(hdcClient, 0, 0, cxClient, cyClient,
                   hdcWindow, 0, 0, cxSource, cySource, SRCCOPY);

        ReleaseDC(hwnd, hdcWindow);
        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

(3)PatBlt——图案块传输:PatBlt(hdc,x,y,cx,cy,dwROP);

  ①单位都是基于逻辑单位的

  ②该函数没有源句柄,因为源为hdc中的画刷句柄。

  ③PatBlt和FillRect函数比较

应用举例

函数调用的差别

绘制黑色矩形

PatBlt(hdc,x,y,cx,cy,BLCKNESS);

FillRect(hdc,&rect,hBrush); //hBrush为黑色画刷,内部也是通过PatBlt的。

反转矩形颜色

PatBlt(hdc,x,y,cx,cy,DSTINVERT);

InvertRect(hdc,&rect);//内部调用PatBlt

14.3.2 光栅操作ROP

(1)位块传输时要涉及三个图像像素位的操作

    ①源:将源位图拉伸或压缩成目标矩形同样的大小

  ②目标:函数调用前的目标矩形

  ③图案:即目标设备上的画刷,要在横向和纵向上不断重复,直到与目标区域一样大。

(2)支持BitBlt、StretchBlt与PatBlt的光栅操作不同(见MSDN相应的函数说明)

14.3.3 单顶点和逻辑矩形问题——以PatBlt(hdc,x,y,cx,cy,dwROP)为例

(1)GDI绘图函数中,只有BitBlt、PatBlt、StretchBlt是以单个顶点加边长来规定逻辑矩形坐标的。其他的函数都要求左上角和右下角坐标。

(2)不同映射模式下顶点坐标和逻辑矩形的设置

原文地址:https://www.cnblogs.com/5iedu/p/4695503.html