3

我们要:

  1. 准确测量文本。
  2. 在存在应用于图形上下文的平移和缩放变换的情况下,将文本逐行渲染到屏幕图形上下文。
  3. 命中测试:允许使用鼠标或通过显示的插入符号精确选择文本。
  4. 如果需要,使用打印机尽可能准确地打印结果。注意:这是次要的。屏幕渲染和点击测试是主要的。
  5. 在 Windows XP 和更高版本的操作系统上运行。

在同样将图形和图像渲染到相同图形上下文的 WinForms 应用程序中。

我们遇到了四种技术。我们已经尝试使用前两个,并在几个月的过程中遇到了所描述的问题。

GDI+

据称与分辨率无关的文本。然而,根据这个问题- 以及其他来源 - 由于质量问题,应避免使用该技术。

MSDN声明调用 Graphics.MeasureString StringFormat.GenericTypographicTextRenderingHint.AntiAlias产生准确的字符串测量。然而,根据我们和其他人的经验,情况并非如此——我们没有得到准确的字符串测量值。

  • 优点:快
  • 缺点:字符串测量不准确。

结果:由于字符串测量不准确而无法使用。

GDI 通过 TextRenderer

这是为了克服 GDI+ 的限制而引入的。然而,这引入了它自己的限制:

  • 非常慢
  • 不适用于图形变换

结果:由于这些原因无法使用

GDI 通过 p/invoke

调用GetTextExtentExPoint文本测量和//DrawText进行渲染。DrawTextExExtTextOut

我们还没有尝试过。

直写

这看起来很有希望,因为它与包括 GDI/GDI+ 在内的其他技术互操作,所以我们的图形渲染的其余部分可能不会改变。但是,它仅适用于 Windows Vista 和更新的 Windows 版本。这是目前的一个问题,因为 Windows XP 仍然有大量的安装基础。

问题

考虑到要求,哪些技术可以工作?

注意: 关于这个话题有很多错误信息,所以只有在你有这方面的专业知识的情况下才能回答这个问题。另外,请不要建议 WPF - 这不是我们正在考虑使用的东西。

4

3 回答 3

4

假设该MeasureCharacterRanges函数比 更准确MeasureString

于 2012-05-25T00:31:52.780 回答
3

我有类似的要求,并且在文本渲染和缩放方面遇到了同样的问题。出于多种原因,甚至我对 WPF (.NET 3.5) 的尝试都是一场噩梦。

graphics.DrawString尽管被“弃用”,但我最终还是使用了 GDI+ ,并使用了一个有趣的技巧来获得准确的文本测量值。

static public RectangleF MeasureInkBox(Graphics graphics, string text, Font font)
{
    var bounds = new RectangleF();
    using (var textPath = new GraphicsPath())
    {
        textPath.AddString(
            text,
            font.FontFamily,
            (int)font.Style,
            font.Size,
            new PointF(0, 0),
            StringFormat.GenericTypographic );
        bounds = textPath.GetBounds();
    }
    return bounds;
}

结果证明速度和质量令人满意。此外,graphics.DrawString推荐使用 winforms 打印文本的方法。

由于字距调整,测量单个字符的位置可能会很棘手,但我想这种方法稍微复杂一点的版本就可以完成这项工作。例如,对于“Hello”,它会测量“H”,然后是“He”,然后是 Hel”等等。它不应该显着降低性能,尤其是当你在接收到一个单词的点击时在飞行时执行它。

于 2012-06-29T04:02:31.497 回答
3

如果您必须同时针对屏幕和打印机,那么在决定使用哪个渲染引擎之前,您需要对您的方法做出一些决定。以下是一些可能性:

  1. 以丝网单位布局并尽可能接近打印机。
  2. 以打印机单元布局并尽可能接近屏幕。
  3. 在理论上的高分辨率空间中进行布局,并为打印机和屏幕进行最佳近似。

在所有情况下,可能的最佳近似值都可以通过在每一步非常仔细的近似值来完成,这可以为每个设备提供最高的保真度,但会以匹配的准确性为代价,或者您可以渲染位图并缩放到设备,这给出了较低的保真度,但对另一个空间是最好的近似。

我已经用 GDI 完成了硬核打印预览。这很难,但对于常规布局来说是可行的。但是,如果您要处理任意变换,尤其是 +/-90 度以外的旋转,那几乎是不可能的。

很容易犯一些细微的错误,并相信你得到的测量结果是错误的。

  • 当笔划宽度与 dpi 处于同一数量级时,字体提示使字体缩放成为非线性,因此,如果您获得w某些文本的宽度,那么将字体大小加倍时的宽度可能不完全是2*w.

  • 字体替换在许多打印机驱动程序中很常见。即使您选择 TrueType 或 OpenType 字体,您在打印机上获得的字体可能在屏幕上获得的字体不同。

  • 非方形像素在某些打印机中很常见。当你在做一些不是轴对齐的事情时,这些甚至会弄乱像样的光栅化器。

  • 字距调整可能令人惊讶。不要假设 width('a') + width('b') == width("ab")。

  • 舍入错误很容易产生。有时您必须知道底层光栅化器使用的舍入规则。

  • 在错误的环境中进行测量太常见了。不要尝试在屏幕上下文中测量并应用转换来获取打印机单位。如果您需要打印机单位,请在打印机上下文中进行测量。

我今天的观点是,如果您只需要打印预览,那么您应该以打印机为单位布局到与页面大小一致的位图,并根据 DPI 的比率将位图缩放到屏幕。这是最容易做的事情,而且效果很好。但目前尚不清楚一个好的硬拷贝和打印预览是否真的是你所追求的。

于 2012-05-25T00:16:14.643 回答