根据可用宽度和字体计算文本高度?

16
我们正在使用PDFsharp从数据库动态创建PDF文档。
我需要知道根据所使用的字体和可用宽度计算文本区域高度的最佳方法。
我需要知道高度,以便在需要时处理分页。
8个回答

21

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"类是什么? - Chani Poz
1
@Chanipoz:这实际上不是一个类,而是一个PDF n层应用程序,旨在帮助在代码端动态生成PDF文件。 - Will Marcouiller

10

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

没错,但是在使用PDFsharp时,您需要调用XGraphics.MeasureString。


2
这似乎不是答案。MeasureString不接受rect/width参数,因此无法知道绘制的高度 - 或者我错过了什么? - noelicus
1
使用XGraphics.MeasureString来查找单行文本的尺寸。请参考XTextFormatter类的代码,自动换行(通过使用MeasureString())。很容易添加一个新的方法XTextFormatter.MeasureString,返回高度。我们通常在应用程序中使用MigraDoc,因此我们只向文档添加文本,而MigraDoc负责处理换行和分页。 - I liked the old Stack Overflow

7

我曾遇到过类似的问题,因此我实现了这个扩展方法:

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%以使其更准确。不确定为什么,如果有人能够解释一下就很有帮助了。 - Brian Tacker

5

2

这个完美地解决了我的问题! - Afshin Rahimi

0
如果有人仍想找答案,我已经实现了一个相当容易理解的方法来查找生成文本的高度。
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

代码解释:

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

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

接下来,计算有多少行文本。这是通过将之前找到的文本总长度除以提供的矩形框的宽度来完成的。我在这里使用while循环完成。

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

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


代码没有考虑到XTextFormatter仅在单词之间添加换行符。PrintString的结果可能会偏移一行甚至更多。XTextFormatter类的源代码包含在PDFsharp中。该类旨在帮助人们入门,您可以添加分页或返回高度的输出参数。While循环可以被除法替换(但这不会改善结果)。 - I liked the old Stack Overflow
@PDFsharpTeam 我非常想知道如何做到这一点。我一直想知道为什么XTextFormatter类不会自动返回生成文本的高度。怎样才能编辑这个类呢? - Wakka02
@Wakka02 我创建了一个基于XTextFormatter的XTextFormatterEx类。编辑这个类很容易,但是我在编译时遇到了一些技术问题。完整的源代码可以在PDFsharp论坛中找到。请参见我的回答。 - I liked the old Stack Overflow

0

OP询问如何根据可用宽度和字体计算文本高度。Windows .NET提供了一个API调用,可以使用宽度参数进行计算;我正在使用的PDFsharp版本(0.9.653,.NET 1.1)没有这个功能。

我的解决方案是使用.NET API调用,并为自定义创建的位图对象分配一个Graphics对象来获取答案。

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

然后,我只需询问.NET在该位图上绘制时的像素大小即可。

您可能还需要将单位从英寸的1/100转换为点(用于PDFsharp)。

''' 适应代码 - 这不是经过测试甚至编译的 - 购买时请注意! ''' 目标:Visual Basic,.NET 1.1(VS2003)[根据需要进行调整]
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' GraphicsAlt.MeasureString() 实际上与 System.Drawing MeasureString(...,Integer) 做了相同的事情。 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' Public Module GraphicsAlt
' ' 仅用于计算下面的 MeasureString() 的静态数据。 ' ' 缓存这两个对象的单个副本,以解决一个否则无法解释的间歇性异常。 ' Private Shared myImage As Bitmap = Nothing Private Shared myGraphics As Graphics = Nothing
Public Shared Function GetMeasureGraphics() As Graphics If myImage Is Nothing Then myImage = New Bitmap(1700, 2200) '' ... 指定8.5x11 myImage.SetResolution(100, 100) '' ... 和100 DPI(如果您想要不同的单位,可以更改此设置) myGraphics = Graphics.FromImage(myImage) End If Return myGraphics End Function
'给定1/100英寸的最大宽度,返回以1/100英寸为单位的矩形 ' Public Function MeasureString(ByVal text As String, ByVal aFont As System.Drawing.Font, ByVal width As Integer) As System.Drawing.SizeF Return (GraphicsAlt.GetMeasureGraphics()).MeasureString(text, aFont, width) End Function
End Module

这听起来像是一个 hack,因为由于舍入误差、字距调整、粗体和斜体的不同处理方式,结果可能与 PDFsharp/MigraDoc 内部使用的 XGraphics.MeasureString 不同。 - I liked the old Stack Overflow

0

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

但它无法确定所需文本的高度。受@Wakka02评论的启发,我改进了这个类,生成了XTextFormatterEx类。
在我看来,它也回答了原始问题,因此我发布了一个答案。
我知道这是一个老问题,答案可能对提问者没有帮助,但这是一个经常被问到的问题,答案可能会帮助其他人。

新类有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; double neededHeight;

// 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 类的内部字段。这需要在编译类时进行特殊处理。我决定将我的 XTextFormatterEx 类复制到 PDFsharp 文件夹中,在下载完整的 PDFsharp 1.32 源码包后。
任何尝试修改 XTextFormatter 或 XTextFormatterEx 类的人都将面临同样的问题。
我希望 PDFsharp 的未来版本可以解决这个问题,允许将这些类的修改版本包含在应用程序项目中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接