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

📄 scgdiplusutils.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 4 页
字号:

///
/// Any image to Enhanced Metafile format
///
BOOL SCGdipPlayMetafile(HDC hDCPlay, HENHMETAFILE hemf, LPCRECT pRect)
{
	ASSERT(hDCPlay);
	ASSERT(hemf);
	ASSERT(pRect);

	Metafile metafile(hemf);
	MetafileHeader header;
	metafile.GetMetafileHeader(&header);

	Graphics graphics(hDCPlay);
	Rect destRec(pRect->left, pRect->top, PRECT_WIDTH(pRect), PRECT_HEIGHT(pRect));
	graphics.DrawImage(&metafile, destRec);
	return (graphics.GetLastStatus()==Ok);
}


///
/// Any GDIp image to Enhanced Metafile format
///
HENHMETAFILE SCConvertImagetoEMF(Image& rImage)
{
	// Store image in metafile.

	// Use printer DC to avoid loss in resolution
	BOOL bPrnDC = FALSE;
#if 1
	HDC hdc = SCGetDefaultPrinterDC(NULL);
	if (hdc)
		bPrnDC = TRUE;
	else
	{
		hdc = GetDC(NULL); // accept loss in resolution
		if (!hdc)
			return NULL;
	}
#else
	// test for screen dc
	HDC hdc = GetDC(NULL);
	if (!hdc)
		return NULL;
#endif

	// Note: this, sometimes, generates images bigger or smaller than expected.
	// Some JPEGs are completely blured. Where is my part in this bug?
	Metafile metafile(hdc, EmfTypeEmfOnly);

	ASSERT(metafile.GetLastStatus()==Ok);
	{// we want the graphics object to detach itself from the metafile before we
	 // extract the GDI handle
		Graphics graphics(&metafile);
		ASSERT(graphics.GetLastStatus()==Ok);

		graphics.DrawImage(&rImage, 0, 0);
		ASSERT(graphics.GetLastStatus()==Ok);
	}

	HENHMETAFILE hEMF = metafile.GetHENHMETAFILE();
	ASSERT(metafile.GetLastStatus()==Ok);
	if (bPrnDC)
		DeleteDC(hdc);
	else
		ReleaseDC(NULL, hdc);

	return hEMF;
}

///
/// Any (gdi+ supported) image file to Enhanced Metafile format
///
HENHMETAFILE SCConvertImagetoEMF(LPCTSTR lpszFname)
{
	// load image
#ifdef _UNICODE
	Image image(lpszFname);
#else
	WCHAR	wFileName[MAX_PATH];
	MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszFname, _tcslen(lpszFname)+1, wFileName, MAX_PATH);
	Image image(wFileName);
#endif
	ASSERT(image.GetLastStatus()==Ok);

	return SCConvertImagetoEMF(image);
}

///
/// Bitmap to Enhanced Metafile format
///
HENHMETAFILE SCGDIpConvertBitmaptoEMF(HBITMAP hbm, HPALETTE hpal)
{
	Bitmap bmp(hbm, hpal);
	ASSERT(bmp.GetLastStatus()==Ok);

	return SCConvertImagetoEMF(bmp);
}

///
/// Any piece of memory containing an image to Enhanced Metafile format
///
HENHMETAFILE SCGDIpConvertImagetoEMF(HANDLE hMem)
{
	HENHMETAFILE hEMF = NULL;
	IStream* pIStream = NULL;
	HRESULT hr = ::CreateStreamOnHGlobal((HGLOBAL)hMem, FALSE, &pIStream);
	if ((hr == S_OK) && pIStream)
	{
		Image img(pIStream, TRUE);
		if (img.GetLastStatus()==Ok)
			hEMF = SCConvertImagetoEMF(img);
		pIStream->Release();
	}
	return hEMF;
}

int MSGetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
   UINT  num = 0;          // number of image encoders
   UINT  size = 0;         // size of the image encoder array in bytes

   ImageCodecInfo* pImageCodecInfo = NULL;

   GetImageEncodersSize(&num, &size);
   if(size == 0)
      return -1;  // Failure

   pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
   if(pImageCodecInfo == NULL)
      return -1;  // Failure

   GetImageEncoders(num, size, pImageCodecInfo);

   for(UINT j = 0; j < num; ++j)
   {
      if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
      {
         *pClsid = pImageCodecInfo[j].Clsid;
         free(pImageCodecInfo);
         return j;  // Success
      }    
   }

   free(pImageCodecInfo);
   return -1;  // Failure
}


BOOL SCGDIpSaveImage(HBITMAP hbm, LPCTSTR lpszPathname, INT iType, INT iJPEGQuality/*=100*/)
{
	ASSERT(hbm);
	EncoderParameters encoderParameters;
	ULONG             quality;
	EncoderParameters* pParameters = NULL;

	// Check encoder
   CLSID clsidEncoder;
   INT   iEncoder;
   switch (iType & SC_SUBTYPE_MASK)
   {
   case SC_SUBTYPE_IMG_JPG:
	   iEncoder = MSGetEncoderClsid(L"image/jpeg", &clsidEncoder);
	   // optimistically prepare quality
	   encoderParameters.Count = 1;
	   encoderParameters.Parameter[0].Guid = EncoderQuality;
	   encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
	   encoderParameters.Parameter[0].NumberOfValues = 1;
	   quality = iJPEGQuality;
	   encoderParameters.Parameter[0].Value = &quality;
	   pParameters = &encoderParameters;
	   break;

   case SC_SUBTYPE_IMG_BMP: iEncoder = MSGetEncoderClsid(L"image/bmp", &clsidEncoder); break;
   case SC_SUBTYPE_IMG_PNG: iEncoder = MSGetEncoderClsid(L"image/png", &clsidEncoder); break;
   case SC_SUBTYPE_IMG_GIF: iEncoder = MSGetEncoderClsid(L"image/gif", &clsidEncoder); break;
   case SC_SUBTYPE_IMG_TIFF: iEncoder = MSGetEncoderClsid(L"image/tiff", &clsidEncoder); break;
   default:
	   {
		   ASSERT(0);
		   return FALSE;
	   }
   }

   if (iEncoder<0)
	   return FALSE;

   // render image
   Bitmap image(hbm, (HPALETTE)NULL);

#ifdef _UNICODE
   Status lRes = image.Save(lpszPathname, &clsidEncoder, pParameters);
#else
   WCHAR	wPathName[MAX_PATH];
   MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPathname, _tcslen(lpszPathname)+1, wPathName, MAX_PATH);
   Status lRes = image.Save(wPathName, &clsidEncoder, pParameters);
#endif

   return (lRes == Ok);
}




