第18章 图元文件_18.2 增强型图元文件(emf)(2)
18.2.7 增强型图元文件的查看和打印程序
(1)传递EMF到剪贴板,剪贴板类型应为:CF_ENHMETAFILE
(2)CopyEnhMetaFile用于复制图元文件
(3)剪贴板中的图元文件会自动在老式与增强型图元文件间转换。
(4)自定义函数CreatePaletteFromMetaFile用于从图元文件中创建逻辑调色板。
【EmfView程序】
/*------------------------------------------------------------
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 = ;
wndclass.cbWndExtra = ;
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 ;
} 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, , ))
{
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 ( == (iNum = GetEnhMetaFilePaletteEntries(hemf, , NULL)))
return NULL; plp = malloc(sizeof(LOGPALETTE)+(iNum - )*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, , 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 ; 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 ; case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_FILE_OPEN:
//显示打开文件对话框
ofn.Flags = ;
if (!GetOpenFileName(&ofn))
return ; //如果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 ; case IDM_FILE_PRINT:
if (!hemf)
return ; //显示打印对话框
printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&printdlg))
return ; if (NULL ==(hdcPrn=printdlg.hDC))
{
MessageBox(hwnd, TEXT("Cannot obtain printer DC"),
szAppName, MB_ICONEXCLAMATION | MB_OK);
return ;
} //获得页面的可打印区域
rect.left = ;
rect.right = GetDeviceCaps(hdcPrn, HORZRES);
rect.top = ;
rect.bottom = GetDeviceCaps(hdcPrn, VERTRES); bSuccess = FALSE; //在打印机设备中回放emf文件,即将emf绘制在打印机上
SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE); if (StartDoc(hdcPrn,&di)> && (StartPage(hdcPrn)>))
{
PlayEnhMetaFile(hdcPrn, hemf, &rect);
if (EndPage(hdcPrn)>)
{
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 ; case IDM_FILE_PROPERTIES:
if (!hemf)
return ; iLength = GetEnhMetaFileDescription(hemf, , NULL); //字符串的字符个数
pBuffer = malloc((iLength + )*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 ; case IDM_FILE_SAVE_AS:
if (!hemf)
return ; //打开“保存”文件对话框
ofn.Flags = OFN_OVERWRITEPROMPT; if (!GetSaveFileName(&ofn))
return ; //保存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 ; case IDM_EDIT_COPY:
case IDM_EDIT_CUT: if (!hemf)
return ; hemfCopy = CopyEnhMetaFile(hemf, NULL);
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_ENHMETAFILE, hemfCopy);
CloseClipboard(); if (LOWORD(wParam) == IDM_EDIT_COPY)
return ; //如果是剪切,则继续执行下去。 case IDM_EDIT_DELETE:
if (hemf)
{
DeleteEnhMetaFile(hemf);
hemf = NULL;
InvalidateRect(hwnd, NULL, TRUE);
}
return ; 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 ; case IDM_APP_EXIT:
SendMessage(hwnd, WM_CLOSE, , );
return ; case IDM_APP_ABOUT:
MessageBox(hwnd, TEXT("Enhanced Metafile Viewer\n")
TEXT("(c)Charles Petzold,1998"),
szAppName,MB_OK);
return ;
} 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 ; 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 () ;
return ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
//resource.h
//{{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.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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 显示精确尺寸的图元文件
(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 = ;
wndclass.cbWndExtra = ;
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 ;
} 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, , ))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
} BOOL PrintRoutine(HWND hwnd)
{
static DOCINFO di;
static PRINTDLG printdlg = { sizeof(PRINTDLG) };
static TCHAR szMessage[]; 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)>)
{
if (StartPage(hdcPrn) > )
{
PaintRoutine(hwnd, hdcPrn, cxPage, cyPage);
if (EndPage(hdcPrn)>)
{
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 ; case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ; 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 ; case IDM_EXIT:
SendMessage(hwnd, WM_CLOSE, , );
return ; case IDM_ABOUT:
MessageBox(hwnd, TEXT("Enhanced Metafile Demo Program\n")
TEXT("Copyright(c) Charles Petzold,1998"),
szClass,MB_ICONINFORMATION | MB_OK);
return ; }
break; case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ; PaintRoutine(hwnd, hdc, cxClient, cyClient); EndPaint (hwnd, &ps) ;
return ; case WM_DESTROY:
PostQuitMessage () ;
return ;
}
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 ? : ; //创建1磅宽的黑色画笔 cx为6英寸,因为1英寸=72磅,所以6英寸/72=6磅,再除以6得1磅
SelectObject(hdc, CreatePen(PS_SOLID, cx / / , )); //画围绕整个标尺的矩形
Rectangle(hdc, iAdj, iAdj, cx + iAdj + , cy + iAdj + ); //刻度尺,共6英寸,每1/16英寸(即6/96)为一个刻度。
for ( i = ; i < ; i++)
{
if (i % == ) iHeight = cy / ; //每隔1英寸,高度为cy/2
else if (i % == ) iHeight = cy / ; //每隔1/2英寸,高度为cx/3;
else if (i % == ) iHeight = cy / ; //每隔1/4英寸,高度为cx/5;
else if (i % == ) iHeight = cy / ; //每隔1/8英寸,高度为cx/8;
else iHeight = cy / ; //每隔1/16英寸,高度为cx/12;
MoveToEx(hdc, i*cx / , cy, NULL);
LineTo(hdc, i*cx / , cy - iHeight);
} //创建逻辑字体,FillMemory最终也是调用memset函数
FillMemory(&lf, sizeof(lf), ); //结构体各字段初始化为0;
lf.lfHeight = cy / ; //字体高度为0.5英寸()
lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf));
SetTextAlign(hdc, TA_BOTTOM | TA_CENTER);
SetBkMode(hdc, TRANSPARENT); //显示数字
for (i = ; i <=; i++)
{
ch = (TCHAR)(i + '');
TextOut(hdc, i*cx / , cy / , &ch, );
} //清除
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 = * cxPix / cxMms / ;//25.4 * cxPix / cxMms; //单位:像素/英寸
yDpi = * cyPix / cyMms / ;// 25.4* cyPix / cyMms; //宽6*xDpi表示6英寸,高1英寸
DrawRuler(hdcEMF, * 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 / ;
cyImage = cyImage* cyPix / cyMms / ; //在指定的矩形区内,水平和垂直居中显示图元文件,同时保证了区域的大小为cxImage和cyImage
rect.left = (cxArea - cxImage) / ;
rect.right = (cxArea + cxImage) / ;
rect.top = (cyArea - cyImage) / ;
rect.bottom = (cyArea + cyImage) / ; 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 ? : ; //创建1磅宽的黑色画笔 cx为6英寸,因为1英寸=72磅,所以6英寸/72=6磅,再除以6得1磅
SelectObject(hdc, CreatePen(PS_SOLID, cx / / , )); //画围绕整个标尺的矩形
Rectangle(hdc, iAdj, iAdj, cx + iAdj + , cy + iAdj + ); //刻度尺,共6英寸,每1/16英寸(即6/96)为一个刻度。
for ( i = ; i < ; i++)
{
if (i % == ) iHeight = cy / ; //每隔1英寸,高度为cy/2
else if (i % == ) iHeight = cy / ; //每隔1/2英寸,高度为cx/3;
else if (i % == ) iHeight = cy / ; //每隔1/4英寸,高度为cx/5;
else if (i % == ) iHeight = cy / ; //每隔1/8英寸,高度为cx/8;
else iHeight = cy / ; //每隔1/16英寸,高度为cx/12;
MoveToEx(hdc, i*cx / , cy, NULL);
LineTo(hdc, i*cx / , cy - iHeight);
} //创建逻辑字体,FillMemory最终也是调用memset函数
FillMemory(&lf, sizeof(lf), ); //结构体各字段初始化为0;
lf.lfHeight = cy / ; //字体高度为0.5英寸()
lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf));
SetTextAlign(hdc, TA_BOTTOM | TA_CENTER);
SetBkMode(hdc, TRANSPARENT); //显示数字
for (i = ; i <=; i++)
{
ch = (TCHAR)(i + '');
TextOut(hdc, i*cx / , cy / , &ch, );
} //清除
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 = * cxPix / cxMms / ;//25.4 * cxPix / cxMms; //单位:像素/英寸
yDpi = * cyPix / cyMms / ;// 25.4* cyPix / cyMms; //宽6*xDpi表示6英寸,高1英寸
DrawRuler(hdcEMF, * 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 / ;
cyImage = cyImage* cyPix / cyMms / ; //约束纵横比,会将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) / ;
rect.right = (cxArea + cxImage) / ;
rect.top = (cyArea - cyImage) / ;
rect.bottom = (cyArea + cyImage) / ; 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 / / , )); //画笔宽度:为逻辑单位 //画围绕整个标尺的矩形
if(GetVersion() & 0x80000000) //windows 98
Rectangle(hdc, , -, cx + , cy);
else
Rectangle(hdc, , -, cx + , cy); //刻度尺,共6英寸,每1/16英寸(即6/96)为一个刻度。
for ( i = ; i < ; i++)
{
if (i % == ) iHeight = cy / ; //每隔1英寸,高度为cy/2
else if (i % == ) iHeight = cy / ; //每隔1/2英寸,高度为cx/3;
else if (i % == ) iHeight = cy / ; //每隔1/4英寸,高度为cx/5;
else if (i % == ) iHeight = cy / ; //每隔1/8英寸,高度为cx/8;
else iHeight = cy / ; //每隔1/16英寸,高度为cx/12;
MoveToEx(hdc, i*cx / , , NULL);
LineTo(hdc, i*cx / , iHeight);
} //创建逻辑字体,FillMemory最终也是调用memset函数
FillMemory(&lf, sizeof(lf), ); //结构体各字段初始化为0;
lf.lfHeight = cy / ; //字体高度为0.5英寸()
lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf));
SetTextAlign(hdc, TA_BOTTOM | TA_CENTER);
SetBkMode(hdc, TRANSPARENT); //显示数字
for (i = ; i <=; i++)
{
ch = (TCHAR)(i + '');
TextOut(hdc, i*cx / , cy / , &ch, );
} //清除
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, , ); 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 / ;
cyImage = cyImage* cyPix / cyMms / ; //在指定的矩形区内,水平和垂直居中显示图元文件,同时保证了区域的大小为cxImage和cyImage
rect.left = (cxArea - cxImage) / ;
rect.right = (cxArea + cxImage) / ;
rect.top = (cyArea - cyImage) / ;
rect.bottom = (cyArea + cyImage) / ; 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 ? : ; //创建1磅宽的黑色画笔 cx为6英寸,因为1英寸=72磅,所以6英寸/72=6磅,再除以6得1磅
SelectObject(hdc, CreatePen(PS_SOLID, cx / / , )); //画围绕整个标尺的矩形
Rectangle(hdc, iAdj, iAdj, cx + iAdj + , cy + iAdj + ); //刻度尺,共6英寸,每1/16英寸(即6/96)为一个刻度。
for ( i = ; i < ; i++)
{
if (i % == ) iHeight = cy / ; //每隔1英寸,高度为cy/2
else if (i % == ) iHeight = cy / ; //每隔1/2英寸,高度为cx/3;
else if (i % == ) iHeight = cy / ; //每隔1/4英寸,高度为cx/5;
else if (i % == ) iHeight = cy / ; //每隔1/8英寸,高度为cx/8;
else iHeight = cy / ; //每隔1/16英寸,高度为cx/12;
MoveToEx(hdc, i*cx / , cy, NULL);
LineTo(hdc, i*cx / , cy - iHeight);
} //创建逻辑字体,FillMemory最终也是调用memset函数
FillMemory(&lf, sizeof(lf), ); //结构体各字段初始化为0;
lf.lfHeight = cy / ; //字体高度为0.5英寸()
lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf));
SetTextAlign(hdc, TA_BOTTOM | TA_CENTER);
SetBkMode(hdc, TRANSPARENT); //显示数字
for (i = ; i <=; i++)
{
ch = (TCHAR)(i + '');
TextOut(hdc, i*cx / , cy / , &ch, );
} //清除
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 = * cxPix / cxMms / ;//25.4 * cxPix / cxMms; //单位:像素/英寸
yDpi = * cyPix / cyMms / ;// 25.4* cyPix / cyMms; //宽6*xDpi表示6英寸,高1英寸
DrawRuler(hdcEMF, * 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, , cyArea, NULL); //将视口原点设在左下角 pt.x = cxArea;
pt.y = ; DPtoLP(hdc, &pt, ); //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) / ;
rect.right = (pt.x + cxImage) / ;
rect.top = (pt.y + cyImage) / ; //注意,这里与前面例子不同
rect.bottom = (pt.y - cyImage) / ; //注意,这里与前面例子不同 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 / / , )); //画笔宽度:为逻辑单位 //画围绕整个标尺的矩形
if(GetVersion() & 0x80000000) //windows 98
Rectangle(hdc, , -, cx + , cy);
else
Rectangle(hdc, , -, cx + , cy); //刻度尺,共6英寸,每1/16英寸(即6/96)为一个刻度。
for ( i = ; i < ; i++)
{
if (i % == ) iHeight = cy / ; //每隔1英寸,高度为cy/2
else if (i % == ) iHeight = cy / ; //每隔1/2英寸,高度为cx/3;
else if (i % == ) iHeight = cy / ; //每隔1/4英寸,高度为cx/5;
else if (i % == ) iHeight = cy / ; //每隔1/8英寸,高度为cx/8;
else iHeight = cy / ; //每隔1/16英寸,高度为cx/12;
MoveToEx(hdc, i*cx / , , NULL);
LineTo(hdc, i*cx / , iHeight);
} //创建逻辑字体,FillMemory最终也是调用memset函数
FillMemory(&lf, sizeof(lf), ); //结构体各字段初始化为0;
lf.lfHeight = cy / ; //字体高度为0.5英寸()
lstrcpy(lf.lfFaceName, TEXT("Times New Roman")); SelectObject(hdc, CreateFontIndirect(&lf));
SetTextAlign(hdc, TA_BOTTOM | TA_CENTER);
SetBkMode(hdc, TRANSPARENT); //显示数字
for (i = ; i <=; i++)
{
ch = (TCHAR)(i + '');
TextOut(hdc, i*cx / , cy / , &ch, );
} //清除
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, , ); 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, , cyArea, NULL);//将视口原点设在左下角 pt.x = cxArea;
pt.y = ;
DPtoLP(hdc, &pt, );//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) / ;
rect.right = (pt.x + cxImage) / ;
rect.top = (pt.y + cyImage) / ; //注意,这里用“+”
rect.bottom = (pt.y - cyImage) / ; //注意,这里用“-” 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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章 图元文件_18.2 增强型图元文件(emf)(2)的更多相关文章
- 第18章 图元文件_18.2 增强型图元文件(emf)(1)
18.2 增强型图元文件(emf) 18.2.1 创建并显示增强型图元文件的步骤 (1)创建:hdcEMF = CreateEnhMetaFile(hdcRef,szFilename,lpRect,l ...
- 第18章 集合框架(2)-Set接口
第18章 集合框架(2)-Set接口 Set是Collection子接口,模拟了数学上的集的概念 Set集合存储特点 1.不允许元素重复 2.不会记录元素的先后添加顺序 Set只包含从Collecti ...
- Java 第18章 多态
18 章 --> 多态 继承: extends 抽象类 abstract (限制类的实例化) 抽象方法 public abstract void show(); //抽象方法只有方法的声明,没 ...
- LPTHW 笨方法学python 18章
看完18章以后,发现第一个练习中,使用了*args读取全部的的输入参数作为一个元组,但是在他的练习中只给了两个变量去赋值,当用户不清楚这个函数的定义时,就可能会给出过多的变量进这个函数,那么就会出现如 ...
- 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(1)-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
- 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
- Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式
Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式 P703 Linux读写内存数据的三种方式 1.read ,write方式会在用户空间和内核空间不断拷贝数据, ...
- 【C#4.0图解教程】笔记(第9章~第18章)
第9章 语句 1.标签语句 ①.标签语句由一个标识符后面跟着一个冒号再跟着一条语句组成 ②.标签语句的执行完全如同标签不存在一样,并仅执行冒号后的语句. ③.给语句添加一个标签允许控制从代码的另一部分 ...
- 第18章 备忘录模式(Memento Pattern)
原文 第18章 备忘录模式(Memento Pattern) 备忘录模式 概述: 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Toke ...
随机推荐
- LigerUI一个前台框架增、删、改asp.net代码的实现
先上代码:前台代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...
- web前端命名规范
在做web项目的时候,命名的规范是很重要.初学者一般急于求成对命名规范没有概念,觉得花时间这些还不如多看几遍框架.其实在我看来,一个良好的命名习惯是很重要的.下面就来介绍一下我总结的命名规范: (1) ...
- Day Tips:ForceDeleteSite
最近遇到一个奇怪的问题,如下图: 试了各种删除方式都不行. 谷歌了一下发现需要使用如下代码删除. SPWebApplication w = SPWebApplication.L ...
- 【IOS】ios中NSUserDefault与android中的SharedPreference用法简单对比
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3405308.html 有Android开发经验的朋友对Shar ...
- PhpStorm下Laravel代码智能提示
phpstorm&Laravel PHPstorm是我见过的最好的PHP的IDE,前年用的时候就毫不犹豫的抛弃了zend studio :) ,Laravel是我用过最好的框架,除了做手游后台 ...
- IOS客户端Coding项目记录(六)
1:获取某一行的坐标 UITableViewCell *cell = [_myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow: ...
- 用Reveal分析第三方App的UI
文章出自:听云博客 Reveal简介: 这是个神奇的工具,它能常透彻地分析个App的UI结构. 这个工具包括两部分,部分是在PC上运行的一个独立应用,即Reveal.app,另一部分代码在你要分析的某 ...
- iOS-工作经验+资料分享(长期更新)
在此记录工作中的一些经验和技术资料 长期更新 欢迎各位业内朋友指正.交流技术上的问题 0.苹果开发联盟电话 4006 701855 1.轻易不用使用tableViewController,因为改变他自 ...
- net2.0对于递归变量的处理方式不同引发的递归问题
同样的代码,用NET2.0执行产生的效果与其它框架使用的不同,导致报错. 认真查找原因后发现该程序的编写人员隐式的使用了一个公共变量,使之在递归过程中不断的被改写,使得1次递归后就破坏了原来的循环体, ...
- 【转】面向对象设计的SOLID原则
S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...