📄 scgdiplusutils.cpp
字号:
///
/// 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 + -