1

我的 windows c++ 程序创建 EMF(增强的元文件格式)以导出到剪贴板、word 和 excel。

以下示例代码生成一个只有 12x12 的 EMF 矩形 (width=height=25),而画布为 25x25(注意:我的笔记本电脑的屏幕分辨率为 3600x1800)。在其他屏幕分辨率下,也会出现类似的缩放异常(太大/太小)。看起来图形绘图的缩放需要设置为分辨率的函数。我在这里的知识显然有差距......任何帮助表示赞赏。

HDC ref_dc = GetDC(NULL);
Rect r(0, 0, 25, 25);
Metafile* emf = new Metafile(ref_dc, r, MetafileFrameUnitPixel, EmfTypeEmfPlusDual, L"Drawing");//to HDC
Graphics* g = new Graphics(emf);

//draw a simple box
Gdiplus::Pen* pen = new Pen(Color(0, 255, 0), 1.0f);
pen->SetDashStyle(DashStyleSolid);
pen->SetLineCap(LineCapRound, LineCapRound, DashCapFlat);
g->DrawRectangle(pen, r);    // DrawMyObject(g);

// code here to put on clipboard
4

2 回答 2

1

尽管与您的实际问题无关,但我不得不指出您在堆上创建所有对象的编程风格很奇怪。没有理由这样使用new。只需在堆栈上创建临时对象。这可以防止您泄漏内存和其他资源(如筛子)。举例来说,您所需要的只是:

// Create Graphics object
Graphics g(emf);

// Draw a simple box
Gdiplus::Pen pen(Color(0, 255, 0), 1.0f);
pen.SetDashStyle(DashStyleSolid);
pen.SetLineCap(LineCapRound, LineCapRound, DashCapFlat);
g.DrawRectangle(pen, r);

// g and pen automatically go out of scope here, implicitly calling the destructor
// and freeing their resources. No need to call delete.

至于您的实际问题,元文件没有固定大小。它们基本上只是封装了一系列可以随意概括的GDI绘图指令。

将增强的元文件放在剪贴板上的正常方法是调用SetClipboardData函数,使用CF_ENHMETAFILE格式。句柄类型显然是HENHMETAFILE. 您需要让 GDI+ 为您提供其中之一,可能在您完成加载/创建图元文件对象后使用该Metafile::GetHENHMETAFILE方法。

缩放/调整大小是客户端代码的责任,客户端代码从剪贴板接收您的元文件并尝试显示它。元文件头包含一个指定其水平和垂直分辨率的条目。然后可以根据显示 DPI 进行缩放。在 GDI+ 中,类似:

Graphics g(...);

Metafile mf(L"MyFile.emf");
MetafileHeader mfh;
mf->GetMetafileHeader(&mfh);

REAL xScale = mfh->GetDpiX() / g.GetDpiX();
REAL yScale = mfh->GetDpiY() / g.GetDpiY();

g.ScaleTransform(xScale, yScale);
于 2016-05-25T16:53:11.937 回答
0

自我回答:

  1. 图形是用“新”创建的,因为它必须在 EMF 被“写入”之前被销毁。否则 emf 不会“记录”Graphics 对象执行的步骤。也许我们应该多放一套牙套,但这同样尴尬。根据文档:“当 Graphics 对象被删除或超出范围时,录制结束。” 因此显式的 new(s) 和 delete(s)。EMF 在 Graphics 销毁后和 EMF 销毁之前被推送到剪贴板。

  2. *错误/问题似乎是由使用包含 Rect 结构作为参数的 EMF 的构造函数引起的。Rect 尺寸似乎与用于绘图的图形对象坐标没有明显的关系,因此它以不可预测的方式裁剪生成的 EMF。使用只有 HDC 或 HDC 和文件名的构造函数可以解决这个问题,至少在我手中是这样。

  3. 最后,添加代码行

    真正的 xScale = mfh->GetDpiX() / g.GetDpiX(); REAL yScale = mfh->GetDpiY() / g.GetDpiY(); g.ScaleTransform(xScale, yScale);

提供了一个基本缩放比例,这样无论屏幕分辨率如何,emfs 的大小或多或少都相似。这对于在用户端为导出提供一致/合理的默认大小非常有用。

于 2016-05-26T16:30:22.487 回答