如何从 TextRenderInfo 获取字体高度/重量?

Bet*_*ker 1 pdf fonts itext

当我使用 iText(Sharp) 解析现有的 PDF 时,我创建了一个实现 IRenderListener 的对象,我将它传递给 PdfReaderContentParser.ProcessContent() 并且果然,我的对象的 RenderText() 被重复调用 PDF 中的所有文本。

问题是,TextRenderInfo 告诉我基本字体(在我的例子中是 Helvetica),但我无法确定字体的高度或其重量(常规与粗体)。这是 iText(Sharp) 的已知缺陷还是我遗漏了什么?

mkl*_*mkl 5

TextRenderInfo 告诉我基本字体(在我的情况下是 Helvetica),但我无法确定字体的高度或其重量(常规与粗体)

高度

不幸的是,iTextSharp 没有提供公共字体大小方法或TextRenderInfo. 有些人通过使用 itsGetAscentLine()和 its之间的距离来解决这个问题GetDescentLine()

Reflection但是,如果您准备好使用,则可以通过公开和使用私有TextRenderInfo成员来做得更好GraphicsState gs,例如在此渲染侦听器中:

public class LocationTextSizeExtractionStrategy : LocationTextExtractionStrategy
{
    //Hold each coordinate
    public List<SizeAndTextAndFont> myChunks = new List<SizeAndTextAndFont>();

    //Automatically called for each chunk of text in the PDF
    public override void RenderText(TextRenderInfo wholeRenderInfo)
    {
        base.RenderText(wholeRenderInfo);
        GraphicsState gs = (GraphicsState) GsField.GetValue(wholeRenderInfo);
        myChunks.Add(new SizeAndTextAndFont(gs.FontSize, wholeRenderInfo.GetText(), wholeRenderInfo.GetFont().PostscriptFontName));
    }

    FieldInfo GsField = typeof(TextRenderInfo).GetField("gs", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
}

//Helper class that stores our rectangle, text, and font
public class SizeAndTextAndFont
{
    public float Size;
    public String Text;
    public String Font;
    public SizeAndTextAndFont(float size, String text, String font)
    {
        this.Size = size;
        this.Text = text;
        this.Font = font;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用这样的渲染侦听器提取信息,如下所示:

using (var pdfReader = new PdfReader(testFile))
{
    // Loop through each page of the document
    for (var page = startPage; page < endPage; page++)
    {
        Console.WriteLine("\n    Page {0}", page);

        LocationTextSizeExtractionStrategy strategy = new LocationTextSizeExtractionStrategy();
        PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);

        foreach (SizeAndTextAndFont p in strategy.myChunks)
        {
            Console.WriteLine(string.Format("<{0}> in {2} at {1}", p.Text, p.Size, p.Font));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生如下输出:

    Page 1
<        The Philippine Stock Exchange, Inc> in Helvetica-Bold at 8
<       Daily Quotations Report> in Helvetica-Bold at 8
<       March 23 , 2015> in Helvetica-Bold at 8
<Name> in Helvetica at 7
<Symbol> in Helvetica at 7
<Bid> in Helvetica at 7
[...]
Run Code Online (Sandbox Code Playgroud)

考虑转换

您在输出中看到的字体大小数字是绘制相应文本时 PDF 图形状态中字体大小属性的值。

由于 PDF 的灵活性,这可能不是您最终在输出中看到的字体大小,但是,自定义转换可能会大大扩展输出。一些 PDF 制作者甚至总是使用字体大小 1 和转换来相应地拉伸输出。

要在此类文档中获得良好的字体大小值,您可以改进如下LocationTextSizeExtractionStrategy方法RenderText

public override void RenderText(TextRenderInfo wholeRenderInfo)
{
    base.RenderText(wholeRenderInfo);
    GraphicsState gs = (GraphicsState) GsField.GetValue(wholeRenderInfo);
    Matrix textToUserSpaceTransformMatrix = (Matrix) TextToUserSpaceTransformMatrixField.GetValue(wholeRenderInfo);
    float transformedFontSize = new Vector(0, gs.FontSize, 0).Cross(textToUserSpaceTransformMatrix).Length;

    myChunks.Add(new SizeAndTextAndFont(transformedFontSize, wholeRenderInfo.GetText(), wholeRenderInfo.GetFont().PostscriptFontName));
}
Run Code Online (Sandbox Code Playgroud)

使用这个额外的反射FieldInfo成员。

FieldInfo TextToUserSpaceTransformMatrixField = typeof(TextRenderInfo).GetField("textToUserSpaceTransformMatrix", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Run Code Online (Sandbox Code Playgroud)

重量

正如您在上面的输出中所看到的,字体名称可能不仅仅包含字体系列名称,还包含一个权重指示器

<       March 23 , 2015> in Helvetica-Bold at 8
Run Code Online (Sandbox Code Playgroud)

因此,在您的示例中,

TextRenderInfo 告诉我基本字体(在我的例子中是 Helvetica)

没有任何装饰的 Helvetica 将意味着正常的重量。

Helvetica 是每个 PDF 查看器必须提供即用型的标准 14 种字体之一:Times-Roman、Helvetica、Courier、Symbol、Times-Bold、Helvetica-Bold、Courier-Bold、ZapfDingbats、Times-Italic、 Helvetica-Oblique、Courier-Oblique、Times-BoldItalic、Helvetica-BoldOblique、Courier-BoldOblique。因此,这些名称非常可靠。

不幸的是,字体名称通常可以任意选择;粗体字体可能在其名称中包含“Bold”或“Black”或其他粗体指示,或者根本没有。

也可以尝试使用指定了条目FontWeight的字体的FontDescriptor字典。不幸的是,这个条目是可选的,你不能指望它在那里。

此外,PDF 中的字体可以人为加粗,参见。这个答案

所有这些数字都是使用相同的字体绘制的,只是增加了一个上升的轮廓线宽。

因此,恐怕没有可靠的方法来找到确切的字体粗细,只有一些可能会或可能不会返回可接受的近似值的启发式方法。