0

I am working on an application which is using emf for buffer drawing. I am trying to save this emf to a bitmap image file using BitBlt. But no drawings are saved to bitmap. I know I can use PlayEnhMetaFile() but I have to use BitBlt or GDI/GDI+ calls for this. As there will be some other drawing calls to emf after saving it to bitmap. Sample code.

void CTestGUIApplicationView::OnDraw(CDC* pDC)
{
CRect oRect(0, 0, 640, 434);
HDC hdc = pDC->GetSafeHdc();
//Meta file creation
int iWidthMM = GetDeviceCaps(hdc, HORZSIZE);
int iHeightMM = GetDeviceCaps(hdc, VERTSIZE);
int iWidthPels = GetDeviceCaps(hdc, HORZRES);
int iHeightPels = GetDeviceCaps(hdc, VERTRES);
CRect rect;
rect.left = (oRect.left * iWidthMM * 100) / iWidthPels;
rect.top = (oRect.top * iHeightMM * 100) / iHeightPels;
rect.right = (oRect.right * iWidthMM * 100) / iWidthPels;
rect.bottom = (oRect.bottom * iHeightMM * 100) / iHeightPels;

HDC hMetaDC = CreateEnhMetaFile(hdc, NULL, &rect, NULL);
CDC *pMetaDC = CDC::FromHandle(hMetaDC);

//Drawing on meta file DC.
RECT drawingRect;
CPen penBlue, pen2, pen3, pen4;
penBlue.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(0, 0, 255));
pen2.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(0, 255, 255));
pen3.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(255, 0, 255));
pen4.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(128, 0, 56));
auto pOldPen = pMetaDC->SelectObject(&penBlue);

pMetaDC->Arc(oRect,
    CPoint(oRect.right, oRect.CenterPoint().y),
    CPoint(oRect.CenterPoint().x, oRect.right));
pMetaDC->SelectObject(&pen2);
pMetaDC->Ellipse(oRect.left + 50, oRect.top + 25, oRect.Width(), oRect.Height());

//copy meta file to DC.
CopyToBitMap(_T("StateImage_EMFDC.bmp"), pMetaDC, oRect);

//some other drawing calls on meta file DC.
pMetaDC->SelectObject(&pen3);
pMetaDC->Ellipse(oRect.left + oRect.Width() / 2, oRect.top + oRect.Height() / 2, oRect.Width(), oRect.Height());
pMetaDC->SelectObject(pOldPen); pOldPen = NULL;

//Copy meta file to window DC.
HENHMETAFILE hMeta = CloseEnhMetaFile(pMetaDC->GetSafeHdc());
if (hMeta != NULL)
{
    //save meta file to disk to view its contents.
    HENHMETAFILE hMeta2 = CopyEnhMetaFile(hMeta, _T("test.emf"));
    DeleteEnhMetaFile(hMeta2);
    PlayEnhMetaFile(hdc, hMeta, oRect);
    DeleteEnhMetaFile(hMeta);
}
//some other drawing on Window DC.
pOldPen = pDC->SelectObject(&pen4);
pDC->Ellipse(oRect.left + 25, oRect.top + 50, oRect.Width() - 30, oRect.Height() - 60);
pDC->SelectObject(pOldPen);
CopyToBitMap(_T("StateImage_WindowDC.bmp"), pDC, oRect);
}
//Routine to copy data from DC to bitmap.
void CTestGUIApplicationView::CopyToBitMap(CString filePath, CDC* pDC, CRect & windRect)
{
//creating bitmap 
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC, windRect.Width(), windRect.Height());
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *oldBMP = memDC.SelectObject(&bitmap);
memDC.FillSolidRect(windRect, RGB(0, 255, 0));
BOOL result = BitBlt(memDC.GetSafeHdc(), 0, 0, windRect.Width() , windRect.Height(), pDC->GetSafeHdc(), 0, 0, SRCCOPY);
memDC.SelectObject(oldBMP);
//Saving bitmap to disk.
CImage image;
image.Attach(bitmap);
image.Save(filePath, Gdiplus::ImageFormatBMP);
image.Detach();
image.Destroy();
bitmap.DeleteObject();
}

"StateImage_WindowDC.bmp" have complete drawing. while "StateImage_EMFDC.bmp" is complete green image which should have drawing on it.

Rizwan Hanif
  • 153
  • 1
  • 8
  • What's wrong with playing the metafile to an HDC into which you've already selected a bitmap? From there, you can BitBlt from this bitmap to a second target. – enhzflep Sep 04 '16 at 03:07

1 Answers1

0

A metafile DC isn't like a regular DC, it doesn't draw on a bitmap; it's only used for recording drawing instructions. From Microsoft's "Enhanced Metafile Creation" page:

When CreateEnhMetaFile succeeds, it returns a handle that identifies a special metafile device context. A metafile device context is unique in that it is associated with a file rather than with an output device. When the system processes a GDI function that received a handle to a metafile device context, it converts the GDI function into an enhanced-metafile record and appends the record to the end of the enhanced metafile.

You say that you can't call PlayEnhMetaFile because you have additional drawing commands you want to append to the metafile after you capture it. In that case I can see two options:

  1. Draw to a regular DC in parallel with the metafile DC.
  2. Use GetEnhMetaFileBits and SetEnhMetaFileBits to make a copy of the metafile that you can use with PlayEnhMetaFile.
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622