📄 scemf.cpp
字号:
// Size of the Windows metafile associated with hMF.
uiSizeBuf = GetWinMetaFileBits(hEMF, 0, NULL, MM_ANISOTROPIC, hrefDC);
// Memory to hold metafile bits.
lpEMFBits = new BYTE[uiSizeBuf];
if (!lpEMFBits)
return;
// Bits of the enhanced metafile associated with hEMF.
GetWinMetaFileBits(hEMF, uiSizeBuf, lpEMFBits, MM_ANISOTROPIC, hrefDC);
// Copy the bits into a memory-based Windows metafile.
HMETAFILE hWMF = SetMetaFileBitsEx(uiSizeBuf, lpEMFBits);
// Copy the Windows metafile to a disk-based Windows metafile.
CopyMetaFile(hWMF, lpszFileName);
// Clean up
DeleteMetaFile(hWMF);
delete [] lpEMFBits;
ReleaseDC(NULL, hrefDC);
}
///
/// Copy the content of the source
///
HMETAFILE SCCopyEMFtoWMF(HENHMETAFILE hEMF, CRect rcSrc, METAFILEPICT *pMtf/*=NULL*/)
{
CMetaFileDC MetaDC;
HDC hAttribDC;
BOOL bWholeEMF = (0==rcSrc.Width() || 0==rcSrc.Height());
long lEmfDPIX = 0;
long lEmfDPIY = 0;
{
long lEmfPaperCx = 0;
long lEmfPaperCy = 0;
if (!SCGetEMFInfos(hEMF, lEmfDPIX, lEmfDPIY, lEmfPaperCx, lEmfPaperCy))
return NULL;
}
CSize sizeEMF;
SCGetEMFPlaySize(hEMF, sizeEMF);
CRect rcPlay(0, 0, sizeEMF.cx, sizeEMF.cy);
// Draw in the metafile.
MetaDC.Create(NULL);
MetaDC.SetAttribDC(hAttribDC=CreateCompatibleDC(NULL)); // Required for some query functions working well.
rcSrc.right++;
rcSrc.bottom++;
//MetaDC.SetMapMode(MM_ANISOTROPIC);
MetaDC.SetWindowOrg(rcSrc.left, rcSrc.top);
MetaDC.SetWindowExt(rcSrc.Width(), rcSrc.Height());
if (!bWholeEMF)
{
CRgn rgn;
rgn.CreateRectRgn(rcSrc.left, rcSrc.top, rcSrc.right, rcSrc.bottom);
MetaDC.SelectClipRgn(&rgn, RGN_COPY);
}
MetaDC.PlayMetaFile(hEMF, (LPRECT)&rcPlay);
HMETAFILE hMeta = MetaDC.Close();
DeleteDC(hAttribDC);
CPoint pt(rcSrc.Width(), rcSrc.Height());
{
HDC hDC = GetDC(NULL);
int iMapMode = SetMapMode(hDC, MM_HIMETRIC);
DPtoLP(hDC, &pt, 1);
SetMapMode(hDC, iMapMode);
ReleaseDC(NULL, hDC);
}
if (hMeta && pMtf)
{// fill the placement header
pMtf->hMF = hMeta;
pMtf->mm = MM_ANISOTROPIC;
pMtf->xExt = pt.x;
pMtf->yExt = pt.y;
}
APMFILEHEADER apmheader;
apmheader.key = WMFMETA_PLACEABLEKEY;
apmheader.hmf = 0; // unused
apmheader.bbox.Left = apmheader.bbox.Top = 0;
apmheader.bbox.Right = pt.x;
apmheader.bbox.Bottom = pt.y;
apmheader.inch = 1440;
apmheader.reserved = 0;
apmheader.checksum = 0;
{// compute checksum
for (WORD *p = (WORD*)&apmheader; (p < (WORD*)&(apmheader.checksum)); ++p)
apmheader.checksum ^= *p;
}
return hMeta;
}
///
/// Close metafile DC and ensure that we never use it again
///
HENHMETAFILE SCCloseEMF(HDC& hEMFDC)
{
HENHMETAFILE hEmfTemp = ::CloseEnhMetaFile(hEMFDC);
hEMFDC = NULL;
return hEmfTemp;
}
void SCRectDPtoHIMETRIC(CDC* pDC, RECT* pRect)
{
ASSERT(pRect);
pDC->DPtoHIMETRIC((LPSIZE)&pRect->left);
pDC->DPtoHIMETRIC((LPSIZE)&pRect->right);
}
void SCRectLPtoHIMETRIC(CDC* pDC, RECT* pRect)
{
ASSERT(pRect);
pDC->LPtoHIMETRIC((LPSIZE)&pRect->left);
pDC->LPtoHIMETRIC((LPSIZE)&pRect->right);
}
void SCRectToTwips(RECT* pRect, int ilogx, int ilogy, CDC* pDC)
{
ASSERT(pRect);
// convert to inches and inches to twips: 1440 twips = 1 inch
pRect->left = MulDiv(pRect->left, 1440, ilogx);
pRect->right = MulDiv(pRect->right, 1440, ilogx);
pRect->top = MulDiv(pRect->top, 1440, ilogy);
pRect->bottom = MulDiv(pRect->bottom, 1440, ilogy);
}
// Default paper (A4, in mm)
#define SC_DFLT_PAPER_CX 210
#define SC_DFLT_PAPER_CY 297
#define SC_DFLT_DPI 96
#define SC_DFLT_PHYSICALWIDTH MulDiv(SC_DFLT_PAPER_CX*10, SC_DFLT_DPI, 254)
#define SC_DFLT_PHYSICALHEIGHT MulDiv(SC_DFLT_PAPER_CY*10, SC_DFLT_DPI, 254)
UINT SCRichEditConvertToEMF(CRichEditCtrl& rRichEdit, HEMFVECTOR& rVector)
{
// Setup paper
HDC hdc;
int nHorizRes;
int nVertRes;
int nMarginX = MulDiv(250, 1440, 254); // twips (2.5cm)
int nMarginY = nMarginX; // all around
// Check default printer
BOOL bPrnDC = FALSE;
#if 1
if ((hdc = SCGetDefaultPrinterDC(rRichEdit.m_hWnd))!=NULL)
#else
if (FALSE)
// test stuff: to force using screen attributes
#endif
{
bPrnDC = TRUE;
nHorizRes = GetDeviceCaps(hdc, PHYSICALWIDTH);
nVertRes = GetDeviceCaps(hdc, PHYSICALHEIGHT);
SetMapMode(hdc, MM_TEXT);
} else
{
hdc = GetDC(NULL);
// Note: may cause problem, since we are not using GetDeviceCaps as we should.
// See the adjustements below.
// Compute pixels by hand for an A4 paper at 96 dpi.
nHorizRes = SC_DFLT_PHYSICALWIDTH;
nVertRes = SC_DFLT_PHYSICALHEIGHT;
}
CDC* pDC = CDC::FromHandle(hdc);
int nLogPixelsX = pDC->GetDeviceCaps(LOGPIXELSX);
int nLogPixelsY = pDC->GetDeviceCaps(LOGPIXELSY);
if (!bPrnDC)
{// Adjustement for actual DPI
nHorizRes = MulDiv(nHorizRes, nLogPixelsX, SC_DFLT_DPI);
nVertRes = MulDiv(nVertRes, nLogPixelsY, SC_DFLT_DPI);
}
CRect rcMeta(0, 0, nHorizRes, nVertRes);
SCRectLPtoHIMETRIC(pDC, &rcMeta); // in 100th of mm
FORMATRANGE fr;
fr.hdcTarget = hdc;
::SetRect(&fr.rcPage, 0, 0, nHorizRes, nVertRes);
SCRectToTwips(&fr.rcPage, nLogPixelsX, nLogPixelsY, pDC);
::CopyRect(&fr.rc, &fr.rcPage);
::InflateRect(&fr.rc, -nMarginX, -nMarginY);
long lTextLen = rRichEdit.GetTextLength();
long lTextOut = 0;
fr.chrg.cpMax = -1;
while (lTextOut<lTextLen)
{
CMetaFileDC MetaDC;
BOOL bOK = MetaDC.CreateEnhanced(pDC, NULL, &rcMeta, NULL);
ASSERT(bOK);
fr.hdc = MetaDC.m_hDC;
fr.chrg.cpMin = lTextOut;
lTextOut = rRichEdit.FormatRange(&fr, TRUE);
HENHMETAFILE hemf = MetaDC.CloseEnhanced();
if (!bPrnDC && hemf)
{
// Device adjustment.
// We must update the header to reflect the device we want
// (the one we computed by hand)
UINT uiSize = GetEnhMetaFileBits(hemf, 0, NULL);
LPBYTE pData = uiSize ? new BYTE[uiSize] : NULL;
if (pData)
{
GetEnhMetaFileBits(hemf, uiSize, pData);
ENHMETAHEADER* pEmfHeader = (ENHMETAHEADER*)pData;
pEmfHeader->szlDevice.cx = nHorizRes;
pEmfHeader->szlDevice.cy = nVertRes;
pEmfHeader->szlMillimeters.cx = SC_DFLT_PAPER_CX;
pEmfHeader->szlMillimeters.cy = SC_DFLT_PAPER_CY;
DeleteEnhMetaFile(hemf);
hemf = SetEnhMetaFileBits(uiSize, pData);
delete [] pData;
} // else stay with bogus emf
}
ASSERT(hemf);
rVector.push_back(hemf);
}
// tell the control to release cached information
rRichEdit.FormatRange(NULL, FALSE);
if (bPrnDC)
DeleteDC(hdc);
else
ReleaseDC(NULL, hdc);
return rVector.size();
}
///
/// RTF or TXT (non UNICODE) file to Enhanced Metafile format
///
UINT SCConvertRTFtoEMF(LPCTSTR lpszFname, HEMFVECTOR& rVector, BOOL bRTF/*=TRUE*/)
{
CSCRichEdit RichEdit;
if (!RichEdit.SCCreateHidden(bRTF))
return 0;
if (!RichEdit.SCLoadFromFile(lpszFname, bRTF))
return 0;
return SCRichEditConvertToEMF(RichEdit, rVector);
}
///
/// RTF or TXT (UNICODE) piece of memory to Enhanced Metafile format
///
UINT SCConvertRTFtoEMF(HANDLE hMem, HEMFVECTOR& rVector, BOOL bRTF/*=TRUE*/)
{
CSCRichEdit RichEdit;
if (!RichEdit.SCCreateHidden(bRTF))
return 0;
if (!RichEdit.SCLoadFromHGlobal(hMem, bRTF))
return 0;
return SCRichEditConvertToEMF(RichEdit, rVector);
}
///
/// Attempt to paste the clipboard content to Enhanced Metafile
///
UINT SCConvertClipboardTextToEMF(HEMFVECTOR& rVector)
{
CSCRichEdit RichEdit;
if (!RichEdit.SCCreateHidden(FALSE))
return 0;
if (!RichEdit.CanPaste())
return 0;
RichEdit.Paste();
return SCRichEditConvertToEMF(RichEdit, rVector);
}
#undef SC_DFLT_PAPER_CX
#undef SC_DFLT_PAPER_CY
#undef SC_DFLT_DPI
#undef SC_DFLT_PHYSICALWIDTH
#undef SC_DFLT_PHYSICALHEIGHT
///
/// Adjust an EMF header to circumvent problems raised by the use of screen DCs
/// as reference DC when creating/translating/filtering an EMF
///
BOOL SCUpdateEMFheader(HENHMETAFILE& hemf, ENHMETAHEADER& rEmfHeader)
{
ASSERT(hemf);
if (0)
{
// Device adjustment.
// We must update the header to reflect the device we want
// (the one we computed by hand)
UINT uiSize = GetEnhMetaFileBits(hemf, 0, NULL);
LPBYTE pData = uiSize ? new BYTE[uiSize] : NULL;
if (pData)
{
GetEnhMetaFileBits(hemf, uiSize, pData);
ENHMETAHEADER* pEmfHeader = (ENHMETAHEADER*)pData;
pEmfHeader->szlDevice.cx = rEmfHeader.szlDevice.cx;
pEmfHeader->szlDevice.cy = rEmfHeader.szlDevice.cy;
pEmfHeader->szlMillimeters.cx = rEmfHeader.szlMillimeters.cx;
pEmfHeader->szlMillimeters.cy = rEmfHeader.szlMillimeters.cy;
CopyRect((LPRECT)&pEmfHeader->rclFrame, (LPRECT)&rEmfHeader.rclFrame);
//CopyRect((LPRECT)&pEmfHeader->rclBounds, (LPRECT)&rEmfHeader.rclBounds);
DeleteEnhMetaFile(hemf);
hemf = SetEnhMetaFileBits(uiSize, pData);
delete [] pData;
return TRUE;
} // else stay with bogus emf
}
return FALSE;
}
///
/// Call this when finished with a created metafile DC
///
void SCEMFDCDispose(HDC& hEMFDC)
{
if (!hEMFDC)
return;
//Close and delete it
HENHMETAFILE hEmfTemp = SCCloseEMF(hEMFDC);
::DeleteEnhMetaFile(hEmfTemp);
}
void SCInitEMFDCForEnumeration1(HDC hEMFDC, ENHMETAHEADER &hEmfHeader)
{
if (!hEMFDC)
return;
::SetMapMode(hEMFDC,MM_ANISOTROPIC);
::SetWindowOrgEx(hEMFDC,0,0,NULL);
::SetViewportOrgEx(hEMFDC,0,0,NULL);
::SetWindowExtEx(hEMFDC,(int)hEmfHeader.szlMillimeters.cx * 100,(int)hEmfHeader.szlMillimeters.cy * 100,NULL);
::SetViewportExtEx(hEMFDC,(int)hEmfHeader.szlDevice.cx, (int)hEmfHeader.szlDevice.cy,NULL);
}
///
/// Call this to viewport and window before playing a metafile
///
void SCInitEMFDCForEnumeration(HDC hEMFDC, ENHMETAHEADER &EmfHeader, HDC hDCRef)
{
if (!hEMFDC)
return;
::SetMapMode(hEMFDC,MM_ANISOTROPIC);
// Set the window extent to rclFrame in pixels
int width, height;
// Get the characteristics of the output device.
int iDpiX = GetDeviceCaps(hDCRef, LOGPIXELSX);
int iDpiY = GetDeviceCaps(hDCRef, LOGPIXELSY);
RECTL& rRect = EmfHeader.rclFrame;
width = MulDiv(rRect.right - rRect.left + 1, iDpiX, L001MMPERINCH);
height = MulDiv(rRect.bottom - rRect.top + 1, iDpiY, L001MMPERINCH);
SetWindowExtEx(hEMFDC, width, height, NULL);
// Set the viewport extent to reflect
// rclFrame in target device units
// Get the physical characteristics of the reference DC
float PixelsX = (float)GetDeviceCaps( hDCRef, HORZRES );
float PixelsY = (float)GetDeviceCaps( hDCRef, VERTRES );
float MMX = (float)GetDeviceCaps( hDCRef, HORZSIZE );
float MMY = (float)GetDeviceCaps( hDCRef, VERTSIZE );
DWORD dwInchesX = (DWORD)(float(EmfHeader.rclFrame.right*PixelsX)/(100.0f*MMX));
DWORD dwInchesY = (DWORD)(float(EmfHeader.rclFrame.bottom*PixelsY)/(100.0f*MMY));
SetViewportExtEx( hEMFDC, dwInchesX, dwInchesY, NULL);
}
static BOOL s_bEMRSMALLTEXTOUT = FALSE;
int CALLBACK SCEnhMetafileFilterProc(HDC hDC, HANDLETABLE FAR *lpHTable, ENHMETARECORD FAR *lpEMFR, int nObj, LPARAM lpData )
{
if (lpEMFR->iType == 108)
s_bEMRSMALLTEXTOUT = TRUE;
else
// Do not play Escape
if (lpEMFR->iType == 106)//EMR_EXTESCAPE)
return 1;
PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, nObj);
return 1;
}
HDC MSCreateEnhMetaFileFlt( LPTSTR szFileName, // Metafile filename
float dwInchesX, // Width in inches
float dwInchesY, // Height in inches
float dwDPI ) // DPI (logical units)
{
RECT Rect = { 0, 0, 0, 0 };
TCHAR szDesc[] = _T("EMFExplorer\0Filtered EMF\0\0");
HDC hMetaDC, hScreenDC;
float PixelsX, PixelsY, MMX, MMY;
// dwInchesX x dwInchesY in .01mm units
SetRect(&Rect, 0, 0, (int)(dwInchesX*2540), (int)(dwInchesY*2540));
// Get a Reference DC
hScreenDC = GetDC( NULL );
// Get the physical characteristics of the reference DC
PixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES );
PixelsY = (float)GetDeviceCaps( hScreenDC, VERTRES );
MMX = (float)GetDeviceCaps( hScreenDC, HORZSIZE );
MMY = (float)GetDeviceCaps( hScreenDC, VERTSIZE );
// Create the Metafile
hMetaDC = CreateEnhMetaFile(hScreenDC, szFileName, &Rect, szDesc);
// Release the reference DC
ReleaseDC( NULL, hScreenDC );
// Did you get a good metafile?
if( hMetaDC == NULL )
return NULL;
// Anisotropic mapping mode
SetMapMode( hMetaDC, MM_ANISOTROPIC );
// Set the Windows extent
SetWindowExtEx( hMetaDC, (int)(dwInchesX*dwDPI), (int)(dwInchesY*dwDPI), NULL );
// Set the viewport extent to reflect
// dwInchesX" x dwInchesY" in device units
SetViewportExtEx( hMetaDC,
(int)((float)dwInchesX*25.4f*PixelsX/MMX),
(int)((float)dwInchesY*25.4f*PixelsY/MMY),
NULL );
return hMetaDC;
}
///
/// Filter an EMF to remove undocumented records
///
BOOL SCPreFilterEMF(HENHMETAFILE& hEmf)
{
ASSERT(hEmf);
ENHMETAHEADER EmfHeader;
if (!::GetEnhMetaFileHeader(hEmf, sizeof(ENHMETAHEADER), &EmfHeader))
{
DWORD dwErrCode = ::GetLastError();
return FALSE;
}
HDC hDCRef = GetDC(NULL);
CSize sizeEMF;
SCGetEMFPlaySize(hEmf, sizeEMF);
long lEmfDPIX = MulDiv(EmfHeader.szlDevice.cx, 254, EmfHeader.szlMillimeters.cx*10L);
long lEmfDPIY = MulDiv(EmfHeader.szlDevice.cy, 254, EmfHeader.szlMillimeters.cy*10L);
int iDpiX = GetDeviceCaps(hDCRef, LOGPIXELSX);
int iDpiY = GetDeviceCaps(hDCRef, LOGPIXELSY);
CRect rcPlay((LPRECT)&EmfHeader.rclFrame);
HDC hNewEMFDC = CreateEnhMetaFile(hDCRef, (LPCTSTR)NULL, (LPRECT)&EmfHeader.rclFrame, NULL);
SCInitEMFDCForEnumeration1(hNewEMFDC, EmfHeader);
if (EnumEnhMetaFile(hNewEMFDC, hEmf, (ENHMFENUMPROC)SCEnhMetafileFilterProc, (LPVOID)NULL, (LPRECT)&rcPlay))
{
if (s_bEMRSMALLTEXTOUT)
{
DeleteEnhMetaFile(hEmf);
hEmf = SCCloseEMF(hNewEMFDC);
}
}
SCEMFDCDispose(hNewEMFDC);
ReleaseDC(NULL, hDCRef);
return TRUE;
}
#if 0
// Zzzz!... Let them sleep.
#define MS_LOGX GetDeviceCaps(hDC, LOGPIXELSX)
#define MS_LOGY GetDeviceCaps(hDC, LOGPIXELSY)
#define MS_HIMETRICINCH 2540
void FAR PASCAL MSHiMetrictoDP(HDC hDC, POINT &pt)
{
pt.x = MulDiv(pt.x, MS_LOGX, MS_HIMETRICINCH);
// The minus sign is required because the Y axis
// points down in the MM_TEXT mapping mode
pt.y = -MulDiv(pt.y, MS_LOGY, MS_HIMETRICINCH);
}
void FAR PASCAL MSDPtoHiMetric(HDC hDC, POINT &pt)
{
pt.x = MulDiv(pt.x, MS_HIMETRICINCH, MS_LOGX);
// The minus sign is required because the Y axis
// points down in the MM_TEXT mapping mode
pt.y = -MulDiv(pt.y, MS_HIMETRICINCH, MS_LOGY);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -