【问题标题】:Typesetting text with .NET使用 .NET 排版文本
【发布时间】:2013-07-01 05:15:56
【问题描述】:

我正在编写一个 WinForms .NET 程序,该程序需要在页面上放置一些文本(带有一些基本的几何/矢量图形)。是否有相当于 OS X 的Core Graphics 和/或Core Text?到目前为止,我只是使用PrintDocument 并使用PrintPageEventArgs 提供的Graphics 对象在页面上绘制文本,但是对字间距、行间距等内容的控制很少,而且很多的东西必须手动完成。

我觉得我错过了什么;有没有更好的方法在页面上排版文本?我不介意使用第三方解决方案,只要它们可以免费供个人使用。

这将用于排版少量文件,包括一页小册子/传单(其中大多数文本是可变的,但图像是静态的)、获奖证书(其中大多数文本和图像是静态的,但有些文本是可变的) 、时间表等。

【问题讨论】:

    标签: c# .net printdocument typesetting


    【解决方案1】:

    为了放下文字:有几种可能:

    1. 一个简单的标签,可让您进行简单的文本操作(如字体、位置、颜色等)
    2. 一个富文本文档,您可以更改控件的属性以满足您的需要,请记住,此文档可能会显示一些简单的图像等。
    3. 图像 -> 您可以使用图形对象和 onpaint 事件动态创建。不建议这样做,因为它是一种非常低级别的方法,但正如您所知,级别越低,您获得的力量就越多。
    4. 许多控件的组合,在您创建的自定义控件中,您保存要在本地成员中绘制/写入的信息 -> 然后在您更改某些内容时继续,然后设置一个标志 (_needToBeRepainted = true;),然后在重新绘制时, if(_needToBeRepainted) 绘制所有内容。

    如果您需要进一步的帮助来解决这个问题,请告诉我。

    【讨论】:

      【解决方案2】:

      WinForms

      当您使用 WinForms 时,几乎不可能进行正确的类型设置,是的,几乎所有事情都必须手动完成。这有几个原因:

      1. 您没有获得详细的字形信息
      2. 无论是 GDI+ 还是基于 GDI 的版本,文本测量都非常不准确。

      Windows Presentation Foundation

      如果您使用 WPF,这是完全不同的事情,因为您可以获得有关每个字形的详细几何信息。

      但是,您可以将两者交错,虽然有点混乱,但可能。虽然,我不推荐它,因为图形和位图不能直接互换,这会导致性能下降。

      如果您想了解是否需要将System.Windows.Media 导入您的项目以访问 WPF 的字体和字形功能。

      您还会遇到其他一些挑战:

      1. WinForm 和 WPF 之间的字体列表不相同(使用 WPF 的字体和字体类型更多)。
      2. 您不能只使用 WPF 字形并将其绘制到 WinForm 位图。
      3. 正如预期的那样,字形中的值在em 中,因此需要根据点大小将它们转换为像素。

      但是,您可以获得以下(不限于)信息:

      所有详细信息(此处无法列出):
      http://msdn.microsoft.com/en-us/library/system.windows.media.glyphtypeface.aspx

      结论

      但如果您坚持使用 GDI+ 和 WinForms,您可以采取的最佳方法可能是使用基于 GDI 的 TextMetrics 类。

      在任何情况下你都会遇到可能的填充问题,你不能设置字符间距等等。

      您必须使用 top + ascent 计算每种字体和大小的基线:

      FontFamily ff = myFont.FontFamily;
      
      float lineSpace = ff.GetLineSpacing(myFont.Style);
      float ascent = ff.GetCellAscent(myFont.Style);
      float baseline =  myFont.GetHeight(ev.Graphics) * ascent / lineSpace;
      
      PointF renderPt = new PointF(pt.X, pt.Y  - baseline));
      ev.Graphics.DrawString("My baselined text", myFont, textBrush, renderPt);
      

      我不知道有任何第三方库可以在 WinForm 环境中做到这一点,我相信出于这里提到的原因以及它会带来的痛苦。

      最后,我只能建议您查看 Windows Presentation Foundation/WPF 以获得更好的基础来实现正确的类型设置,因为使用 WinForms 为此您会陷入很多妥协(我制作了一个字体查看器,它是我遇到 WPF 的地方,因为我想显示字形和有关它的详细信息,包括黑盒等 - 这已经够痛苦了)。

      更新:

      WebBrowser 作为排版引擎

      可能的解决方法是使用 WebBrowser 控件进行设置。这不是真正的 hack,而是有点 hack-ish,因为它最初对用户计算机上的 IE 浏览器建立了不必要的依赖。

      但是,当涉及到类型设置时,这会变得很灵活,因为您可以像使用任何 HTML 页面一样简单地控制文本。

      要获得结果,请附加带有文本样式和属性的 HTML。您甚至可以将它与图像等结合起来(显然)。

      例如,该控件可以位于用户不可见的另一个隐藏表单上。

      在表单上放入 WebControl 或手动创建它后,只需一步即可完成设置 HTML:

          WebBrowser1.DocumentText = "<span style='font-size:24px;'>Type-setting</span> <span style='font-family:sans-serif;font-size:18px;font-style:italic;'>using the browser component.</span>";
      

      下一步是将您呈现为 HTML 的内容作为图像抓取,可以这样做:

      using mshtml;
      using System.Drawing;
      using System.Runtime.InteropServices;
      
      [ComImport, InterfaceType((short)1), Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
      private interface IHTMLElementRenderFixed
      {
          void DrawToDC(IntPtr hdc);
          void SetDocumentPrinter(string bstrPrinterName, IntPtr hdc);
      }
      
      public Bitmap GetImage(string id)
      {
          HtmlElement e = webBrowser1.Document.GetElementById(id);
          IHTMLImgElement img = (IHTMLImgElement)e.DomElement;
          IHTMLElementRenderFixed render = (IHTMLElementRenderFixed)img;
      
          Bitmap bmp = new Bitmap(e.OffsetRectangle.Width, e.OffsetRectangle.Height);
          Graphics g = Graphics.FromImage(bmp);
          IntPtr hdc = g.GetHdc();
          render.DrawToDC(hdc);
          g.ReleaseHdc(hdc);
      
          return bmp;
      }
      

      发件人:Saving images from a WebBrowser Control

      现在您可以将位图放到您的普通页面上。 ..或者直接在表单上使用控件,减少交互能力(如果没有右键菜单很容易成为问题)。

      不知道它的确切用途,这可能是也可能不是合适的解决方案,但它提供了一些强大的选项并且可以代替第三方解决方案。

      组件

      从高处和低处看,这个区域似乎没有那么多针对性。我可以找到一个接近的组件,但模式仍在继续:一个将用大锤击中钉子。它最终与 WebBrowser 解决方法属于同一类别。

      这个组件确实是一个成熟的编辑器,但是通过禁用它的大部分,它也许可以用来简单地显示格式化的文本/图形,并且手头有类型设置:

      http://www.textcontrol.com/en_US/products/dotnet/overview/

      另一种可能是使用 PDF 组件设置内容并使用组件将 PDF 呈现为图形(商业):
      http://www.dynamicpdf.com/Generate-PDF-.NET.aspx
      http://www.dynamicpdf.com/Rasterizer-PDF-.NET.aspx

      非商业:
      http://www.pdfsharp.net/?AspxAutoDetectCookieSupport=1

      使用GhostScript获取图片:
      http://www.codeproject.com/Articles/32274/How-To-Convert-PDF-to-Image-Using-Ghostscript-API

      明显的静态替代方案

      ..也许是软木塞,但无论如何我都会把它包括在内,因为简单有时效果最好 -

      如果不是绝对要求能够动态创建这些页面,则在 Illustrator/Photoshop/inDesign 等中生成所有文本和图形,并将结果保存为要显示的图像。

      【讨论】:

      • 我不知道为什么,但我只是假设会有相当于 OS X 的核心图形和核心文本。或者至少是某种封装字符串及其属性的类。例如,OS X 的 Foundation 和 AppKit 框架有一个名为 NSAttributedString 的类,它围绕一个常规的 NSString 对象,允许您将不同的属性应用于常规旧字符串的不同部分(字体、大小、颜色,甚至字距调整)等等)。然后,您可以简单地将这个属性字符串绘制到图形上下文中。不过谢谢你的信息,我会仔细考虑的。
      • @dreamlax 我为此添加了一个可能的替代解决方案。
      • 网络浏览器肯定会花费很多精力,但是是的,相当多的额外开销;我会做一些基准测试,看看是否合适。
      • 如果使用其他 Web 渲染器之一,则可以避免使用 WebBrowser 解决方案,例如WebKit。
      • 这里肯定有足够多的信息为我指明正确的方向。 +500 给你!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 2014-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多