第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)个,注意含\0。


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("EMF2\0EMF Demo #2\0"));
          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("EMF3\0EMF Demo #3\0"));
          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("EMF4\0EMF Demo #4\0"));
          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("EMF5\0EMF Demo #5\0"));
          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("EMF6\0EMF Demo #6\0"));
        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("EMF7\0EMF Demo #7\0"));
        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);
}
时间: 2024-08-04 09:35:39

第18章 图元文件_18.2 增强型图元文件(emf)(1)的相关文章

第18章 图元文件_18.2 增强型图元文件(emf)(2)

18.2.7 增强型图元文件的查看和打印程序 (1)传递EMF到剪贴板,剪贴板类型应为:CF_ENHMETAFILE (2)CopyEnhMetaFile用于复制图元文件 (3)剪贴板中的图元文件会自动在老式与增强型图元文件间转换. (4)自定义函数CreatePaletteFromMetaFile用于从图元文件中创建逻辑调色板. [EmfView程序]      /*------------------------------------------------------------ EMF

《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记

章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(1)-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(2)-读书笔记 <TCP/IP详解卷1:协议>第4章 ARP:地址解析协议-读书笔记 <TCP/IP详解卷1:协议>第5章 RARP:逆地址解析协议-读书笔记 <TCP/IP详解卷1:协

设计模式之第18章-观察者模式(Java实现)

设计模式之第18章-观察者模式(Java实现) 话说曾小贤,也就是陈赫这些天有些火,那么这些明星最怕的,同样最喜欢的是什么呢?没错,就是狗仔队.英文的名字比较有意思,是paparazzo,这一说法据说来自意大利电影<滴露牡丹开>中一个专门偷拍明星照片的一个摄影师的名字,“Paparazzo”,中文译为帕帕拉齐,俗语就是狗仔队.这些明星因狗仔队而荣,获得曝光率,也因狗仔队而损,被曝光负面新闻,不管怎么说,总之是“火起来了”,让明星们又爱又恨.(众人:鱼哥,你扯远了).咳咳,这个狗仔队其实嘛,也就

《Cracking the Coding Interview》——第18章:难题——题目10

2014-04-29 04:22 题目:给定一堆长度都相等的单词,和起点.终点两个单词,请从这堆单词中寻找一条变换路径,把起点词变成终点词,要求每次变换只能改一个字母. 解法:Leetcode中有Word Ladder,这题基本思路一致. 代码: 1 // 18.10 Given a list of words, all of same length. Given a source and a destionation words, you have to check if there exis

《Cracking the Coding Interview》——第18章:难题——题目9

2014-04-29 04:18 题目:有一连串的数被读入,设计一个数据结构,能随时返回当前所有数的中位数. 解法:用一个大顶堆,一个小顶堆将数分成数量最接近的两份,就能轻松得到中位数了. 代码: 1 // 18.9 A stream of integers are passed to you, you have to tell me the median as they keep coming in. 2 #include <climits> 3 #include <iostream&

《Cracking the Coding Interview》——第18章:难题——题目13

2014-04-29 04:40 题目:给定一个字母组成的矩阵,和一个包含一堆单词的词典.请从矩阵中找出一个最大的子矩阵,使得从左到右每一行,从上到下每一列组成的单词都包含在词典中. 解法:O(n^3)级别的时间和空间进行动态规划.这道题目和第17章的最后一题很像,由于这题的时间复杂度实在是高,我动手写了字典树进行加速.如果单纯用哈希表来作为词典,查询效率实际会达到O(n)级别,导致最终的算法复杂度为O(n^4).用字典树则可以加速到O(n^3),因为对于一个字符串"abcd",只需要

《Cracking the Coding Interview》——第18章:难题——题目11

2014-04-29 04:30 题目:给定一个由'0'或者'1'构成的二维数组,找出一个四条边全部由'1'构成的正方形(矩形中间可以有'0'),使得矩形面积最大. 解法:用动态规划思想,记录二维数组每个元素向上下左右四个方向各有多少个连续的'1',然后用O(n^3)时间计算出满足条件的最大正方形.时间复杂度O(n^3),空间复杂度O(n^2). 代码: 1 // 18.11 Given an NxN matrix of 0s and 1s, find out a subsquare whose

《Cracking the Coding Interview》——第18章:难题——题目12

2014-04-29 04:36 题目:最大子数组和的二位扩展:最大子矩阵和. 解法:一个维度上进行枚举,复杂度O(n^2):另一个维度执行最大子数组和算法,复杂度O(n).总体时间复杂度为O(n^3),还需要O(n)额外空间. 代码: 1 // 18.12 Given an n x n matrix, find the submatrix with largest sum. Return the sum as the result. 2 #include <algorithm> 3 #inc

《Cracking the Coding Interview》——第18章:难题——题目6

2014-04-29 02:27 题目:找出10亿个数中最小的100万个数,假设内存可以装得下. 解法1:内存可以装得下?可以用快速选择算法得到无序的结果.时间复杂度总体是O(n)级别,但是常系数不小. 代码: 1 // 18.6 Find the smallest one million number among one billion numbers. 2 // Suppose one billion numbers can fit in memory. 3 // I'll use quic