///
/// Rotate and translate Graphics so that the origin is at (rect.left, rect.top)
///
BOOL SCRotateGraphics(Graphics* pGraphics, int iAngle, CRect rect, int iXPos, int iYPos)
{
	ASSERT(pGraphics);
	BOOL bOk = FALSE;
	XFORM xform;
	memset(&xform, 0, sizeof(xform));

	// Formulas:	
	//xform.eM11 = (float)cos((float)iAngle*(ST_PI)/180.0f); => 0 for PI/2 and 3PI/2, 1 for 0 and PI
	//xform.eM12 = (float)sin((float)iAngle*(ST_PI)/180.0f); => 0 for 0 and PI, 1 for PI/2 and 3PI/2

	// rotate and translate at once
	switch (iAngle)
	{
	case 90:
		xform.eM11 = 0;
		xform.eM12 = 1;
		xform.eDx = (float)(rect.bottom + iXPos);
		xform.eDy = (float)(-rect.left + iYPos);
		break;

	case 270:
		xform.eM11 = 0;
		xform.eM12 = -1;
		xform.eDx = (float)(-rect.top + iXPos);
		xform.eDy = (float)(rect.right + iYPos);
		break;

	case 180:
		xform.eM11 = -1;
		xform.eM12 = 0;
		xform.eDx = (float)(rect.right + iXPos);
		xform.eDy = (float)(rect.bottom + iYPos);
		break;

	case 0:
		xform.eM11 = 1;
		xform.eM12 = 0;
		xform.eDx = (float)(-rect.left + iXPos);
		xform.eDy = (float)(-rect.top + iYPos);
		break;

	default:
		ASSERT(0);
	}
	xform.eM22 = xform.eM11;
	xform.eM21 = -xform.eM12;

	Matrix matrix(xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
	pGraphics->SetTransform(&matrix);

	bOk = (pGraphics->GetLastStatus()==Ok);
	ASSERT(bOk);

	return bOk;
}


BOOL CALLBACK SCGDIpFlatEnumMetafile(Gdiplus::EmfPlusRecordType recordType,
											UINT flags, UINT uiEMFRecDataSize,
											const BYTE* pEMFRecData, VOID* pCallbackData)
{
	Metafile* pMetafile = (Metafile*)pCallbackData;
	pMetafile->PlayRecord(recordType, flags, uiEMFRecDataSize, pEMFRecData);
	return TRUE;
}

///
/// Convert a GDI EMF to a GDI+ (scaled, rotated, etc...) EMF
///
/// WARNING: This does NOT WORK! (complex ROP codes fail,...)
///
HENHMETAFILE SCBBoxConvertEMFtoEMFp(HENHMETAFILE hEMF,
								SCGDIpDrawingAttributes& rDrawingAttributes, EmfType eType,
								CRect& rcDest, CRect& rcMeta, CRect& PaperRect, HDC hDCPlay,
								REAL iZoom, INT iAngle, I_SCRenderingContext* pIPostRender/*=NULL*/)
{
#pragma message( __FILE__  "(1721): TODO: Fix SCBBoxConvertEMFtoEMFp ")
	ASSERT(hEMF);

	CSize sizeEMF;
	SCGetEMFPlaySize(hEMF, sizeEMF);

	hDCPlay = CreateCompatibleDC(NULL);
	HBITMAP hbm = CreateCompatibleBitmap(hDCPlay, sizeEMF.cx, sizeEMF.cy);
	HBITMAP hOldBm = (HBITMAP)SelectObject(hDCPlay, hbm);

//PRB1: the 81 dpi syndrome? (see SC_USING_TRICK81 in SCEMFImage.cpp)
//		Rect frameRect(rcMeta.left, rcMeta.top, rcMeta.Width(), rcMeta.Height());
//		Metafile* pMeta = new Metafile(hDCPlay, frameRect, MetafileFrameUnitGdi, eType);
	UNUSED(rcMeta);
	Rect frameRect(rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height());
	Metafile* pMeta = new Metafile(hDCPlay, frameRect, MetafileFrameUnitPixel, eType);
	ASSERT(pMeta->GetLastStatus()==Ok);

	// Play EMF in pMeta.
	int iPlayX = rcDest.left - PaperRect.left;
	int iPlayY = rcDest.top - PaperRect.top;
	CRect rcPlay(iPlayX, iPlayY, iPlayX + iZoom*sizeEMF.cx, iPlayY + iZoom*sizeEMF.cy);

#if 0
//PRB2: renderer does not work.
	BOOL bUseRenderer = (SCGdipGetEMFType(hEMF)!=EmfTypeEmfPlusOnly);
#else
	BOOL bUseRenderer = FALSE;
#endif

	// Note: Graphics object must be detached from the metafile before we can retrieve
	// the metafile handle; of course, post renderer must be called before detachment.
	if (bUseRenderer)
	{
		// Clip
		::IntersectClipRect(hDCPlay, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom);

		// Rotate
		int iGrOldMode;
		if (iAngle)
		{// Position of the PAGE rectangle for rotation in world coordinates
			CRect rcRotate = PaperRect;
			rcRotate.OffsetRect(iPlayX, iPlayY);
			SCRotateDC(hDCPlay, iAngle, rcRotate, rcDest.left, rcDest.top, iGrOldMode);
		}

		// Parse
		CSCEMFmetaDCRenderer renderer(pMeta);
		rDrawingAttributes.bPrinting = FALSE;
		renderer.SCSetDrawingAttributes(rDrawingAttributes);

		CSCEMFgdiParser	parser(&renderer);
		parser.SCParse(hEMF, hDCPlay, (LPRECT)&rcPlay);

		if (pIPostRender)
		{
			// restore the pre-rendering state to get a clean graphics
			parser.SCRestorePreRenderingState();
			GDPGraphics* pGraphics = renderer.SCGetGraphics();
			ASSERT(pGraphics);
			// post render
			pIPostRender->SCPostRender(hDCPlay, NULL, pGraphics);
		}
	} else
	{// Draw only
		// Note: this too has problems; a combination of 2 images (one with ROP:SRCPAINT
		// the second with ROP:SRCAND) produces a black image.
		// Where is this my responsibility in this bug?
		Metafile metafile(hEMF);
		Graphics graphics(pMeta);

		// Clip
		// You know what? GDI+ finds a way to place this clipping instruction in the metafile
		// AFTER the following FillRectangle.
		Rect rectClip(rcDest.left, rcDest.top, RECT_WIDTH(rcDest), RECT_HEIGHT(rcDest));
		graphics.SetClip(rectClip, CombineModeReplace);

		// Background
		if (rDrawingAttributes.bBkSolid)
		{
			Color BrushColor;
			BrushColor.SetFromCOLORREF(rDrawingAttributes.crPaperColor);
			SolidBrush brush(BrushColor);
			rectClip.Inflate(1, 1); // include border; otherwise clipping will be lost (!?)
			graphics.FillRectangle(&brush, rectClip);
		} // else clipping is lost

		// Rotate
		if (iAngle)
		{
			CRect rcRotate = PaperRect;
			rcRotate.OffsetRect(iPlayX, iPlayY);
			SCRotateGraphics(&graphics, iAngle, rcRotate, rcDest.left, rcDest.top);
		}

		// Draw
#if 0
		// a function is missing. I give up here.
		
		ImageAttributes imgattributes;
		if (rDrawingAttributes.crPaperColor!=RGB(255, 255, 255))
		{
			ColorMap clrMap;
			clrMap.oldColor = Color(255, 255, 255, 255);
			clrMap.newColor = BrushColor;
			imgattributes.SetRemapTable(1, &clrMap);
		}

		RectF rectImage(rcPlay.left, rcPlay.top, rcPlay.Width(), rcPlay.Height());
		// 1) call not understood
		//	graphics.DrawImage(&metafile, rectImage,
		//				rcMeta.X/100.0, rcMeta.Y/100.0,
		//				rcMeta.Width/100.0, rcMeta.Height/100.0,
		//				UnitMillimeter,
		//				&imgattributes, NULL, NULL);
		
		// 2) data is falling into ... metafile
		//	graphics.EnumerateMetafile(&metafile, rectImage,
		//				SCGDIpFlatEnumMetafile, &metafile, &imgattributes);
		
		// 3) and we can't enumerate accross metafiles
		//	graphics.EnumerateMetafile(&metafile, rectImage,
		//				SCGDIpFlatEnumMetafile, pMeta, &imgattributes);
		
		// The PlayRecord function should be a member
		// of Graphics, not of Metafile.
		// Now, my son, you see the power of a DC?
#else
		// Here, we are losing the remaining drawing attributes
		Rect rectImage(rcPlay.left, rcPlay.top, rcPlay.Width(), rcPlay.Height());
		graphics.DrawImage(&metafile, rectImage);
		if (pIPostRender)
		{
			pIPostRender->SCPostRender(hDCPlay, NULL, &graphics);
		}
#endif
	}

	HENHMETAFILE hEMFp = pMeta->GetHENHMETAFILE();
	delete pMeta;
	pMeta = NULL;

	SelectObject(hDCPlay, hOldBm);
	DeleteObject(hbm);
	DeleteDC(hDCPlay);

	ASSERT(hEMFp);
	return hEMFp;
}

///
/// Convert a GDI EMF to a GDI+ EMF (unscaled and no border)
///
/// WARNING: This does NOT WORK!
///
HENHMETAFILE SCConvertEMFtoEMFp(HENHMETAFILE hEMF,
								SCGDIpDrawingAttributes& rDrawingAttributes,
								EmfType eType)
{
#pragma message( __FILE__  "(1859): TODO: Fix SCConvertEMFtoEMFp")
	ASSERT(hEMF);
	ENHMETAHEADER EmfHeader;
	if (!::GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &EmfHeader))
		return NULL;

	CSize sizeEMF;
	SCGetEMFPlaySize(hEMF, sizeEMF);

	HDC hDCPlay = CreateCompatibleDC(NULL);
	HBITMAP hbm = CreateCompatibleBitmap(hDCPlay, sizeEMF.cx, sizeEMF.cy);
	HBITMAP hOldBm = (HBITMAP)SelectObject(hDCPlay, hbm);

//PRB1: the 81 dpi syndrome? (see SC_USING_TRICK81 in SCEMFImage.cpp)
//		Rect frameRect(0, 0, RECT_WIDTH(EmfHeader.rclFrame), RECT_HEIGHT(EmfHeader.rclFrame));
//		Metafile* pMeta = new Metafile(hDCPlay, frameRect, MetafileFrameUnitGdi, eType);
	Rect frameRect(0, 0, sizeEMF.cx, sizeEMF.cy);
	Metafile* pMeta = new Metafile(hDCPlay, frameRect, MetafileFrameUnitPixel, eType);
	ASSERT(pMeta->GetLastStatus()==Ok);

	// Play EMF in pMeta.
	CRect rcPlay(0, 0, sizeEMF.cx, sizeEMF.cy);
//PRB2: renderer does not work.
	BOOL bUseRenderer = (SCGdipGetEMFType(hEMF)==EmfTypeEmfOnly);

	// Note: Graphics object must be detached from the metafile before we can retrieve
	// the metafile handle
	if (bUseRenderer)
	{
		::IntersectClipRect(hDCPlay, rcPlay.left, rcPlay.top, rcPlay.right, rcPlay.bottom);

		CSCEMFmetaDCRenderer renderer(pMeta);

		rDrawingAttributes.bPrinting = FALSE;
		renderer.SCSetDrawingAttributes(rDrawingAttributes);

		CSCEMFgdiParser	parser(&renderer);
		parser.SCParse(hEMF, hDCPlay, (LPRECT)&rcPlay);
	}
	else
	{// Draw only (for example to just convert to/from GDI+)
		Metafile metafile(hEMF);
		Graphics graphics(pMeta);

		// background (can be deactivated before calling this function)
		if (rDrawingAttributes.bBkSolid)
		{
			Color BrushColor;
			BrushColor.SetFromCOLORREF(rDrawingAttributes.crPaperColor);
			SolidBrush brush(BrushColor);
			Rect rectBkgn(rcPlay.left, rcPlay.top, rcPlay.Width(), rcPlay.Height());
			graphics.FillRectangle(&brush, rectBkgn);
		}
	
		// draw
		Rect destRec(rcPlay.left, rcPlay.top, rcPlay.Width(), rcPlay.Height());
		graphics.DrawImage(&metafile, destRec);
	}

	HENHMETAFILE hEMFp = pMeta->GetHENHMETAFILE();
	delete pMeta;

	SelectObject(hDCPlay, hOldBm);
	DeleteObject(hbm);
	DeleteDC(hDCPlay);

	return hEMFp;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -