18.2.7 加強型圖元文件的查看和打印程序windows
(1)傳遞EMF到剪貼板,剪貼板類型應爲:CF_ENHMETAFILE框架
(2)CopyEnhMetaFile用於複製圖元文件函數
(3)剪貼板中的圖元文件會自動在老式與加強型圖元文件間轉換。字體
(4)自定義函數CreatePaletteFromMetaFile用於從圖元文件中建立邏輯調色板。ui
【EmfView程序】spa
/*------------------------------------------------------------ EMFVIEW.C -- View Enhanced Metafiles (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName[] = TEXT("EmfView"); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd ; MSG msg ; WNDCLASS wndclass ; HACCEL hAccel; 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 = szAppName ; 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 Viewer"), // 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) ; hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage (&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd,hAccel,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam ; } HPALETTE CreatePaletteFromMetaFile(HENHMETAFILE hemf) { HPALETTE hPalette; LOGPALETTE* plp; int iNum; if (!hemf) return NULL; //獲取圖元文件中的調色板數目 if (0 == (iNum = GetEnhMetaFilePaletteEntries(hemf, 0, NULL))) return NULL; plp = malloc(sizeof(LOGPALETTE)+(iNum - 1)*sizeof(PALETTEENTRY)); plp->palVersion = 0x0300; plp->palNumEntries = iNum; GetEnhMetaFilePaletteEntries(hemf, iNum, plp->palPalEntry); //獲取圖元文件調色板中的各個顏色條目 hPalette = CreatePalette(plp); free(plp); return hPalette; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static OPENFILENAME ofn; static TCHAR szFilter[] = TEXT("Enhanced Metafiles(*.EMF)\0*.emf\0") TEXT("All Files (*.*)\0*.*\0\0"); static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static DOCINFO di = { sizeof(DOCINFO), TEXT("EmfView:Printing") }; static PRINTDLG printdlg = { sizeof(PRINTDLG) }; BOOL bSuccess; HDC hdcPrn; HDC hdc ; PAINTSTRUCT ps ; RECT rect ; static HENHMETAFILE hemf; HENHMETAFILE hemfCopy; HMENU hMenu; int iEnable; HPALETTE hPalette; PTSTR pBuffer; int i,iLength; ENHMETAHEADER header; switch (message) { case WM_CREATE: //初始化OPENFILENAME結構體 memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = TEXT("emf"); return 0 ; case WM_INITMENUPOPUP: hMenu = GetMenu(hwnd); iEnable = hemf ? MF_ENABLED : MF_GRAYED; EnableMenuItem(hMenu, IDM_FILE_SAVE_AS, iEnable); EnableMenuItem(hMenu, IDM_FILE_PRINT, iEnable); EnableMenuItem(hMenu, IDM_FILE_PROPERTIES, iEnable); EnableMenuItem(hMenu, IDM_EDIT_CUT, iEnable); EnableMenuItem(hMenu, IDM_EDIT_COPY, iEnable); EnableMenuItem(hMenu, IDM_EDIT_DELETE, iEnable); EnableMenuItem(hMenu, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_ENHMETAFILE) ? MF_ENABLED : MF_GRAYED); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //顯示打開文件對話框 ofn.Flags = 0; if (!GetOpenFileName(&ofn)) return 0; //若是emf文件己經在內存中,則刪掉。 if (hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; } //加載emf文件 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); hemf = GetEnhMetaFile(szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //發送重繪客戶區消息 InvalidateRect(hwnd, NULL, TRUE); if (hemf == NULL) { MessageBox(hwnd, TEXT("Cannot load metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); } return 0; case IDM_FILE_PRINT: if (!hemf) return 0; //顯示打印對話框 printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&printdlg)) return 0; if (NULL ==(hdcPrn=printdlg.hDC)) { MessageBox(hwnd, TEXT("Cannot obtain printer DC"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; } //得到頁面的可打印區域 rect.left = 0; rect.right = GetDeviceCaps(hdcPrn, HORZRES); rect.top = 0; rect.bottom = GetDeviceCaps(hdcPrn, VERTRES); bSuccess = FALSE; //在打印機設備中回放emf文件,即將emf繪製在打印機上 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); if (StartDoc(hdcPrn,&di)>0 && (StartPage(hdcPrn)>0)) { PlayEnhMetaFile(hdcPrn, hemf, &rect); if (EndPage(hdcPrn)>0) { bSuccess = TRUE; EndDoc(hdcPrn); } } ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); DeleteDC(hdcPrn); if (!bSuccess) { MessageBox(hwnd, TEXT("Could not print metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); } return 0; case IDM_FILE_PROPERTIES: if (!hemf) return 0; iLength = GetEnhMetaFileDescription(hemf, 0, NULL); //字符串的字符個數 pBuffer = malloc((iLength + 256)*sizeof(TCHAR)); GetEnhMetaFileHeader(hemf, sizeof(ENHMETAHEADER), &header); //格式化頭記錄信息 i = wsprintf(pBuffer, TEXT("Bounds =(%i,%i,) to (%i,%i) pixels\n"), header.rclBounds.left,header.rclBounds.top, header.rclBounds.right,header.rclBounds.bottom); i += wsprintf(pBuffer+i, TEXT("Frame =(%i,%i,) to (%i,%i) mms\n"), header.rclFrame.left, header.rclFrame.top, header.rclFrame.right, header.rclFrame.bottom); i += wsprintf(pBuffer + i, TEXT("Resolution =(%i,%i,) pixels ") TEXT(" =(%i,%i,) mms\n"), header.szlDevice.cx,header.szlDevice.cy, header.szlMillimeters.cx,header.szlMillimeters.cy); i += wsprintf(pBuffer + i, TEXT("Size = %i, Recoreds = %i, ") TEXT("Handles = %i, Palette Entries = %i\n"), header.nBytes,header.nRecords, header.nHandles,header.nPalEntries); if (iLength) { i += wsprintf(pBuffer + i, TEXT("Description = ")); GetEnhMetaFileDescription(hemf, iLength, pBuffer + i); //注意緩衝區大小爲iLength // pBuffer內容形如"......EMF3\0EMF3 Demo #3\0\0"。MessageBox遇\0時會結束,爲了 //防止出現這種狀況,可將把字符串中間出現的\0替換成空格。此字符串中間只有一個, //又因lstrlen()函數會計算字符串長度,也是遇\0結束而且長度不含\0,可用 //以下代碼替換。 pBuffer[lstrlen(pBuffer)] = TEXT(' '); } MessageBox(hwnd, pBuffer, TEXT("Metafile Properties"), MB_OK); free(pBuffer); return 0; case IDM_FILE_SAVE_AS: if (!hemf) return 0; //打開「保存」文件對話框 ofn.Flags = OFN_OVERWRITEPROMPT; if (!GetSaveFileName(&ofn)) return 0; //保存emf到磁盤 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); //CopyEnhMetaFile將hemf拷到szFileName指定的文件中,並返回副本的句柄. hemfCopy = CopyEnhMetaFile(hemf, szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (hemfCopy) { DeleteEnhMetaFile(hemf); hemf = hemfCopy; //將拷貝的副本設爲當前的圖元文件 } else MessageBox(hwnd, TEXT("Cannot Save metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; case IDM_EDIT_COPY: case IDM_EDIT_CUT: if (!hemf) return 0; hemfCopy = CopyEnhMetaFile(hemf, NULL); OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_ENHMETAFILE, hemfCopy); CloseClipboard(); if (LOWORD(wParam) == IDM_EDIT_COPY) return 0; //若是是剪切,則繼續執行下去。 case IDM_EDIT_DELETE: if (hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; InvalidateRect(hwnd, NULL, TRUE); } return 0; case IDM_EDIT_PASTE: OpenClipboard(hwnd); hemfCopy = GetClipboardData(CF_ENHMETAFILE); CloseClipboard(); if (hemfCopy && hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; } hemf = CopyEnhMetaFile(hemfCopy, NULL); DeleteEnhMetaFile(hemfCopy); InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_APP_EXIT: SendMessage(hwnd, WM_CLOSE, 0, 0); return 0; case IDM_APP_ABOUT: MessageBox(hwnd, TEXT("Enhanced Metafile Viewer\n") TEXT("(c)Charles Petzold,1998"), szAppName,MB_OK); return 0; } case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; if (hemf) { if (hPalette = CreatePaletteFromMetaFile(hemf)) { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } //回放圖元文件 PlayEnhMetaFile(hdc, hemf, &rect); if (hPalette) { DeleteObject(hPalette); } } EndPaint (hwnd, &ps) ; return 0 ; case WM_QUERYNEWPALETTE: //窗口被激活時,收到此消息 if (!hemf || !(hPalette = CreatePaletteFromMetaFile(hemf))) return FALSE; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); InvalidateRect(hwnd, NULL, FALSE); DeleteObject(hPalette); ReleaseDC(hwnd, hdc); return TRUE; case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) break; if (!hemf || !(hPalette = CreatePaletteFromMetaFile(hemf))) break; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); UpdateColors(hdc); DeleteObject(hPalette); ReleaseDC(hwnd, hdc); break; case WM_DESTROY: if (hemf) DeleteEnhMetaFile(hemf); PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
//resource.h3d
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 EmfView.rc 使用 // #define IDM_FILE_OPEN 40001 #define IDM_FILE_SAVE_AS 40002 #define IDM_FILE_PRINT 40003 #define IDM_FILE_PROPERTIES 40004 #define IDM_APP_EXIT 40005 #define IDM_EDIT_CUT 40006 #define IDM_EDIT_COPY 40007 #define IDM_EDIT_PASTE 40008 #define IDM_EDIT_DELETE 40009 #define IDM_APP_ABOUT 40010 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40019 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//EmfView.rccode
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMFVIEW MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Open\tCtrl+O", IDM_FILE_OPEN MENUITEM "Save &As...", IDM_FILE_SAVE_AS MENUITEM "&Print...\tCtrl+P", IDM_FILE_PRINT MENUITEM SEPARATOR MENUITEM "&Peroperties", IDM_FILE_PROPERTIES MENUITEM SEPARATOR MENUITEM "E&xit", IDM_APP_EXIT END POPUP "&Edit" BEGIN MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE MENUITEM "&Delete\tDel", IDM_EDIT_DELETE END POPUP "Help" BEGIN MENUITEM "&About EmfView...", IDM_APP_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // EMFVIEW ACCELERATORS BEGIN "C", IDM_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT "O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT "P", IDM_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT "V", IDM_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, NOINVERT "X", IDM_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
18.2.8 顯示精確尺寸的圖元文件orm
(1)圖元文件的好處是可自由縮放,但有時須要按特定尺寸或縱橫比來顯示。如本例中的爲了保持6英寸寬和1英寸高的刻尺大小不變,必須保證其顯示區域的大小不變,即也是6×1英寸。視頻
(2)本例中CreateEnhMetaFile的第1個參數爲NULL,因此建立出來的圖元文件的設備環境是以視頻顯示設備做爲參考設備環境的。因此調用GetDeviceCaps獲得的其實是視頻顯示的設備環境信息。
(3)畫6英寸寬和1英寸高的刻度尺,須要知道設備的分辨率。由於刻度尺的邊界大小是以視頻DC爲參考被寫進ENHMETAHEADER的rclBounds字段的(單位是像素),因此在若是按該字段設置的顯示矩形,在打印機上顯示出來的刻度尺將明顯變小。而rclFrame指定了圖像的物理尺寸(單位0.01mm),能夠經過該字段與目標設備環境結合,來換算出圖像的像素大小。從而保證,在不一樣的設備環境都能正確顯示較爲真實的刻度尺出來。
【Emf8和Emf9程序】
//Emf.c——是本程序的框架,也是後續程序的框架
/*------------------------------------------------------------ EMF.C -- Enhanced Metafile Demostration Shell Program (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" extern void CreateRoutine(HWND); extern void PaintRoutine(HWND, HDC, int, int); extern TCHAR szClass[]; extern TCHAR szTitle[]; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; HANDLE hInst; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd ; MSG msg ; WNDCLASS wndclass ; TCHAR szResource[] = TEXT("EMF"); hInst = hInstance; 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 = szResource ; wndclass.lpszClassName = szClass; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szClass, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szClass, // window class name szTitle, // 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 ; } BOOL PrintRoutine(HWND hwnd) { static DOCINFO di; static PRINTDLG printdlg = { sizeof(PRINTDLG) }; static TCHAR szMessage[32]; BOOL bSuccess = FALSE; HDC hdcPrn; int cxPage, cyPage; printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&printdlg)) return TRUE; if (NULL == (hdcPrn = printdlg.hDC)) return FALSE; cxPage = GetDeviceCaps(hdcPrn, HORZRES); cyPage = GetDeviceCaps(hdcPrn, VERTRES); lstrcpy(szMessage, szClass); lstrcat(szMessage, TEXT(": Printing")); di.cbSize = sizeof(DOCINFO); di.lpszDocName = szMessage; if (StartDoc(hdcPrn,&di)>0) { if (StartPage(hdcPrn) > 0) { PaintRoutine(hwnd, hdcPrn, cxPage, cyPage); if (EndPage(hdcPrn)>0) { EndDoc(hdcPrn); bSuccess = TRUE; } } } DeleteDC(hdcPrn); return bSuccess; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; BOOL bSuccess; static int cxClient, cyClient; switch (message) { case WM_CREATE: CreateRoutine(hwnd); return 0 ; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_PRINT: SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); bSuccess = PrintRoutine(hwnd); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (!bSuccess) MessageBox(hwnd, TEXT("Error encountered during printing"), szClass, MB_ICONASTERISK | MB_OK); return 0; case IDM_EXIT: SendMessage(hwnd, WM_CLOSE, 0, 0); return 0; case IDM_ABOUT: MessageBox(hwnd, TEXT("Enhanced Metafile Demo Program\n") TEXT("Copyright(c) Charles Petzold,1998"), szClass,MB_ICONINFORMATION | MB_OK); return 0; } break; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; PaintRoutine(hwnd, hdc, cxClient, cyClient); EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
//Emf8(與課本的Emf9合併了)
/*-------------------------------------------------- EMF8 —— Enhanced Metafile Demo #8 (c)Charles Petzold,1998 ----------------------------------------------------*/ #pragma warning(disable: 4996) //win8.1以上GetVersion己過期,加上這句關閉 #include <windows.h> TCHAR szClass[] = TEXT("EMF8"); TCHAR szTitle[] = TEXT("EMF8: Enhanced Metafile Demo #8"); void DrawRuler(HDC hdc, int cx, int cy) { int iAdj,i,iHeight; LOGFONT lf; TCHAR ch; iAdj = GetVersion() & 0x80000000 ? 0 : 1; //建立1磅寬的黑色畫筆 cx爲6英寸,由於1英寸=72磅,因此6英寸/72=6磅,再除以6得1磅 SelectObject(hdc, CreatePen(PS_SOLID, cx / 72 / 6, 0)); //畫圍繞整個標尺的矩形 Rectangle(hdc, iAdj, iAdj, cx + iAdj + 1, cy + iAdj + 1); //刻度尺,共6英寸,每1/16英寸(即6/96)爲一個刻度。 for ( i = 1; i < 96; i++) { if (i % 16 == 0) iHeight = cy / 2; //每隔1英寸,高度爲cy/2 else if (i % 8 == 0) iHeight = cy / 3; //每隔1/2英寸,高度爲cx/3; else if (i % 4 == 0) iHeight = cy / 5; //每隔1/4英寸,高度爲cx/5; else if (i % 2 == 0) iHeight = cy / 8; //每隔1/8英寸,高度爲cx/8; else iHeight = cy / 12; //每隔1/16英寸,高度爲cx/12; MoveToEx(hdc, i*cx / 96, cy, NULL); LineTo(hdc, i*cx / 96, cy - iHeight); } //建立邏輯字體,FillMemory最終也是調用memset函數 FillMemory(&lf, sizeof(lf), 0); //結構體各字段初始化爲0; lf.lfHeight = cy / 2; //字體高度爲0.5英寸() lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf)); SetTextAlign(hdc, TA_BOTTOM | TA_CENTER); SetBkMode(hdc, TRANSPARENT); //顯示數字 for (i = 1; i <=5; i++) { ch = (TCHAR)(i + '0'); TextOut(hdc, i*cx / 6, cy / 2, &ch, 1); } //清除 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); } void CreateRoutine(HWND hwnd) { HDC hdcEMF; HENHMETAFILE hemf; int cxMms, cyMms, cxPix, cyPix, xDpi, yDpi; //注意,第1個參數爲NULL,會將視頻顯示設備環境做爲「參考設備環境」 hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf8.emf"), NULL, TEXT("EMF8\0EMF Demo #8\0")); if (hdcEMF == NULL) return; //由於CreateEnhMetaFile的第1個參數爲NULL,因此儘管如下以hdcEMF爲參數, //但實際上獲得的倒是視頻設備環境的DC的信息 cxMms = GetDeviceCaps(hdcEMF, HORZSIZE); //以毫米爲單位 cyMms = GetDeviceCaps(hdcEMF, VERTSIZE); cxPix = GetDeviceCaps(hdcEMF, HORZRES);//像素規模(單位:像素) cyPix = GetDeviceCaps(hdcEMF, VERTRES); //分辨率 xDpi = 254 * cxPix / cxMms / 10;//25.4 * cxPix / cxMms; //單位:像素/英寸 yDpi = 254 * cyPix / cyMms / 10;// 25.4* cyPix / cyMms; //寬6*xDpi表示6英寸,高1英寸 DrawRuler(hdcEMF, 6 * xDpi, yDpi); //傳入的數值爲6英寸內的像素總量和1英寸內的像素總量 hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); } void PaintRoutine(HWND hwnd, HDC hdc, int cxArea, int cyArea) { ENHMETAHEADER emh; HENHMETAFILE hemf; int cxImage, cyImage,cxMms,cyMms,cxPix,cyPix; RECT rect; hemf = GetEnhMetaFile(TEXT("emf8.emf")); GetEnhMetaFileHeader(hemf, sizeof(emh), &emh); /*方案1——利用圖像的像素尺寸 經過rclBounds字段(是設備單位:像素)顯示出來的刻度尺,因本例指定圖元文件 的參考設備爲視頻DC,因此在視頻顯示器顯示正常,但在打印中,刻度尺明顯變小。 */ //cxImage = emh.rclBounds.right - emh.rclBounds.left; //cyImage = emh.rclBounds.bottom - emh.rclBounds.top; /*方案2——利用圖像的物理尺寸 經過rclFrame字段(是設備單位:0.01mm)顯示出來的刻度尺,這樣無論在視頻顯示器 仍是打印機上,顯示出來的刻度尺都較爲真實 */ //目標設備信息 cxMms = GetDeviceCaps(hdc,HORZSIZE); //寬度(單位:mm) cyMms = GetDeviceCaps(hdc, VERTSIZE);//高度(單位:mm) cxPix = GetDeviceCaps(hdc, HORZRES);//寬度(單位:像素) cyPix = GetDeviceCaps(hdc, VERTRES);//高度(單位:像素) cxImage = emh.rclFrame.right - emh.rclFrame.left; //單位:0.01mm cyImage = emh.rclFrame.bottom - emh.rclFrame.top; //將圖元文件大小(0.01mm爲單位)轉換爲像素大小 cxImage = cxImage* cxPix / cxMms / 100; cyImage = cyImage* cyPix / cyMms / 100; //在指定的矩形區內,水平和垂直居中顯示圖元文件,同時保證了區域的大小爲cxImage和cyImage rect.left = (cxArea - cxImage) / 2; rect.right = (cxArea + cxImage) / 2; rect.top = (cyArea - cyImage) / 2; rect.bottom = (cyArea + cyImage) / 2; PlayEnhMetaFile(hdc, hemf, &rect); //回放(繪製)圖元文件 DeleteEnhMetaFile(hemf); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Emf8.rc 使用 // #define IDM_PRINT 40001 #define IDM_EXIT 40002 #define IDM_ABOUT 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Emf8.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMF MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Print...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_ABOUT END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
18.2.9 縮放比和縱橫比
(1)本例是在Emf9的基礎上改進的,刻度尺大小能夠改變,但縱橫比約束爲6:1
(2) 取客戶區寬度和高度與原圖像寬度和高度的比值,最小者爲最終圖像縱橫比
【Emf10程序】
/*-------------------------------------------------- EMF10 —— Enhanced Metafile Demo #10 (c)Charles Petzold,1998 ----------------------------------------------------*/ #pragma warning(disable: 4996) //win8.1以上GetVersion己過期,加上這句關閉 #include <windows.h> TCHAR szClass[] = TEXT("EMF10"); TCHAR szTitle[] = TEXT("EMF10: Enhanced Metafile Demo #10"); void DrawRuler(HDC hdc, int cx, int cy) { int iAdj,i,iHeight; LOGFONT lf; TCHAR ch; iAdj = GetVersion() & 0x80000000 ? 0 : 1; //建立1磅寬的黑色畫筆 cx爲6英寸,由於1英寸=72磅,因此6英寸/72=6磅,再除以6得1磅 SelectObject(hdc, CreatePen(PS_SOLID, cx / 72 / 6, 0)); //畫圍繞整個標尺的矩形 Rectangle(hdc, iAdj, iAdj, cx + iAdj + 1, cy + iAdj + 1); //刻度尺,共6英寸,每1/16英寸(即6/96)爲一個刻度。 for ( i = 1; i < 96; i++) { if (i % 16 == 0) iHeight = cy / 2; //每隔1英寸,高度爲cy/2 else if (i % 8 == 0) iHeight = cy / 3; //每隔1/2英寸,高度爲cx/3; else if (i % 4 == 0) iHeight = cy / 5; //每隔1/4英寸,高度爲cx/5; else if (i % 2 == 0) iHeight = cy / 8; //每隔1/8英寸,高度爲cx/8; else iHeight = cy / 12; //每隔1/16英寸,高度爲cx/12; MoveToEx(hdc, i*cx / 96, cy, NULL); LineTo(hdc, i*cx / 96, cy - iHeight); } //建立邏輯字體,FillMemory最終也是調用memset函數 FillMemory(&lf, sizeof(lf), 0); //結構體各字段初始化爲0; lf.lfHeight = cy / 2; //字體高度爲0.5英寸() lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf)); SetTextAlign(hdc, TA_BOTTOM | TA_CENTER); SetBkMode(hdc, TRANSPARENT); //顯示數字 for (i = 1; i <=5; i++) { ch = (TCHAR)(i + '0'); TextOut(hdc, i*cx / 6, cy / 2, &ch, 1); } //清除 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); } void CreateRoutine(HWND hwnd) { HDC hdcEMF; HENHMETAFILE hemf; int cxMms, cyMms, cxPix, cyPix, xDpi, yDpi; //注意,第1個參數爲NULL,會將視頻顯示設備環境做爲「參考設備環境」 hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf10.emf"), NULL, TEXT("EMF10\0EMF Demo #10\0")); if (hdcEMF == NULL) return; //由於CreateEnhMetaFile的第1個參數爲NULL,因此儘管如下以hdcEMF爲參數, //但實際上獲得的倒是視頻設備環境的DC的信息 cxMms = GetDeviceCaps(hdcEMF, HORZSIZE); //以毫米爲單位 cyMms = GetDeviceCaps(hdcEMF, VERTSIZE); cxPix = GetDeviceCaps(hdcEMF, HORZRES);//像素規模(單位:像素) cyPix = GetDeviceCaps(hdcEMF, VERTRES); //分辨率 xDpi = 254 * cxPix / cxMms / 10;//25.4 * cxPix / cxMms; //單位:像素/英寸 yDpi = 254 * cyPix / cyMms / 10;// 25.4* cyPix / cyMms; //寬6*xDpi表示6英寸,高1英寸 DrawRuler(hdcEMF, 6 * xDpi, yDpi); //傳入的數值爲6英寸內的像素總量和1英寸內的像素總量 hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); } void PaintRoutine(HWND hwnd, HDC hdc, int cxArea, int cyArea) { ENHMETAHEADER emh; HENHMETAFILE hemf; int cxImage, cyImage,cxMms,cyMms,cxPix,cyPix; RECT rect; float fScale; hemf = GetEnhMetaFile(TEXT("emf10.emf")); GetEnhMetaFileHeader(hemf, sizeof(emh), &emh); /*利用圖像的物理尺寸 經過rclFrame字段(是設備單位:0.01mm)顯示出來的刻度尺,這樣無論在視頻顯示器 仍是打印機上,顯示出來的刻度尺都較爲真實 */ //目標設備信息 cxMms = GetDeviceCaps(hdc,HORZSIZE); //寬度(單位:mm) cyMms = GetDeviceCaps(hdc, VERTSIZE);//高度(單位:mm) cxPix = GetDeviceCaps(hdc, HORZRES);//寬度(單位:像素) cyPix = GetDeviceCaps(hdc, VERTRES);//高度(單位:像素) cxImage = emh.rclFrame.right - emh.rclFrame.left; //單位:0.01mm cyImage = emh.rclFrame.bottom - emh.rclFrame.top; //將圖元文件大小(0.01mm爲單位)轉換爲像素大小 cxImage = cxImage* cxPix / cxMms / 100; cyImage = cyImage* cyPix / cyMms / 100; //約束縱橫比,會將cxImage或cyImage調整成客戶區大小,但cxImage:cyImage保持6:1 fScale = min((float)cxArea / cxImage, (float)cyArea / cyImage); cxImage = (int)(fScale*cxImage); //即cxImage和cyImage同時按fScale這個係數縮放 cyImage = (int)(fScale*cyImage); //也就能夠保持縱橫比保持不變(即原來的6:1) //在指定的矩形區內,水平和垂直居中顯示圖元文件,同時保證了區域的大小爲cxImage和cyImage rect.left = (cxArea - cxImage) / 2; rect.right = (cxArea + cxImage) / 2; rect.top = (cyArea - cyImage) / 2; rect.bottom = (cyArea + cyImage) / 2; PlayEnhMetaFile(hdc, hemf, &rect); //回放(繪製)圖元文件 DeleteEnhMetaFile(hemf); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Emf11.rc 使用 // #define IDM_PRINT 40001 #define IDM_EXIT 40002 #define IDM_ABOUT 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Emf10.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMF MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Print...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_ABOUT END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
18.2.10 圖元文件中的映射模式——在圖元文件內部使用映射模式
(1)本例中SetMapMode會被寫進圖元文件中,在CreateRoutine設置,省去了經過GetDeviceCaps求分辨率的過程
(2)設置映射模式爲MM_LOENGLISH,即邏輯單位的座標爲0.01英寸。要畫6×1英寸的刻度尺,即須要傳給DrawRuler的參數爲600×100
(3)MM_LOENGLISH中,縱座標向上增長,會影響MoveToEx和LineTo等畫刻度線函數。
【Emf11程序】——效果與Emf9基本同樣。
/*-------------------------------------------------- EMF11 —— Enhanced Metafile Demo #11 (c)Charles Petzold,1998 ----------------------------------------------------*/ #pragma warning(disable: 4996) //win8.1以上GetVersion己過期,加上這句關閉 #include <windows.h> TCHAR szClass[] = TEXT("EMF11"); TCHAR szTitle[] = TEXT("EMF11: Enhanced Metafile Demo #11"); void DrawRuler(HDC hdc, int cx, int cy) { int i,iHeight; LOGFONT lf; TCHAR ch; //建立1磅寬的黑色畫筆 cx爲6英寸,由於1英寸=72磅,因此6英寸/72=6磅,再除以6得1磅 SelectObject(hdc, CreatePen(PS_SOLID, cx / 72 / 6, 0)); //畫筆寬度:爲邏輯單位 //畫圍繞整個標尺的矩形 if(GetVersion() & 0x80000000) //windows 98 Rectangle(hdc, 0, -2, cx + 2, cy); else Rectangle(hdc, 0, -1, cx + 1, cy); //刻度尺,共6英寸,每1/16英寸(即6/96)爲一個刻度。 for ( i = 1; i < 96; i++) { if (i % 16 == 0) iHeight = cy / 2; //每隔1英寸,高度爲cy/2 else if (i % 8 == 0) iHeight = cy / 3; //每隔1/2英寸,高度爲cx/3; else if (i % 4 == 0) iHeight = cy / 5; //每隔1/4英寸,高度爲cx/5; else if (i % 2 == 0) iHeight = cy / 8; //每隔1/8英寸,高度爲cx/8; else iHeight = cy / 12; //每隔1/16英寸,高度爲cx/12; MoveToEx(hdc, i*cx / 96, 0, NULL); LineTo(hdc, i*cx / 96, iHeight); } //建立邏輯字體,FillMemory最終也是調用memset函數 FillMemory(&lf, sizeof(lf), 0); //結構體各字段初始化爲0; lf.lfHeight = cy / 2; //字體高度爲0.5英寸() lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf)); SetTextAlign(hdc, TA_BOTTOM | TA_CENTER); SetBkMode(hdc, TRANSPARENT); //顯示數字 for (i = 1; i <=5; i++) { ch = (TCHAR)(i + '0'); TextOut(hdc, i*cx / 6, cy / 2, &ch, 1); } //清除 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); } void CreateRoutine(HWND hwnd) { HDC hdcEMF; HENHMETAFILE hemf; //注意,第1個參數爲NULL,會將視頻顯示設備環境做爲「參考設備環境」 hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf11.emf"), NULL, TEXT("EMF11\0EMF Demo #11\0")); if (hdcEMF == NULL) return; SetMapMode(hdcEMF,MM_LOENGLISH); //邏輯座標的單位爲0.01英寸 //600×100爲邏輯座標,即寬6英寸,高1英寸 DrawRuler(hdcEMF, 600, 100); hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); } void PaintRoutine(HWND hwnd, HDC hdc, int cxArea, int cyArea) { ENHMETAHEADER emh; HENHMETAFILE hemf; int cxImage, cyImage,cxMms,cyMms,cxPix,cyPix; RECT rect; hemf = GetEnhMetaFile(TEXT("emf11.emf")); GetEnhMetaFileHeader(hemf, sizeof(emh), &emh); /*方案1——利用圖像的像素尺寸 經過rclBounds字段(是設備單位:像素)顯示出來的刻度尺,因本例指定圖元文件 的參考設備爲視頻DC,因此在視頻顯示器顯示正常,但在打印中,刻度尺明顯變小。 */ //cxImage = emh.rclBounds.right - emh.rclBounds.left; //cyImage = emh.rclBounds.bottom - emh.rclBounds.top; /*方案2——利用圖像的物理尺寸 經過rclFrame字段(是設備單位:0.01mm)顯示出來的刻度尺,這樣無論在視頻顯示器 仍是打印機上,顯示出來的刻度尺都較爲真實 */ //目標設備信息 cxMms = GetDeviceCaps(hdc,HORZSIZE); //寬度(單位:mm) cyMms = GetDeviceCaps(hdc, VERTSIZE);//高度(單位:mm) cxPix = GetDeviceCaps(hdc, HORZRES);//寬度(單位:像素) cyPix = GetDeviceCaps(hdc, VERTRES);//高度(單位:像素) cxImage = emh.rclFrame.right - emh.rclFrame.left; //單位:0.01mm cyImage = emh.rclFrame.bottom - emh.rclFrame.top; //將圖元文件大小(0.01mm爲單位)轉換爲像素大小 cxImage = cxImage* cxPix / cxMms / 100; cyImage = cyImage* cyPix / cyMms / 100; //在指定的矩形區內,水平和垂直居中顯示圖元文件,同時保證了區域的大小爲cxImage和cyImage rect.left = (cxArea - cxImage) / 2; rect.right = (cxArea + cxImage) / 2; rect.top = (cyArea - cyImage) / 2; rect.bottom = (cyArea + cyImage) / 2; PlayEnhMetaFile(hdc, hemf, &rect); //回放(繪製)圖元文件 DeleteEnhMetaFile(hemf); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Emf11.rc 使用 // #define IDM_PRINT 40001 #define IDM_EXIT 40002 #define IDM_ABOUT 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Emf11.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMF MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Print...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_ABOUT END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
18.2.11 使用映射模式顯示圖元文件
(1)由於圖元文件的rcFrame的單位爲0.01mm,因此使用MM_HIMETRIC來顯示,可減小單位的換算。(注意MM_HIMETRIC邏輯座標的單位也是0.01mm)
(2)MM_HIMETRIC的縱座標向上爲正,意味着客戶區的y座標爲負數。爲了便於操做,可將視口原點移到客戶區的左下角。
(3)經過把客戶區左上角的設備點(cxArea,0)傳給DPToLP,可獲得客戶區的尺寸(單位:0.01mm)
(4)能夠使用映射模式來建立一個圖元文件,再經過映射模式來顯示這個圖元文件。
【Emf12程序】使用映射模式來顯示圖元文件
效果圖與Emf8同樣
/*-------------------------------------------------- EMF12 —— Enhanced Metafile Demo #12 (c)Charles Petzold,1998 ----------------------------------------------------*/ #pragma warning(disable: 4996) //win8.1以上GetVersion己過期,加上這句關閉 #include <windows.h> TCHAR szClass[] = TEXT("EMF12"); TCHAR szTitle[] = TEXT("EMF12: Enhanced Metafile Demo #12"); void DrawRuler(HDC hdc, int cx, int cy) { int iAdj,i,iHeight; LOGFONT lf; TCHAR ch; iAdj = GetVersion() & 0x80000000 ? 0 : 1; //建立1磅寬的黑色畫筆 cx爲6英寸,由於1英寸=72磅,因此6英寸/72=6磅,再除以6得1磅 SelectObject(hdc, CreatePen(PS_SOLID, cx / 72 / 6, 0)); //畫圍繞整個標尺的矩形 Rectangle(hdc, iAdj, iAdj, cx + iAdj + 1, cy + iAdj + 1); //刻度尺,共6英寸,每1/16英寸(即6/96)爲一個刻度。 for ( i = 1; i < 96; i++) { if (i % 16 == 0) iHeight = cy / 2; //每隔1英寸,高度爲cy/2 else if (i % 8 == 0) iHeight = cy / 3; //每隔1/2英寸,高度爲cx/3; else if (i % 4 == 0) iHeight = cy / 5; //每隔1/4英寸,高度爲cx/5; else if (i % 2 == 0) iHeight = cy / 8; //每隔1/8英寸,高度爲cx/8; else iHeight = cy / 12; //每隔1/16英寸,高度爲cx/12; MoveToEx(hdc, i*cx / 96, cy, NULL); LineTo(hdc, i*cx / 96, cy - iHeight); } //建立邏輯字體,FillMemory最終也是調用memset函數 FillMemory(&lf, sizeof(lf), 0); //結構體各字段初始化爲0; lf.lfHeight = cy / 2; //字體高度爲0.5英寸() lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf)); SetTextAlign(hdc, TA_BOTTOM | TA_CENTER); SetBkMode(hdc, TRANSPARENT); //顯示數字 for (i = 1; i <=5; i++) { ch = (TCHAR)(i + '0'); TextOut(hdc, i*cx / 6, cy / 2, &ch, 1); } //清除 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); } void CreateRoutine(HWND hwnd) { HDC hdcEMF; HENHMETAFILE hemf; int cxMms, cyMms, cxPix, cyPix, xDpi, yDpi; //注意,第1個參數爲NULL,會將視頻顯示設備環境做爲「參考設備環境」 hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf12.emf"), NULL, TEXT("EMF12\0EMF Demo #12\0")); if (hdcEMF == NULL) return; //由於CreateEnhMetaFile的第1個參數爲NULL,因此儘管如下以hdcEMF爲參數, //但實際上獲得的倒是視頻設備環境的DC的信息 cxMms = GetDeviceCaps(hdcEMF, HORZSIZE); //以毫米爲單位 cyMms = GetDeviceCaps(hdcEMF, VERTSIZE); cxPix = GetDeviceCaps(hdcEMF, HORZRES);//像素規模(單位:像素) cyPix = GetDeviceCaps(hdcEMF, VERTRES); //分辨率 xDpi = 254 * cxPix / cxMms / 10;//25.4 * cxPix / cxMms; //單位:像素/英寸 yDpi = 254 * cyPix / cyMms / 10;// 25.4* cyPix / cyMms; //寬6*xDpi表示6英寸,高1英寸 DrawRuler(hdcEMF, 6 * xDpi, yDpi); //傳入的數值爲6英寸內的像素總量和1英寸內的像素總量 hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); } //使用映射模式來顯示圖元文件 void PaintRoutine(HWND hwnd, HDC hdc, int cxArea, int cyArea) { ENHMETAHEADER emh; HENHMETAFILE hemf; int cxImage, cyImage; RECT rect; POINT pt; SetMapMode(hdc, MM_HIMETRIC); //邏輯單位:0.01mm SetViewportOrgEx(hdc, 0, cyArea, NULL); //將視口原點設在左下角 pt.x = cxArea; pt.y = 0; DPtoLP(hdc, &pt, 1); //pt.x這客戶區的寬度,pt.y爲客戶區的高度(單位0.01mm) hemf = GetEnhMetaFile(TEXT("emf12.emf")); GetEnhMetaFileHeader(hemf, sizeof(emh), &emh); /*方案2——利用圖像的物理尺寸 經過rclFrame字段(是設備單位:0.01mm)顯示出來的刻度尺,這樣無論在視頻顯示器 仍是打印機上,顯示出來的刻度尺都較爲真實 */ cxImage = emh.rclFrame.right - emh.rclFrame.left; //單位:0.01mm cyImage = emh.rclFrame.bottom - emh.rclFrame.top; //在指定的矩形區內,水平和垂直居中顯示圖元文件,同時保證了區域的大小爲cxImage和cyImage rect.left = (pt.x- cxImage) / 2; rect.right = (pt.x + cxImage) / 2; rect.top = (pt.y + cyImage) / 2; //注意,這裏與前面例子不一樣 rect.bottom = (pt.y - cyImage) / 2; //注意,這裏與前面例子不一樣 PlayEnhMetaFile(hdc, hemf, &rect); //回放(繪製)圖元文件 DeleteEnhMetaFile(hemf); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Emf12.rc 使用 // #define IDM_PRINT 40001 #define IDM_EXIT 40002 #define IDM_ABOUT 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Emf12.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMF MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Print...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_ABOUT END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
【Emf13程序】使用映射模式來建立和顯示圖元文件。
/*-------------------------------------------------- EMF13 —— Enhanced Metafile Demo #13 (c)Charles Petzold,1998 ----------------------------------------------------*/ #pragma warning(disable: 4996) //win8.1以上GetVersion己過期,加上這句關閉 #include <windows.h> TCHAR szClass[] = TEXT("EMF13"); TCHAR szTitle[] = TEXT("EMF13: Enhanced Metafile Demo #13"); void DrawRuler(HDC hdc, int cx, int cy) { int i,iHeight; LOGFONT lf; TCHAR ch; //建立1磅寬的黑色畫筆 cx爲6英寸,由於1英寸=72磅,因此6英寸/72=6磅,再除以6得1磅 SelectObject(hdc, CreatePen(PS_SOLID, cx / 72 / 6, 0)); //畫筆寬度:爲邏輯單位 //畫圍繞整個標尺的矩形 if(GetVersion() & 0x80000000) //windows 98 Rectangle(hdc, 0, -2, cx + 2, cy); else Rectangle(hdc, 0, -1, cx + 1, cy); //刻度尺,共6英寸,每1/16英寸(即6/96)爲一個刻度。 for ( i = 1; i < 96; i++) { if (i % 16 == 0) iHeight = cy / 2; //每隔1英寸,高度爲cy/2 else if (i % 8 == 0) iHeight = cy / 3; //每隔1/2英寸,高度爲cx/3; else if (i % 4 == 0) iHeight = cy / 5; //每隔1/4英寸,高度爲cx/5; else if (i % 2 == 0) iHeight = cy / 8; //每隔1/8英寸,高度爲cx/8; else iHeight = cy / 12; //每隔1/16英寸,高度爲cx/12; MoveToEx(hdc, i*cx / 96, 0, NULL); LineTo(hdc, i*cx / 96, iHeight); } //建立邏輯字體,FillMemory最終也是調用memset函數 FillMemory(&lf, sizeof(lf), 0); //結構體各字段初始化爲0; lf.lfHeight = cy / 2; //字體高度爲0.5英寸() lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf)); SetTextAlign(hdc, TA_BOTTOM | TA_CENTER); SetBkMode(hdc, TRANSPARENT); //顯示數字 for (i = 1; i <=5; i++) { ch = (TCHAR)(i + '0'); TextOut(hdc, i*cx / 6, cy / 2, &ch, 1); } //清除 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); } //在圖元文件內部使用映射模式 void CreateRoutine(HWND hwnd) { HDC hdcEMF; HENHMETAFILE hemf; //注意,第1個參數爲NULL,會將視頻顯示設備環境做爲「參考設備環境」 hdcEMF = CreateEnhMetaFile(NULL, TEXT("emf13.emf"), NULL, TEXT("EMF13\0EMF Demo #13\0")); if (hdcEMF == NULL) return; SetMapMode(hdcEMF,MM_LOENGLISH); //邏輯座標的單位爲0.01英寸 //600×100爲邏輯座標,即寬6英寸,高1英寸 DrawRuler(hdcEMF, 600, 100); hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); } //使用映射模式來顯示圖元文件 void PaintRoutine(HWND hwnd, HDC hdc, int cxArea, int cyArea) { ENHMETAHEADER emh; HENHMETAFILE hemf; int cxImage, cyImage; RECT rect; POINT pt; SetMapMode(hdc, MM_HIMETRIC);//邏輯單位:0.01mm SetViewportOrgEx(hdc, 0, cyArea, NULL);//將視口原點設在左下角 pt.x = cxArea; pt.y = 0; DPtoLP(hdc, &pt, 1);//pt.x這客戶區的寬度,pt.y爲客戶區的高度(單位0.01mm) hemf = GetEnhMetaFile(TEXT("emf13.emf")); GetEnhMetaFileHeader(hemf, sizeof(emh), &emh); /*方案2——利用圖像的物理尺寸 經過rclFrame字段(是設備單位:0.01mm)顯示出來的刻度尺,這樣無論在視頻顯示器 仍是打印機上,顯示出來的刻度尺都較爲真實 */ cxImage = emh.rclFrame.right - emh.rclFrame.left; //單位:0.01mm cyImage = emh.rclFrame.bottom - emh.rclFrame.top; //在指定的矩形區內,水平和垂直居中顯示圖元文件,同時保證了區域的大小爲cxImage和cyImage rect.left = (pt.x - cxImage) / 2; rect.right = (pt.x + cxImage) / 2; rect.top = (pt.y + cyImage) / 2; //注意,這裏用「+」 rect.bottom = (pt.y - cyImage) / 2; //注意,這裏用「-」 PlayEnhMetaFile(hdc, hemf, &rect); //回放(繪製)圖元文件 DeleteEnhMetaFile(hemf); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Emf13.rc 使用 // #define IDM_PRINT 40001 #define IDM_EXIT 40002 #define IDM_ABOUT 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Emf13.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(簡體,中國) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // EMF MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Print...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_ABOUT END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED