zoukankan      html  css  js  c++  java
  • 第18章 图元文件_18.2 增强型图元文件(emf)(1)

    18.2 增强型图元文件(emf)

    18.2.1 创建并显示增强型图元文件的步骤

    (1)创建:hdcEMF = CreateEnhMetaFile(hdcRef,szFilename,lpRect,lpDescription);

    参数

    含义

    hdcRef

    参考设备环境,NULL时表示以屏幕为参考

    szFileName

    指定文件名时,创建磁盘文件(.EMF)。为NULL时创建内存图元文件

    lpRect

    用于描述图元文件的大小和位置(以0.01mm为单位),可用它精确定义图元文件的物理尺寸

    lpDescription

    对图元文件的一段说明。包括创建应用程序的名字、一个NULL字符、对图元文件的一段说明以及两个NULL字符。

    返回值

    增强型图元文件DC。(注意不是图元文件的句柄,要获得实际的图元文件句柄,得调用CloseEnhMetaFile函数)

    (2)关闭图元文件hEmf = CloseEnhMetaFile(hdcEMF);返回图元文件句柄

    (3)显示图元文件 PlayEnhMetaFile(hdc,hEmf,&rect);

    参数

    含义

    hdc

    设备环境句柄

    hEmf

    图元文件句柄

    lpRect

    指定显示区域(逻辑单位),GDI会缩放图像以适应该矩形范围

    (4)删除图元文件 DeleteEnhMetaFile(hEmf);

    【Emf1程序】

      ①创建图元文件时,矩形和画线的坐标大小并不重要,重要的是坐标间的对应关系。可以将他们同时加倍或同时减去一个常数,结果是一样的。

      ②图像会被拉伸,以满足PlayEnhMetaFile函数中指定的矩形尺寸。

      ③这个例子中,图形的对角线会出现不完全落在顶点上,这是Windows在存储图元文件中坐标的处理方式造成的,会在后面加以解决。

     

    /*------------------------------------------------------------
       EMF1.C -- Enhanced Metafile Demo #1
                     (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 ("EMF1") ;
         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_APPLICATION) ;
         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,                  // window class name
                              TEXT ("Enhanced Metafile Demo #1"), // 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 HENHMETAFILE hEmf;
         HDC         hdc,hdcEMF;
         PAINTSTRUCT ps ;
         RECT        rect ;
         
         switch (message)
         {
         case WM_CREATE:
              hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL);  //4个参数全为NULL
    
              Rectangle(hdcEMF, 100, 100, 200, 200);
    
              MoveToEx(hdcEMF, 100, 100, NULL); //左上——右下
              LineTo(hdcEMF, 200, 200);
    
              MoveToEx(hdcEMF, 200, 100, NULL); //右上——左下
              LineTo(hdcEMF, 100, 200);
    
              hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,并保存在静态变量中
              return 0 ;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rect) ;
              
              rect.left = rect.right / 4;
              rect.right = 3 * rect.right / 4;
              rect.top = rect.bottom / 4;
              rect.bottom = 3 * rect.bottom / 4;
    
              PlayEnhMetaFile(hdc, hEmf, &rect); //在指定的rect区域内显示图元文件
              
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
              DeleteEnhMetaFile(hEmf); //删除内存中的图元文件
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

    18.2.2 窥探增强型图元文件的内部机制

    (1)实例图解增强型EMF文件结构

     

    (2)文件结构:头记录(ENHMETAHEADER)、各记录(ENHMETARECORD)、文件结尾(EMR_EOF)

      ①头记录ENHMETAHEADER

    偏移量

    字段

    含义

    0x00

    DWORD iType;

    总是等于EMR_HEADER(即1)

    0x04

    DWORD nSize;

    结构的大小。如本例0x90,注意这个大小是含描述字符串的长度,即等于sizeof(ENHMETAHEADER)+nDescription*2

    0x08

    RECTL rclBounds;

    以像素为单位的矩形边框:

    如左上角(100,100),右下角(200,200)

    0x18

    RECTL rclFrame;

    以0.01mm为单位的图像尺寸

    如本例(0x09D6,0x09DE)即(2518,2526)

    由HORZSIZE/HORZRES或VERTSIZE/VERTRES换算得来。

    0x28

    DWORD dSignature;

    ENHMETA_SIGNATURE=“EMF”,即0x464D4520

    0x2C

    DWORD nVersion;

    0x00010000

    0x30

    DWORD nBytes;

    以字节为单位的文件总长度。本例0xFC

    0x34

    DWORD nRecords;

    文件含有的记录数。本例0x0000007。一个头记录、五个GDI函数调用和一个文件结束记录

    0x38

    WORD  nHandles;

    句柄表中的句柄数。本例为0x0001。通常表示在图元文件中使用的GDI对象(如画笔、画刷、字体)的非默认句柄的数目。GDI为自己保留了第一个,所以本例为1。

    0x3A

    WORD  sReserved;

    0x3C

    DWORD nDescription;

    描述字符串的字符的个数。本例为0x12(18)个,注意含。

    0x40

    DWORD offDescription;

    描述字符串在文件中的起始偏移位置,跟在szlMicrometers字段的后面。本例为0x0000006C。注意,每个字符用UNICODE编码(占2个字节)。

    0x44

    DWORD nPalEntries;

    调色板的颜色条目的个数。本例为0

    0x48

    SIZEL szlDevice;

    以像素为单位的设备分辨率。这里的设备由CreatEnhMetaFile函数的第一个参数,为NULL时表示屏幕设备1366×768,该值等于GetDeviceCaps的HORZRES和VERTRES。

    0x50

    SIZEL szlMillimeters;

    以mm为单位的设备分辨率。本例为344×194。该值等GetDeviceCaps的HORZSIZE和VERTSIZE。

    0x58

    DWORD cbPixelFormat;

    像素格式的尺寸

    0x5C

    DWORD offPixelFormat;

    像素格式的起始偏移位置

    0x60

    DWORD bOpenGL;

    在不含OpenGL记录时,该值为FALSE

    0x64

    SIZEL szlMicrometers

    参考设备的尺寸(单位:微米)。本例344000和194000

      ②每条记录(ENHMEARECORD)——一般记录GDI函数的调用

    字段

    含义

    DWORD iType

    记录类型(如Rectangle、MoveToEx、SetWindowExtEx等)

    在WINGDI.H中定义,以EMR_开头

    DWORD nSize

    该记录的长度

    DWORD dParm[1]

    存放参数的数组(一个或多个dParam字段)

      ③文件结尾(EMR_EOF):20字节

    【EMF2程序】

    /*------------------------------------------------------------
       EMF2.C -- Enhanced Metafile Demo #2
                     (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 ("EMF2") ;
         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_APPLICATION) ;
         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,                  // window class name
                              TEXT ("Enhanced Metafile Demo #2"), // 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)
    {
         HENHMETAFILE hEmf;
         HDC         hdc,hdcEMF;
         PAINTSTRUCT ps ;
         RECT        rect ;
         
         switch (message)
         {
         case WM_CREATE:
        
              hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf2.emf"), NULL, TEXT("EMF2EMF Demo #2"));
              if (!hdcEMF)
                  return 0;
    
              Rectangle(hdcEMF, 100, 100, 200, 200);
    
              MoveToEx(hdcEMF, 100, 100, NULL); //左上——右下
              LineTo(hdcEMF, 200, 200);
    
              MoveToEx(hdcEMF, 200, 100, NULL); //右上——左下
              LineTo(hdcEMF, 100, 200);
    
              hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,这里不用静态.
                                               
              DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
              return 0 ;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rect) ;
              
              rect.left = rect.right / 4;
              rect.right = 3 * rect.right / 4;
              rect.top = rect.bottom / 4;
              rect.bottom = 3 * rect.bottom / 4;
    
              if (hEmf = GetEnhMetaFile(TEXT("emf2.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
              {
                   PlayEnhMetaFile(hdc, hEmf, &rect); //在指定的rect区域内显示图元文件
                   DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
              }
         
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

    18.2.3 图元文件和GDI对象

    (1)如何存储GDI对象(如,画笔、画刷,注意不是GDI绘图命令)

    (2)创建画笔、画刷的调用会被存储到图元文件内部。这些非备用的GDI对象会被从1开始编号。

    (3)图元文件也会存储SelectObject和DeleteObject等函数调用

    (4)EMREXTCREATEPEN结构体

    字段

    含义

    EMR  emr

    包含emr.iType和emr.nSize,是图元文件的基本结构

    DWORD ihPen

    图元文件GDI对象句柄表中的索引值

    DWORD offBmi

    如果指定位图时,表示位图相对于该记录的偏移

    DWORD cbBmi

    如果指定位图时,表示位图的大小(单位:字节)

    DWORD offBits

    如果指定位图时,表示画笔位图的像素数据的相对该记录的偏移

    DWORD cbBits

    位图像素数据的大小(单位:字节)

    EXTLOGPEN elp;

    扩展的逻辑画笔

    (5)EXTLOGPEN结构体

    字段

    含义

    DWORD  elpPenStyle

    可取PS_GEOMETRIC、PS_COSMETIC、PS_DASH等

    DWORD  elpWidth

    当指定为PS_GEOMETRIC时,表示画笔的宽度(逻辑单位),否则为1,表示1像素的宽度。

    UINT   elpBrushStyle

    画笔的画刷样式,如BS_HATCHED、BS_SOLID

    COLORREF  elpColor

    画笔颜色

    ULONG_PTR elpHatch

    当elpBrushStyle为BS_PATTERN时,指向位图的句柄。

    当elpBrushStyle为BS_SOLID或BS_HOLLOW时,则忽略。

    DWORD  elpNumEntries

    调色板的条目数。如果elpPenStyle没有指定为PS_USERSTYLE,则该值为0

    DWORD  elpStyleEntry[1]

    调色板颜色数组

     【图解GDI对象存储】

    【EMF3程序】

     

    /*------------------------------------------------------------
       EMF3.C -- Enhanced Metafile Demo #3
                     (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 ("EMF3") ;
         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_APPLICATION) ;
         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,                  // window class name
                              TEXT ("Enhanced Metafile Demo #3"), // 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)
    {
         HENHMETAFILE hEmf;
         HDC         hdc,hdcEMF;
         PAINTSTRUCT ps ;
         RECT        rect ;
         LOGBRUSH   lb;
         
         switch (message)
         {
         case WM_CREATE:
    
              hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf3.emf"), NULL, TEXT("EMF3EMF Demo #3"));
              if (!hdcEMF)
                  return 0;
    
              //创建并选入画刷
              SelectObject(hdcEMF, CreateSolidBrush(RGB(0, 0, 255)));
    
              lb.lbStyle = BS_SOLID;
              lb.lbColor = RGB(255, 0, 0);
              lb.lbHatch = 0;
    
              //创建并选入画笔
              SelectObject(hdcEMF, ExtCreatePen(PS_SOLID | PS_GEOMETRIC, 5, &lb, 0, NULL));
    #if(WINVER < 0x0400)    //win98
    
                  Rectangle(hdcEMF, 100, 100, 201, 201);
    #else
    
                  Rectangle(hdcEMF, 101, 101, 202, 202);
    #endif
              Rectangle(hdcEMF, 100, 100, 200, 200);
    
              MoveToEx(hdcEMF, 100, 100, NULL); //左上——右下
              LineTo(hdcEMF, 200, 200);
    
              MoveToEx(hdcEMF, 200, 100, NULL); //右上——左下
              LineTo(hdcEMF, 100, 200);
    
              DeleteObject(SelectObject(hdcEMF, GetStockObject(BLACK_PEN)));
              DeleteObject(SelectObject(hdcEMF, GetStockObject(WHITE_BRUSH)));
    
              hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,这里不用静态.
                                               
              DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
              return 0 ;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rect) ;
              
              rect.left = rect.right / 4;
              rect.right = 3 * rect.right / 4;
              rect.top = rect.bottom / 4;
              rect.bottom = 3 * rect.bottom / 4;
    
              if (hEmf = GetEnhMetaFile(TEXT("emf3.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
              {
                   PlayEnhMetaFile(hdc, hEmf, &rect); //在指定的rect区域内显示图元文件
                   DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
              }
         
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

    18.2.4 图元文件和位图

    (1)GDI会与设备相关的位图自动转换 为与设备无关的位图(DIB)。

    (2)调用StretchBlt时,图元文件内部使用的是StretchDIBits函数,而不是StretchBlt。

    (3)EMR_STRETCH记录的长度达4024字节,这里包含了紧缩型的DIB位图数据。

    (4)EMRSTRETCH结构体

    字段

    含义

    EMR emr

    包含两个DWORD型的字段emr.iType和emr.nSize,该字段是所有图元文件记录的基本结构。

    RECTL rclBounds

    边界矩形(单位:设备单位)

    LONG xDest

    目标矩形的左上角x坐标(逻辑单位)

    LONG yDest

    目标矩形的左上角y坐标(逻辑单位)

    LONG cxDest

    目标矩形的宽度(逻辑单位)

    LONG cyDest

    目标矩形的高度(逻辑单位)

    DWORD dwRop

    光栅操作码

    LONG  xSrc

    源矩形的左上角x坐标(逻辑单位)

    LONG  ySrc

    源矩形的左上角y坐标(逻辑单位)

    XFORM  xformSrc

    世界坐标到逻辑坐标的变换矩阵

    typedef struct  tagXFORM {  /* xfrm */

        FLOAT eM11;

        FLOAT eM12;

        FLOAT eM21;

        FLOAT eM22;

        FLOAT eDx;

        FLOAT eDy;

    } XFORM;

    COLORREF crBkColorSrc

    源设备环境DC的背景颜色,是个RGB值。

    DWORD iUsageSrc

    BITMAPINFO结构体的bmiColors字段。可取如下值:DIB_PAL_COLORS或DIB_RGB_COLORS。

    DWORD offBmiSrc

    BITMAPINFO结构的偏移

    DWORD cbBmiSrc

    BITMAPINFO结构体的大小

    DWORD offBitsSrc

    位图像素数据的偏移

    DWORD cbBitsSrc

    像素数据的多少(单位:字节)

    LONG  cxSrc

    源矩形的宽度

    LONG  cySrc

    源矩形的高度

     【EMF4程序】

    /*------------------------------------------------------------
       EMF4.C -- Enhanced Metafile Demo #4
                     (c) Charles Petzold, 1998
      ------------------------------------------------------------*/
    #define OEMRESOURCE   //要定义这个,才能使用OBM_CLOSE图标
    #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 ("EMF4") ;
         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_APPLICATION) ;
         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,                  // window class name
                              TEXT ("Enhanced Metafile Demo #4"), // 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)
    {
         HENHMETAFILE hEmf;
         HDC         hdc,hdcEMF,hdcMem;
         PAINTSTRUCT ps ;
         RECT        rect ;
         HBITMAP     hbm;
         BITMAP      bm;
         
         switch (message)
         {
         case WM_CREATE:
    
              hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf4.emf"), NULL, TEXT("EMF4EMF Demo #4"));
              if (!hdcEMF)
                  return 0;
    
              hbm = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE));
    
              GetObject(hbm, sizeof(BITMAP), &bm);
    
              hdcMem = CreateCompatibleDC(hdcEMF);
              SelectObject(hdcMem, hbm);
    
              //只有这个GDI函数才会被写到图元文件中
              StretchBlt(hdcEMF, 100, 100, 100, 100, 
                         hdcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
    
              DeleteDC(hdcMem);
              DeleteObject(hbm);
    
              hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,这里不用静态.
    
    
              DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
              return 0 ;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rect) ;
              
              rect.left = rect.right / 4;
              rect.right = 3 * rect.right / 4;
              rect.top = rect.bottom / 4;
              rect.bottom = 3 * rect.bottom / 4;
    
              if (hEmf = GetEnhMetaFile(TEXT("emf4.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
              {
                   PlayEnhMetaFile(hdc, hEmf, &rect); //在指定的rect区域内显示图元文件
                   DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
              }
         
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

     【 图解EMF4.emf文件结构】

     18.2.5 枚举图元文件

    (1)枚举函数EnumEnhMetaFile

    参数

    含义

    HDC hdc

    显示图元文件的设备环境句柄

    HENHMETAFILE hemf

    图元文件句柄

    ENHMFENUMPROC lpEnhMetaFunc

    枚举回调函数,每读取一条记录,会调用一次该函数。包括头记录和文件结束记录。通常返回TRUE,返回FALSE时结束枚举过程。

    LPVOID lpData

    传给枚举回调函数的额外参数

    CONST RECT *lpRect

    在指定的矩形区内显示图元文件

    (2)枚举回调函数——自定义的,要作为EnumEnhMetaFile函数的第3个参数。

    参数

    含义

    HDC hdc

    显示图元文件的设备环境句柄

    HANDLETABLE *lpHTable

    指向HANDLETABLE结构体,这里存储了图元文件中用到的所有的非备用GDI对象的句柄。可以用指针读取出来,如lpHTable->objectHandles[2]读取编号为2的GDI对象。

    Typedef struct tagHANDLETABLE

    {

        HGIDOBJ objectHandle[1];

    }HANDLETABLE。

    CONST ENHMETARECORD *lpEMFR

    该结构前面己经解释过来,主要用来描述每个记录的类型,长度及一个或多个参数。

    int nObj

    图元文件中用到的非备用GDI对象的句柄数量。如用到了画笔和画刷,则nObj=3。(2+1)

    LPARAM lpData

    额外数据

       ▲本例中共有3个GDI对象的句柄,编号为0、1、2。

      ①当第1次调用枚举回调函数时,HANDLETABLE中的第1个元素为图元文件的句柄,第2、3个元素设为0,表示为本例中用到的画笔和画刷预留位置。

      ②PlayEnhMetaFileRecord时读取到EMR_CREATEBRUSHINDIRECT时,会创建第1个GDI对象(编号为1),即新建一个画刷,并把这个画刷存储在lpHTable->objectHandles[1]中。

      ③当PlayEnhMetaFileRecord到EMR_SELECTOBJECT记录时,GDI会从HANDLETABLE结构体中读取到这个GDI对象的实际句柄,并传给SelectObject函数。

      ④当PlayEnhMetaFileRecord读到EMR_DELETEOBJECT时,会将该数组lpHTable->objectHandles[1]置0.

    (3)PlayEnhMetaFileRecord函数——回放单独一条增强型图元文件记录。

    【Emf5程序】

    /*------------------------------------------------------------
       EMF5.C -- Enhanced Metafile Demo #5
                     (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 ("EMF5") ;
         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_APPLICATION) ;
         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,                  // window class name
                              TEXT ("Enhanced Metafile Demo #5"), // 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 ;
    }
    
    int CALLBACK EnhMetaFileProc(HDC hdc, HANDLETABLE* pHandleTable, CONST ENHMETARECORD* pEmfRecord,
        int iHandles, LPARAM pData)
    {
        PlayEnhMetaFileRecord(hdc, pHandleTable, pEmfRecord, iHandles);
        return TRUE;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         HENHMETAFILE hEmf;
         HDC         hdc,hdcEMF;
         PAINTSTRUCT ps ;
         RECT        rect ;
         LOGBRUSH   lb;
         
         switch (message)
         {
         case WM_CREATE:
    
              hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf5.emf"), NULL, TEXT("EMF5EMF Demo #5"));
              if (!hdcEMF)
                  return 0;
    
              //创建并选入画刷
              SelectObject(hdcEMF, CreateSolidBrush(RGB(0, 0, 255)));
    
              lb.lbStyle = BS_SOLID;
              lb.lbColor = RGB(255, 0, 0);
              lb.lbHatch = 0;
    
              //创建并选入画笔
              SelectObject(hdcEMF, ExtCreatePen(PS_SOLID | PS_GEOMETRIC, 5, &lb, 0, NULL));
    #if(WINVER < 0x0400)    //win98
    
                  Rectangle(hdcEMF, 100, 100, 201, 201);
    #else
    
                  Rectangle(hdcEMF, 101, 101, 202, 202);
    #endif
              Rectangle(hdcEMF, 100, 100, 200, 200);
    
              MoveToEx(hdcEMF, 100, 100, NULL); //左上——右下
              LineTo(hdcEMF, 200, 200);
    
              MoveToEx(hdcEMF, 200, 100, NULL); //右上——左下
              LineTo(hdcEMF, 100, 200);
    
              DeleteObject(SelectObject(hdcEMF, GetStockObject(BLACK_PEN)));
              DeleteObject(SelectObject(hdcEMF, GetStockObject(WHITE_BRUSH)));
    
              hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,这里不用静态.
                                               
              DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
              return 0 ;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rect) ;
              
              rect.left = rect.right / 4;
              rect.right = 3 * rect.right / 4;
              rect.top = rect.bottom / 4;
              rect.bottom = 3 * rect.bottom / 4;
    
              if (hEmf = GetEnhMetaFile(TEXT("emf5.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
              {
                   //与EMF3程序不同,这里使用枚举函数,而不使用PlayEnhMetaFile
                   //PlayEnhMetaFile(hdc, hEmf, &rect);
                   EnumEnhMetaFile(hdc, hEmf, EnhMetaFileProc, NULL, &rect); 
                   DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
              }
         
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

    【Emf6程序】

    /*------------------------------------------------------------
    EMF6.C -- Enhanced Metafile Demo #6
    (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("EMF6");
        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_APPLICATION);
        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,                  // window class name
            TEXT("Enhanced Metafile Demo #6"), // 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;
    }
    
    //自定义的枚举图元文件的回调函数。
    int CALLBACK EnhMetaFileProc(HDC hdc, HANDLETABLE* pHandleTable, CONST ENHMETARECORD* pEmfRecord,
        int iHandles, LPARAM pData)
    {
        ENHMETARECORD* pEmfr;  //因为pEmfRecord所指的对象为CONST类型,不可修改。
    
        //因记录为CONST不可修改,为了修改该记录,需复制一个记录出来,并保存指针到pEmfr中
        pEmfr = malloc(pEmfRecord->nSize);
        CopyMemory(pEmfr, pEmfRecord, pEmfRecord->nSize);
    
        //将原来的矩形改为椭圆
        if (pEmfr->iType == EMR_RECTANGLE)
            pEmfr->iType = EMR_ELLIPSE;
    
        if (pEmfr->iType != EMR_LINETO)  //去掉“X”中的两条线,只画出椭圆,并填充
        {
            PlayEnhMetaFileRecord(hdc, pHandleTable, pEmfr, iHandles); //回放显示某条记录
        }
    
        free(pEmfr);
    
        return TRUE;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HENHMETAFILE hEmf;
        HDC         hdc, hdcEMF;
        PAINTSTRUCT ps;
        RECT        rect;
        LOGBRUSH   lb;
    
        switch (message)
        {
        case WM_CREATE:
    
            hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf6.emf"), NULL, TEXT("EMF6EMF Demo #6"));
            if (!hdcEMF)
                return 0;
    
            //创建并选入画刷
            SelectObject(hdcEMF, CreateSolidBrush(RGB(0, 0, 255)));
    
            lb.lbStyle = BS_SOLID;
            lb.lbColor = RGB(255, 0, 0);
            lb.lbHatch = 0;
    
            //创建并选入画笔
            SelectObject(hdcEMF, ExtCreatePen(PS_SOLID | PS_GEOMETRIC, 5, &lb, 0, NULL));
    #if(WINVER < 0x0400)    //win98
    
            Rectangle(hdcEMF, 100, 100, 201, 201);
    #else
    
            Rectangle(hdcEMF, 101, 101, 202, 202);
    #endif
            Rectangle(hdcEMF, 100, 100, 200, 200);
    
            MoveToEx(hdcEMF, 100, 100, NULL); //左上——右下
            LineTo(hdcEMF, 200, 200);
    
            MoveToEx(hdcEMF, 200, 100, NULL); //右上——左下
            LineTo(hdcEMF, 100, 200);
    
            DeleteObject(SelectObject(hdcEMF, GetStockObject(BLACK_PEN)));
            DeleteObject(SelectObject(hdcEMF, GetStockObject(WHITE_BRUSH)));
    
            hEmf = CloseEnhMetaFile(hdcEMF); //返回图元文件句柄,这里不用静态.
    
            DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
            return 0;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            GetClientRect(hwnd, &rect);
    
            rect.left = rect.right / 4;
            rect.right = 3 * rect.right / 4;
            rect.top = rect.bottom / 4;
            rect.bottom = 3 * rect.bottom / 4;
    
            if (hEmf = GetEnhMetaFile(TEXT("emf6.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
            {
                //与EMF3程序不同,这里使用枚举函数,而不使用PlayEnhMetaFile
                EnumEnhMetaFile(hdc, hEmf, EnhMetaFileProc, NULL, &rect);
                DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    18.2.6 嵌入图像的方法

    (1)将源图元文件的设备环境句柄当作第1个参数传递给函数EnumEnhMetaFile。

    (2)在枚举回调函数里,就可以在这个设备环境里进行绘图。(也可以用PlayEnhMetaFile函数,将整个图元文件插件到现有的图元文件( PlayEnhMetaFile(hdcEMF,hemfOld,&rect))

    (3)当使用自定义的画笔或画刷绘制某个图形后,要进行恢复原来的画笔、画刷。

    【Emf7程序】

    /*------------------------------------------------------------
    EMF7.C -- Enhanced Metafile Demo #7
    (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("EMF7");
        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_APPLICATION);
        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,                  // window class name
            TEXT("Enhanced Metafile Demo #7"), // 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;
    }
    
    //自定义的枚举图元文件的回调函数。
    int CALLBACK EnhMetaFileProc(HDC hdc, HANDLETABLE* pHandleTable, CONST ENHMETARECORD* pEmfRecord,
        int iHandles, LPARAM pData)
    {
        HBRUSH hBrush;
        HPEN hPen;
        LOGBRUSH lb;
    
        //回放旧文件中除头记录和文件结束记录外的所有记录。
        if (pEmfRecord->iType != EMR_HEADER && pEmfRecord->iType != EMR_EOF)
            PlayEnhMetaFileRecord(hdc, pHandleTable, pEmfRecord, iHandles);
    
        
        if (pEmfRecord->iType == EMR_RECTANGLE)
        {
            hBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); //透明画刷
    
            //创建新画笔,并保留旧画笔到hPen中。
            lb.lbStyle = BS_SOLID;
            lb.lbColor = RGB(0, 255, 0); //绿色画笔
            lb.lbHatch = 0;
            hPen = SelectObject(hdc, 
                               ExtCreatePen(PS_SOLID|PS_GEOMETRIC,5,&lb,0,NULL));
    
            Ellipse(hdc, 100, 100, 200, 200);
    
            DeleteObject(SelectObject(hdc, hPen)); //选入旧画笔,并删除自己创建的画笔
            SelectObject(hdc, hBrush); //备用画刷不用删除
        }
    
        return TRUE;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        ENHMETAHEADER emh;
        HENHMETAFILE hEmf,hEmfOld;
        HDC         hdc, hdcEMF;
        PAINTSTRUCT ps;
        RECT        rect;
    
    
        switch (message)
        {
        case WM_CREATE:
    
            //获取emf3图元文件和头记录
            hEmfOld = GetEnhMetaFile(TEXT("emf3.emf"));
            GetEnhMetaFileHeader(hEmfOld, sizeof(ENHMETAHEADER), &emh);  //唯一目标是要获取rclBounds字段
    
            //创建新的图元文件DC
            hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf7.emf"), NULL, TEXT("EMF7EMF Demo #7"));
            if (!hdcEMF)
                return 0;
    
            //将旧的emf3图元文件绘制新的hdcEMF中。(即回放)
            EnumEnhMetaFile(hdcEMF, hEmfOld, EnhMetaFileProc, NULL,(RECT*)&emh.rclBounds);
    
            //返回图元文件句柄,这里不用静态.
            hEmf = CloseEnhMetaFile(hdcEMF);
    
            DeleteEnhMetaFile(hEmfOld);
            DeleteEnhMetaFile(hEmf); //直接删除,在WM_PAINT中,要从磁盘中读取该文件,与EMF1程序不同
            return 0;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            GetClientRect(hwnd, &rect);
    
            rect.left = rect.right / 4;
            rect.right = 3 * rect.right / 4;
            rect.top = rect.bottom / 4;
            rect.bottom = 3 * rect.bottom / 4;
    
            if (hEmf = GetEnhMetaFile(TEXT("emf7.emf"))) //这里从磁盘中加载进来,与EMF1程序不同
            {
                PlayEnhMetaFile(hdc, hEmf, &rect);
                DeleteEnhMetaFile(hEmf); //显示完就删除该图元文件
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
  • 相关阅读:
    织梦开发——相关阅读likeart应用
    织梦标签教程
    织梦专题调用代码
    HIT 2543 Stone IV
    POJ 3680 Intervals
    HIT 2739 The Chinese Postman Problem
    POJ 1273 Drainage Ditches
    POJ 2455 Secret Milking Machine
    SPOJ 371 Boxes
    HIT 2715 Matrix3
  • 原文地址:https://www.cnblogs.com/5iedu/p/4706327.html
Copyright © 2011-2022 走看看