⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scemf.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	
	// 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 + -