【问题标题】:How to correctly scale drawing for EMF using gdi+如何使用 gdi+ 正确缩放 EMF 绘图
【发布时间】:2016-09-23 09:47:04
【问题描述】:

我的 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

【问题讨论】:

  • 似乎 EMF 是错误的标签,因为它被分配给了 Eclipse 建模框架。

标签: c++ winapi gdi+ metafile


【解决方案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 method

缩放/调整大小是客户端代码的责任,客户端代码从剪贴板接收您的图元文件并尝试显示它。元文件头包含一个指定其水平和垂直分辨率的条目。然后可以根据显示 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);

【讨论】:

    【解决方案2】:

    自我回答:

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

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

    3. 最后,添加代码行

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-31
      • 2016-02-03
      • 1970-01-01
      • 2015-11-22
      • 2010-09-14
      • 2019-08-19
      • 2014-01-20
      • 1970-01-01
      相关资源
      最近更新 更多