当我使用iText(夏普)解析现有PDF时,我创建了一个实现IRenderListener的对象,我将其传递给PdfReaderContentParser.ProcessContent(),果然,我的对象的RenderText()会被反复调用PDF中的所有文本
问题是,TextRenderInfo告诉我基本字体(在我的情况下,Helvetica),但我无法分辨字体的高度及其重量(常规与粗体)。这是iText(夏普)的已知缺陷还是我错过了什么?
答案 0 :(得分:3)
TextRenderInfo告诉我基本字体(在我的情况下,Helvetica),但我无法分辨字体的高度及其重量(常规与粗体)
不幸的是,iTextSharp在TextRenderInfo
中没有提供公共字体大小的方法或成员。有些人通过使用GetAscentLine()
和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;
}
}
您可以使用这样的渲染侦听器提取信息:
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));
}
}
}
这会产生如下输出:
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
[...]
您在输出中看到的数字字体大小是绘制相应文本时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));
}
使用此附加反射FieldInfo
成员。
FieldInfo TextToUserSpaceTransformMatrixField = typeof(TextRenderInfo).GetField("textToUserSpaceTransformMatrix", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
正如您在上面的输出中所看到的,字体名称可能包含的不仅仅是字体系列名称,还包含重量指示器
< March 23 , 2015> in Helvetica-Bold at 8
因此,在您的示例中,
没有任何装饰的Helvetica意味着正常的重量。TextRenderInfo告诉我基本字体(在我的例子中,Helvetica)
Helvetica是标准的14种字体之一,每个PDF查看器必须开箱即用:Times-Roman,Helvetica,Courier,Symbol,Times-Bold,Helvetica-Bold,Courier-Bold,ZapfDingbats,Times -Italic,Helvetica-Oblique,Courier-Oblique,Times-BoldItalic,Helvetica-BoldOblique,Courier-BoldOblique。因此,这些名称非常可靠。
不幸的是,字体名称一般可以任意选择;粗体字体可能在其名称中带有“粗体”或“黑色”或其他粗体指示,或者根本没有。
也可以尝试使用字体的 FontDescriptor 字典,并为其指定条目 FontWeight 。不幸的是,这个条目是可选的,你不能指望它完全存在。
此外,PDF中的字体可以人为加粗,参见this answer:
所有这些数字都是使用相同的字体绘制的,只是添加了一个上升的轮廓线宽。
因此,我担心没有可靠的方法来找到确切的字体粗细,只有一些启发式可能会或可能不会返回可接受的近似值。