• 第18章 图元文件_18.1 老式图元文件格式(wmf)


    18.1 老式图元文件格式(wmf)

    (1)创建图元文件:HDC hdcMeta = CreateMetaFile(lpszFile);

      ①如果lpszFile为NULL则图元文件存储在内存中,如果指定文件名(XXX.WMF)则存储为磁盘文件。

      ②返回值为图元文件的设备环境句柄,可以使用内存DC一样,用GDI绘图函数在其上绘图。

    (2)关闭图元文件:HMETAFILE hmf= CloseMetaFile(hdcMeta);

      ①这里不像一般的DC,创建DC后要删除DC,而是关闭。

      ②关闭图元文件的设备环境会返回该图元文件的句柄。

    (3)显示(绘制)图元文件:PlayMetaFile

      ①绘制图元文件中的各对象,即在CreateMetaFile和CloseMetaFile之间所有的GDI调用。

      ②图元文件中的函数坐标,其具体含义将由目标设备环境的当前坐标转换设置来确定。

    (4)删除图元文件句柄:DeleteMetaFile(hmf);//

    ★注意只删除图元文件句柄,并没删除磁盘上的文件。要删除文件可调用DeleteFile。

    【MetaFile程序】

     

    /*------------------------------------------------------------
       METAFILE.C -- Metafile Demonstration Program
                     (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 ("Metafile") ;
         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 ("Metafile Demonstration"), // 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)
    {
    
         PAINTSTRUCT ps ;
         static HMETAFILE hmf;
         static int cxClient, cyClient;
         HDC         hdc,hdcMeta;
         HBRUSH      hBrush;
         int x, y;
    
         switch (message)
         {
         case WM_CREATE:
              //创建图元文件设备环境(内存中)
              hdcMeta = CreateMetaFile(NULL);
    
              //创建蓝色画刷
              hBrush = CreateSolidBrush(RGB(0, 0, 255));
    
              Rectangle(hdcMeta, 0, 0, 100, 100);
    
              MoveToEx(hdcMeta, 0, 0, NULL); //左上
              LineTo(hdcMeta, 100, 100);     //右下
              MoveToEx(hdcMeta, 0, 100, NULL);//左下
              LineTo(hdcMeta, 100, 0);        //右上
    
              SelectObject(hdcMeta, hBrush);
              Ellipse(hdcMeta, 20, 20, 80, 80);
    
              //关闭图元文件设备环境,并返回图元文件句柄
              hmf = CloseMetaFile(hdcMeta);
    
              DeleteObject(hBrush);
              return 0 ;
              
         case WM_SIZE:
             cxClient = LOWORD(lParam);
             cyClient = HIWORD(lParam);
             return 0;
    
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
              
              //设置图元文件里面对象的坐标单位。
              SetMapMode(hdc, MM_ANISOTROPIC);
              SetWindowExtEx(hdc, 1000, 1000, NULL);
              SetViewportExtEx(hdc, cxClient, cyClient, NULL);
    
              //重复画图元文件100次,按10*10排列
              for (y = 0; y < 10; y++)
              for (x = 0; x < 10; x++)
              {
                  SetWindowOrgEx(hdc, -100 * x, -100 * y, NULL);
                  PlayMetaFile(hdc, hmf);
              }
            
              EndPaint (hwnd, &ps) ;
              return 0 ;
              
         case WM_DESTROY:
             DeleteMetaFile(hmf);
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    
    void PrepareMetaFile(HDC hdc, LPMETAFILEPICT pmfp, int cxClient,int cyClient)
    {
        int xScale, yScale, iScale;
    
        SetMapMode(hdc, pmfp->mm); //根据mm字段设置映射模式
    
    
        //处理MM_ISOTROPIC和MM_ANISOTROPIC情况
        if (pmfp->mm == MM_ISOTROPIC || pmfp->mm == MM_ANISOTROPIC)
        {
            if (pmfp->xExt ==0 )     //xExtyExt表示不指定图像的大小时
            {
                //在图元文件内部己经会自己调用SetWindowExtEx函数,这里无须设置。
                SetViewportExtEx(hdc, cxClient, cyClient, NULL); 
            }
            else if (pmfp->xExt >0)  //xExtyExt表示图像的大小,单位是0.01mm
            {
                SetViewportExtEx(hdc,
                                 pmfp->xExt* GetDeviceCaps(hdc, HORZRES) / 
                                             GetDeviceCaps(hdc, HORZSIZE) / 100, //将逻辑单位转为像素大小
                                             pmfp->yExt* GetDeviceCaps(hdc, VERTRES) /
                                             GetDeviceCaps(hdc, VERTSIZE) / 100, //将yExt*0.01mm转为像素大小
                                             NULL);
            }
            else if (pmfp->xExt < 0)  //xExt、yExt表示图像的比值表示纵横比。
            {
                //将图像显示区域除以图像的大小,获得缩放比
                //首先cxClient的单位为像素,乘以HORZSIZE/HORZRES,转换为像素规模所对应的毫米总数,再乘以100
                //转为单位为0.01毫米,最后再除以图像的大小,得到缩放比
                xScale = 100 * cxClient * GetDeviceCaps(hdc, HORZSIZE) /      //单位都化为0.01毫米进行比较
                                          GetDeviceCaps(hdc, HORZRES) / -pmfp->xExt;
    
                yScale = 100 * cyClient * GetDeviceCaps(hdc, VERTSIZE) /      //单位都化为0.01毫米进行比较
                    GetDeviceCaps(hdc, VERTRES) / -pmfp->yExt;
    
                iScale = min(xScale, yScale);
    
                //设置视口范围,将图像大小映射到整个显示区域
                SetViewportExtEx(hdc, -pmfp->xExt *iScale* GetDeviceCaps(hdc, HORZRES) / 
                                                           GetDeviceCaps(hdc, HORZSIZE) /100,
                                      -pmfp->yExt *iScale* GetDeviceCaps(hdc, VERTRES) /
                                                           GetDeviceCaps(hdc, VERTSIZE) /100,
                                NULL);
            }
        }
    
        //如果不是MM_ISOTROPIC或MM_ANISOTROPIC模式,则xExt和yExt的值表示图像的宽度和
        //高度,单位由mm字段的设置决定。
    }

    18.1.1 把图元文件存储到磁盘

    (1)获取磁盘中的图元文件:hmf = GetMetaFile(szFileName);

    (2)在WM_PAINT中处理完后,可以直接DeleteMetaFile(hmf);

    (3)当把图元文件定义为资源时,可以将其作为一个数据块加载。如果己经有图元文件内容的数据块,可以使用如下语句来创建图元文件。

      hmf = SetMetaFileBitsEx(iSize,pData);//根据pData的内容来创建图元文件。

      GetMetaFileBitsEx(hmf,iSize,pData);//将图元文件拷到pData内存块中。iSize为图元文件的大小。

    18.1.2 老式的图元文件和剪贴板

    (1)老式图元文件的缺点:

      ①老式图元文件中的坐标是逻辑坐标。显示时,图像大小很难确定。

      ②如果在图元文件内部设置了MM_ISOTROPIC或MM_ANISOTROPIC映射模式时,那么程序在PlayMetaFile期间用户很难干预,也就不能设置映射模式了。只能在PlayMetaFile之前或之后设置映射模式了。但图元文件内部会调用SetWindowExtEx等函数,所以,用户设置的无法真正工作。

    (2)解决方案——传入剪贴板的不是图元文件句柄,而是METAFILEPIC结构体。

    字段

    含义

    LONG mm

    映射模式

    LONG xExt

    图元文件的宽度和高度

    1. 在除MM_ISOTROPIC和MM_ANISOTROPIC映射模式下,其单位为mm字段中设置映射模式的单位。

    2. 在MM_ISOTROPIC和MM_ANISOTROPIC中,单位:0.01mm。

      ①xExt=0时,表示不指定图像的尺寸或纵横比

    ②xExt>0时,表示图像的宽度和高度。

    ③xExt<0时,其值单位仍然是0.01mm,但这种情况下,更有意义的是xExt/yExt的比值,即纵横比。

    LONG yExt

    LONG hMF

    图元文件句柄

      注意:当得到图元文件设备环境后,要在其上绘图前,一般还用调用SetWindowExtEx来指定绘图逻辑单位。但一般不包含SetMapMode、SetViewportExtEx或SetViewportOrgEx的调用。因为这些是基于显示平面的设备单位。即图元文件本身,内部一般要调用SetWindowExtEx函数,但不包含SetViewportExtEx等函数。

    (3)创建图元文件并复制到剪贴板

     //创建图元文件设备环境
    hdcMeta = CreateMetaFile(NULL); //基于内存的
    SetWindowExtEx(hdcMeta,…); //在图元文件内部设置映射模式,但不包含
    SetWindowOrgEx(hdcMeta,…); // SetMapMode或SetViewportExtEx函数。
    
    //获取该图元文件的句柄
    hmf = CloseMetaFile(hdcMeta); 
    
    //复制到剪贴板
    GLOBALHANDLE hGlobal;
    LPMETAFILEPICT pMFP;  //指向METAFILEPICT结构的指针
    hGlobal = GlobalAlloc(GHND|GMEM_SHARE,sizeof(METAFILEPICT));
    pMFP = (LPMETAFILEPICT)GlobalLock(hGlobal);
    
    //设置结构体设置
    pMFP->mm = MM_...; //使用的映射模式;
    pMFP->xExt = …;  //设置图像的宽度(逻辑单位)
    pMFP->yExt =…;
    pMPF->hMF = hmf;
    
    GlobalUnlock(hGlobal);
    
    //传送到剪贴板
    OpenClipboard(hwnd);
    EmptyClipboard();
    SetClipboardData(CF_METAFILEPICT,hGlobal);//这里传入的是METAFILEPIC结构,而不是hmf;
    CloseClipboard();  //至此,hGlobal和hmf句柄失效,不能再使用它们了。

    (4)从剪贴板中获取图元文件,并显示。

    //获取METAFILEPICT结构体
    OpenClipboard(hwnd);
    hGlobal = GetClipboardData(CF_METAFILEPICT);
    pMFP->(LPMETAFILEPICT)GlobalLock(hGlobal);
    
    SaveDC(hdc);
    //根据mm、xExt、yExt设置映射模式
    PrepareMetaFile(hdc,pMFP,cxClient,cyClient); //其中cxClient,cyClient为图元文件要显示的像素宽度和高度。该函数是自定义的,见后面的代码实现。
    PlayMetaFile(pMFP->hMF);
    RestoreDC(hdc,-1);
    
    GlobalUnlock(hGlobal);
    CloseClipboard();
    
    (4)PrepareMetaFile函数的分析
     void PrepareMetaFile(HDC hdc, LPMETAFILEPICT pmfp, int cxClient,int cyClient)
    {
        int xScale, yScale, iScale;
    
        SetMapMode(hdc, pmfp->mm); //根据mm字段设置映射模式
    
    
        //处理MM_ISOTROPIC和MM_ANISOTROPIC情况
        if (pmfp->mm == MM_ISOTROPIC || pmfp->mm == MM_ANISOTROPIC)
        {
            if (pmfp->xExt ==0 )     //xExtyExt表示不指定图像的大小时
            {
                //在图元文件内部己经会自己调用SetWindowExtEx函数,这里无须设置。
                SetViewportExtEx(hdc, cxClient, cyClient, NULL); 
            }
            else if (pmfp->xExt >0)  //xExtyExt表示图像的大小,单位是0.01mm
            {
                SetViewportExtEx(hdc,
                                 pmfp->xExt* GetDeviceCaps(hdc, HORZRES) / 
                                             GetDeviceCaps(hdc, HORZSIZE) / 100, //将逻辑单位转为像素大小
                                             pmfp->yExt* GetDeviceCaps(hdc, VERTRES) /
                                             GetDeviceCaps(hdc, VERTSIZE) / 100, //将yExt*0.01mm转为像素大小
                                             NULL);
            }
            else if (pmfp->xExt < 0)  //xExt、yExt表示图像的比值表示纵横比。
            {
                //将图像显示区域除以图像的大小,获得缩放比
                //首先cxClient的单位为像素,乘以HORZSIZE/HORZRES,转换为像素规模所对应的毫米总数,再乘以100
                //转为单位为0.01毫米,最后再除以图像的大小,得到缩放比
                xScale = 100 * cxClient * GetDeviceCaps(hdc, HORZSIZE) /      //单位都化为0.01毫米进行比较
                                          GetDeviceCaps(hdc, HORZRES) / -pmfp->xExt;
    
                yScale = 100 * cyClient * GetDeviceCaps(hdc, VERTSIZE) /      //单位都化为0.01毫米进行比较
                    GetDeviceCaps(hdc, VERTRES) / -pmfp->yExt;
    
                iScale = min(xScale, yScale);
    
                //设置视口范围,将图像大小映射到整个显示区域
                SetViewportExtEx(hdc, -pmfp->xExt *iScale* GetDeviceCaps(hdc, HORZRES) / 
                                                           GetDeviceCaps(hdc, HORZSIZE) /100,
                                      -pmfp->yExt *iScale* GetDeviceCaps(hdc, VERTRES) /
                                                           GetDeviceCaps(hdc, VERTSIZE) /100,
                                NULL);
            }
        }
    
        //如果不是MM_ISOTROPIC或MM_ANISOTROPIC模式,则xExt和yExt的值表示图像的宽度和
        //高度,单位由mm字段的设置决定。
    }

    (5)Windows剪贴板会自动进行老格式和增强型格式之间的转换。是否转换,要看用户从剪贴板请求的文件格式。

  • 相关阅读:
    Structured streaming
    streaming窗口操作
    scala伴生对象,apply()及单例
    storm集成kafka
    solr简易安装配置
    拦路雨偏似雪花,饮泣的你冻吗?--稍瑞,我是关键字过滤器
    我存在,你深深的循环里--从反射看JSON死循环
    ueditor:原谅我这一生不羁放纵爱独特
    或许你不知道(2):LinkedList
    自定义负载均衡
  • 原文地址:https://www.cnblogs.com/5iedu/p/4706324.html
Copyright © 2020-2023  润新知