【问题标题】:Calculate text height based on available width and font?根据可用宽度和字体计算文本高度?
【发布时间】:2010-10-28 10:17:38
【问题描述】:

我们正在使用 PDFsharp 从数据库中动态创建 PDF 文档。

我需要知道计算文本区域高度的最佳方法 关于使用的字体和可用宽度。

我需要知道高度,以便在需要时处理分页符。

【问题讨论】:

    标签: .net formatting pdfsharp


    【解决方案1】:

    在 .NET 中,您可以调用 Graphics.MeasureString 来了解绘制文本的大小。

    【讨论】:

      【解决方案2】:

      PdfSharp.Drawing.XGraphics 对象有一个 MeasureString 方法,可以返回您需要的内容。

       var pdfDoc = new PdfSharp.Pdf.PdfDocument();
       var pdfPage = pdfDoc.AddPage();
       var pdfGfx = PdfSharp.Drawing.XGraphics.FromPdfPage(pdfPage);
       var pdfFont = new PdfSharp.Drawing.XFont("Helvetica", 20);
      
       while (pdfGfx.MeasureString("Hello World!").Width > pdfPage.Width)
            --pdfFont.Size;
      
       pdfGfx.DrawString("Hello World!", pdfFont
            , PdfSharp.Drawing.XBrushes.Black
            , new PdfSharp.Drawing.XPoint(100, 100));
      

      这应该对您有所帮助。请考虑到我没有测试这段代码,因为我是为了提供帮助而即时编写的。它可能包含一些编译时错误,但您可能会明白。

      【讨论】:

      • 什么是“PdfSharp”类?
      • @Chanipoz:这实际上不是一个类,这是一个 PDF n 层应用程序,用于帮助在代码端动态生成 PDF 文件。
      【解决方案3】:

      在 .NET 中,您可以调用 Graphics.MeasureString 了解如何 绘制的文本会变大。

      没错,但是当使用 PDFsharp 时,您调用 XGraphics.MeasureString。

      【讨论】:

      • 这似乎不是答案。 MeasureString 不采用矩形/宽度,因此无法知道绘制的高度 - 还是我错过了什么?
      • 使用 XGraphics.MeasureString 查找单行文本的尺寸。有关自动换行的代码(通过使用 MeasureString()),请参见 XTextFormatter 类。添加一个返回高度的新方法 XTextFormatter.MeasureString 应该很容易。我们通常在我们的应用程序中使用 MigraDoc,因此我们只向文档添加文本,而 MigraDoc 关心换行符和分页符。
      【解决方案4】:

      OP 询问如何根据可用宽度 和字体计算文本高度。 Windows .NET 为此提供了一个 API 调用,它接受一个宽度参数;我使用的 PDFsharp 版本(0.9.653,.NET 1.1)没有。

      我的解决方案 - 使用 .NET API 调用和为自定义创建的 Bitmap 对象分配的 Graphics 对象来获得答案。

      对我有用的是使用具有 100 DPI 分辨率(关键)并且恰好是纵向页面大小的位图(可能不太关键)。

      然后我只是询问 .NET 在该位图上绘制的像素大小是多少。

      然后您可能希望将单位从 1/100 英寸转换为磅(对于 PDFsharp)。

      ''' 改编代码 - 这未经测试甚至编译 - 警告 Emptor! ''' 目标:Visual Basic、.NET 1.1 (VS2003) [根据需要调整] ''''''''''''''''''' ' GraphicsAlt.MeasureString() 的作用与 System.Drawing MeasureString(...,Integer) 的作用基本相同。 ''''''''''''''''''' 公共模块 GraphicsAlt ' ' 静态数据仅用于计算下面的 MeasureString()。 ' ' 缓存这两个对象的单个副本,以解决其他无法解释的间歇性异常。 ' 私人共享 myImage 作为位图 = 无 私人共享 myGraphics 作为图形 = 没有 公共共享函数 GetMeasureGraphics() 作为图形 如果 myImage 什么都不是,那么 myImage = New Bitmap(1700, 2200) '' ... 指定 8.5x11 myImage.SetResolution(100, 100) '' ... 和 100 DPI(如果你想要不同的单位,你可以改变这个) myGraphics = Graphics.FromImage(myImage) 万一 返回我的图形 结束功能 '给定 1/100TH 英寸最大宽度,返回 Rect 以保持单位 1/100TH 英寸 ' 公共函数 MeasureString(ByVal text As String, ByVal aFont As System.Drawing.Font, ByVal width As Integer) As System.Drawing.SizeF 返回 (GraphicsAlt.GetMeasureGraphics()).MeasureString(text, aFont, width) 结束功能 端模块

      【讨论】:

      • 这听起来像是一个 hack,因为由于舍入错误、字距调整、粗体和斜体的不同处理,结果可能与 PDFsharp/MigraDoc 内部使用的 XGraphics.MeasureString 不同。
      【解决方案5】:

      我有一个类似的问题,所以我实现了这个扩展方法:

      public static double MeasureHeight(this PdfSharp.Drawing.XGraphics gfx, string text, PdfSharp.Drawing.XFont font, int width)
      {
          var lines = text.Split('\n');
      
          double totalHeight = 0;
      
          foreach (string line in lines)
          {
              var size = gfx.MeasureString(line, font);
              double height = size.Height + (size.Height * Math.Floor(size.Width / width));
      
              totalHeight += height;
          }
      
          return totalHeight;
      }
      

      【讨论】:

      • 这对我来说是一个快速而简单的解决方案。但是,我确实注意到,在执行 size.Height * Math.Floor(size.Width / width) 时,它有时会低估宽度(或者 TextFormatter 在包装文本时可能会高估宽度)。所以我不得不将宽度值增加大约 15% 以使其更准确。不知道为什么,如果有人能解释一下会有所帮助。
      【解决方案6】:

      如果有人仍然想找到答案,我已经实现了一个相当容易理解的方法来找出结果文本的高度。

      Public Function PrintString(text As String, ft As XFont, rect As XRect, graph As XGraphics, b As SolidBrush, Optional tf As XTextFormatter = Nothing) As Integer
          If Not IsNothing(tf) Then
              tf.DrawString(text, ft, b, rect)
          Else
              Dim drawLeft As New XStringFormat
              drawLeft.Alignment = XStringAlignment.Near
      
              graph.DrawString(text, ft, b, rect, drawLeft)
          End If
      
          Dim width As Double = graph.MeasureString(text, ft).Width
          Dim multiplier As Integer = 0
      
          While width > 0
              multiplier += 1
      
              width -= rect.Width
          End While
      
          Dim height As Double = (graph.MeasureString(text, ft).Height) * multiplier
          Return height
      End Function
      

      解释代码:

      首先,打印文本。我包含了一个名为 tf 的可选 XTextFormatter,因为我在我的应用程序中可以互换使用 XGraphics 或 XTextFormatters。

      然后,通过 MeasureString().Width 计算文本的长度。

      然后,计算有多少行文本。这是通过将之前找到的文本的总长度除以提供的打印税款的矩形(框)的宽度来完成的。我在这里使用了一个while循环。

      将文本的高度(使用 graph.MeasureString().Height)乘以行数。这是文本的最终高度。

      返回高度值。现在,调用 PrintString() 函数将打印提供的文本,然后返回打印文本的高度。

      【讨论】:

      • 代码没有考虑到 XTextFormatter 只在单词之间添加换行符。 PrintString 的结果可能偏离一行甚至多行。 XTextFormatter 类的源代码包含在 PDFsharp 中。此类旨在让人们开始使用,您可以添加分页符或返回高度的 out 参数。 While 循环可以用除法代替(但这不会改善结果)。
      • @PDFsharpTeam 我非常想知道如何做到这一点。我一直想知道为什么 XTextFormatter 类不会自动返回结果文本的高度。如何编辑课程?
      • @Wakka02 我创建了一个基于 XTextFormatter 的 XTextFormatterEx 类。编辑这个类很容易,但我在编译它时遇到了一些技术问题。完整的源代码可以在 PDFsharp 论坛中找到。请参阅我对这个问题的回答。
      【解决方案7】:

      PDFsharp 包含一个 XTextFormatter 类,可用于绘制带有换行符的文本。

      但是它不能确定文本所需的高度。受@Wakka02 评论的启发,我改进了这个类,生成了 XTextFormatterEx 类。
      我认为它也回答了原始问题,因此我发布了答案。
      我知道这是一个老问题,答案可能对 OP 没有帮助,但这是一个常见问题,答案可能对其他人有所帮助。

      新类有 500 行代码 - 我认为这对于这篇文章来说太多了。

      源代码可以在PDFsharp论坛上找到:
      http://forum.pdfsharp.net/viewtopic.php?p=9213#p9213

      也可以在我不起眼的博客中找到:
      http://developer.th-soft.com/developer/pdfsharp-improving-the-xtextformatter-class-measuring-the-height-of-the-text/

      在使用新类时,您可以先调用PrepareDrawString 来了解文本适合多少以及适合文本的高度。然后您的解码器可以绘制准备好的文本或准备另一个文本或使用不同的矩形准备相同的文本。

      我的新班级: XTextFormatterEx tf = new XTextFormatterEx(gfx); int lastCharIndex; 双倍需要高度;

      // Draw the text in a box with the optimal height
      // (magic: we know that one page is enough).
      XRect rect = new XRect(40, 100, 250, double.MaxValue);
      //tf.Alignment = ParagraphAlignment.Left;
      tf.PrepareDrawString(text, font, rect,
                           out lastCharIndex, out neededHeight);
      rect = new XRect(40, 100, 250, neededHeight);
      gfx.DrawRectangle(XBrushes.SeaShell, rect);
      // Both variants should look the same.
      
      // Optimized version: draw the prepared string.
      tf.DrawString(XBrushes.Black, XStringFormats.TopLeft);
      

      准备文本会多次调用 MeasureString。稍后无需再次调用 MeasureString 即可绘制准备好的文本。

      截至今天(2015 年 7 月 17 日),XTextFormatterEx 类(与原来的 XTextFormatter 一样)使用 XFont 类的内部字段。这需要在编译类时进行特殊处理。在下载 PDFsharp 1.32 的完整源代码包后,我决定将我的 XTextFormatterEx 类复制到 PDFsharp 文件夹中。
      任何尝试修改 XTextFormatter 或 XTextFormatterEx 类的人都将面临同样的问题。
      我希望未来版本的 PDFsharp 可以解决这个问题,允许将这些类的修改版本包含在应用程序项目中。

      【讨论】:

        【解决方案8】:

        我为 XGraphic 对象编写了一个小的扩展方法来做到这一点:通过指定 maxWidth 来计算确切的文本高度(和宽度)。 有关代码,请参阅以下要点:https://gist.github.com/erichillah/d198f4a1c9e8f7df0739b955b245512a

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-28
          • 1970-01-01
          • 2017-02-23
          • 2013-08-26
          • 1970-01-01
          相关资源
          最近更新 更多