我有一个生成荟萃(EMFS)的应用程序。它使用参考设备(又称屏幕)来渲染这些元素,因此,元数据的DPI会根据代码正在运行的机器而变化。

假设我的代码打算创建x 11英寸8.5的元数据。以我的开发工作站作为参考,我最终获得了具有的EMF

  • {0,0,21590,27940}的rclframe(mm千分之一的元素的尺寸)
  • {1440,900}的szldevice(参考设备的尺寸,以像素为单位)
  • {416,260}的szlmillimeters(参考设备的尺寸,mm)

好的,所以rclframe告诉我,EMF的大小应该是

  • 21590 /2540 = 8.5宽
  • 27940 /2540 = 11

就在。使用此信息,如果我的数学正确,我们也可以确定显示器的物理DPI:

  • (1440 * 25.4) / 416 = 87.9231水平DPI
  • (900 * 25.4) / 260 = 87.9231垂直DPI

问题

播放此元数据的任何内容 - emf-to-pdf转换,当右键单击Windows Explorer中的EMF等时的“摘要”页面,似乎可以截断计算出的DPI值,显示87而不是87.9231(甚至是87.9231) 88会没关系)。

这将导致一个页面,该页面在x 10.98英寸(使用87 dpi)中的物理尺寸为8.48,而不是8.5 in x 11 in(使用88 dpi)(使用88 dpi),当时播放了元素。

  • 是否可以更改参考设备的DPI,以便用于计算DPI的元数据中存储的信息出现到一个不错的整数中?
  • 我可以创建自己的设备上下文并指定其DPI吗?还是我真的必须使用打印机来做到这一点?

感谢您的任何见解。

有帮助吗?

解决方案

我很好奇Windows如何知道显示器的物理大小。您必须在某个地方更改配置?也许您可以将其更改为更方便的值,这些值分割得很好。

如名称所暗示的那样,必须将“设备上下文”连接到系统设备。但是,这不需要是硬件驱动程序,它可以是设备模拟器,例如PDF Writer Print驱动程序。我已经看到至少一个可以让您设置任意DPI。

其他提示

现在,我学到的比我要了解的要了解的更多。

1.一些 Metafile 班级的构造函数的过载效果不佳,并且将以截断的DPI值运行。

考虑以下:

protected Graphics GetNextPage(SizeF pageSize)
{
    IntPtr deviceContextHandle;
    Graphics offScreenBufferGraphics;
    Graphics metafileGraphics;
    MetafileHeader metafileHeader;

    this.currentStream = new MemoryStream();
    using (offScreenBufferGraphics = Graphics.FromHwnd(IntPtr.Zero))
    {
        deviceContextHandle = offScreenBufferGraphics.GetHdc();
        this.currentMetafile = new Metafile(
            this.currentStream,
            deviceContextHandle,
            new RectangleF(0, 0, pageSize.Width, pageSize.Height),
            MetafileFrameUnit.Inch,
            EmfType.EmfOnly);

        metafileGraphics = Graphics.FromImage(this.currentMetafile);

        offScreenBufferGraphics.ReleaseHdc();
    }

    return metafileGraphics;
}

如果您通过了 SizeF {8.5,11},您可能希望得到一个 Metafile 有一个 rclFrame {21590,27940}。毕竟,将英寸转换为毫米并不难。但是你可能不会。根据您的分辨率,GDI+似乎在转换英寸参数时会使用截断的DPI值。为了做对了,我必须自己以百分之一的毫米自己做,GDI+仅通过了,因为这就是它本地存储在Metafile标题中的方式:

this.currentMetafile = new Metafile(
    this.currentStream,
    deviceContextHandle,
    new RectangleF(0, 0, pageSize.Width * 2540, pageSize.Height * 2540),
    MetafileFrameUnit.GdiCompatible,
    EmfType.EmfOnly);

舍入错误#1解决了 - rclFrame 我的元数据现在是正确的。

2. DPI Graphics 实例记录到 Metafile 总是错的。

看到 metafileGraphics 我通过打电话设置的变量 Graphics.FromImage() 在metafile上?好吧,似乎 Graphics 实例将始终具有96 DPI的DPI。 (如果我不得不猜测,它总是设置为 逻辑 DPI,不是 身体的 一。)

您可以想象当您在画一个 Graphics 实例在96 DPI下运行并记录到 Metafile 实例在其标题中具有87.9231 DPI“记录”。 (我说“录制”是因为它是根据其他值计算得出的。)metafile的“像素”(请记住,存储在metafile中的GDI命令在 像素)更大,因此您诅咒和喃喃自语,为什么您要呼唤一英寸长的末端长到一英寸长的一英寸长。

解决方案是缩小 Graphics 实例:


metafileGraphics = Graphics.FromImage(this.currentMetafile);
metafileHeader = this.currentMetafile.GetMetafileHeader();
metafileGraphics.ScaleTransform(
    metafileHeader.DpiX / metafileGraphics.DpiX,
    metafileHeader.DpiY / metafileGraphics.DpiY);

那不是hoot吗?但这似乎有效。

“舍入”错误#2解决了 - 当我说在88 dpi时以“ 1英寸”画画时,Pixel最好是$%$^!记录为像素#88。

3. szlMillimeters 可以差异很大;远程桌面引起了很多乐趣。

因此,我们发现(按马克的答案),有时,Windows查询了您的显示器的EDID,并且实际上知道它的物理上有多大。 gdi+有益地使用此(HORZSIZE 等)填写 szlMillimeters 财产。

现在,想象一下您回家调试此远程桌面代码。假设您的家用计算机恰好有16:9的宽屏显示器。

显然,Windows无法查询远程显示的EDID。因此,它使用了320 x 240毫米的古老默认值,这很好,除了它恰好是4:3的纵横比,现在完全相同的代码在显示屏上生成一个元数据,据说据称具有非 - 正方形物理像素:水平DPI和垂直DPI不同,我不记得上次看到这种情况。

我现在对此的解决方法是:“好吧,不要在远程桌面下运行它。”

4.我正在使用的EMF-to-PDF工具在查看该工具时有一个舍入错误 rclFrame 标题。

这是我问题引发这个问题的主要原因。我的元素一直是“正确的”(在我修复了前两个问题之后,正确,正确的),所有这些寻求创建“高分辨率”元元的搜索都是红鲱鱼。的确,在低分辨率显示器上记录元数据时,丢失了一些保真度;这是因为在元数据中指定的GDI命令以像素指定。它是矢量格式并可以扩展或向下扩展,丢失了一些信息都没关系 在实际录制期间 当GDI+决定哪个“像素”将操作捕捉到。

我联系了供应商,他们给了我一个更正的版本。

舍入错误#3解决了。

5. Windows Explorer中的“摘要”窗格在显示计算的DPI时恰好会截断值。

碰巧的是,此截断值代表与内部使用EMF-TO-PDF工具相同的错误值。除此之外,这个怪癖对讨论没有任何意义。

结论

由于我的问题是关于在设备上下文上与DPI的期待,因此Mark's是一个很好的答案。

请注意,我一直在WXP上使用120 dpi运行(大字体),这意味着metafilegraphics.dpix将返回120。

EMF文件似乎没有记录DPI的参考上下文(在这种情况下为120,大多数其他人为96)。

为了使事情变得更有趣,可以通过绘制在内存位图上创建EMF,该内存位图将SetResolution()设置为300DPI。在这种情况下,我认为缩放因子必须是300,而不是显示器(86.x)或Windows(120)可能使用的。

摘要页面上的价值观似乎是错误的。它们计算为:

Size = round(precize_size)+1
Resolution = trunc(precize_resolution)

在不舍入或截断的情况下计算精确值的情况。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top