使用iTextSharp,我如何确定解析后的文本块是否加粗和加下划线?
详细说明:
我正在尝试用C#解析.PDF文件,专门用于粗体和下划线的文本。使用ITextSharp,我可以从LocationTextExtractionStrategy派生,并从传递给重写的.RenderText方法的iTextSharp.text.pdf.parser.TextRenderInfo对象中获取文本,位置,字体等。
但是,确定TextRenderInfo对象中的文本是否为粗体和/下划线并不是直截了当的。
这是我目前的尝试:
private FieldInfo _gsField = typeof(TextRenderInfo).GetField("gs",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
//Automatically called for each chunk of text in the PDF
public override void RenderText(TextRenderInfo renderInfo)
{
base.RenderText(renderInfo);
//UNDONE:Need to determine if text is underlined. How?
//NOTE: renderInfo.GetFont().FontWeight does not contain any actual information
var gs = (GraphicsState)_gsField.GetValue(renderInfo);
var textChunkInfo = new TextChunkInfo(renderInfo);
_allLocations.Add(textChunkInfo);
if (gs.Font.PostscriptFontName.Contains("Bold"))
//Add this to our found collection
FoundItems.Add(new TextChunkInfo(renderInfo));
if (!_lineHeights.Contains(textChunkInfo.LineHeight))
_lineHeights.Add(textChunkInfo.LineHeight);
}
当前尝试的完整源代码:GitHub Repository(两个示例(example.pdf和example2.pdf)包含在与我将要搜索的文本类似的文本中。)
答案 0 :(得分:2)
我尝试使用TextRenderInfo.GetFont()查找字体属性,但未成功
我目前可以通过访问TextRenderInfo对象上的私有Graphics State字段并检查它的.Font.PostscriptFontName属性来确定单词“Bold”(丑陋,但看起来有效),从而确定文本是否为Bold。 。)
我不太明白这种区别。 TextRenderInfo.GetFont()
与Font
的私有图形状态字段的TextRenderInfo
属性完全相同。
尽管如此,这确实是确定大胆的主要方法之一。
使用大胆 以PDF格式撰写
明确加粗字体(这是更好的方式);在这种情况下,可以尝试通过
确定字体是否为粗体查看字体名称:它可能包含子字符串“bold”或类似名称;
查看字体的一些可选属性,例如字体粗细,但要注意,它们是可选的......
检查嵌入的字体文件(如果适用)。
这些方法都不是万无一失的;
与非粗体文本相同的字体,但使用特殊技术使它们显示为粗体(又名穷人的粗体),例如。
不仅可以填充字形轮廓,还可以沿着它绘制更粗的线条,以获得大胆的印象,
两次绘制字形,第二次略微移位,也是一种大胆的印象。
带下划线 写入PDF通常是通过在文本下明确绘制线条或非常细的矩形来实现的。您可以通过实现IExtRenderListener
来尝试检测此类行,使用它解析相关页面以确定行位置,然后在文本提取期间与文本位置匹配。两者都可以在一次通过中完成,但要注意,不需要在文本之前绘制下划线,或者甚至不久之后,pdf生成器可以首先绘制所有文本,然后才绘制所有下划线。此外,我也遇到了一个有趣的结构,非常短(例如1pt)非常宽(例如50pt)的垂直线有效地被看作是水平的......
IExtRenderListener
使用三种新方法[{1}},IRenderListener
和ModifyPath
扩展了RenderPath
。无论何时绘制某条路径,无论是单行,矩形还是某些非常复杂的路径,您都会首先获得一些ClipPath
个调用(至少一个)
ModifyPath
定义路径所包含的行和曲线,然后最多一次/**
* Called when the current path is being modified. E.g. new segment is being added,
* new subpath is being started etc.
*
* @param renderInfo Contains information about the path segment being added to the current path.
*/
void ModifyPath(PathConstructionRenderInfo renderInfo);
调用
ClipPath
(当且仅当路径将作为以下绘图操作的剪辑路径时),最后只有一个/**
* Called when the current path should be set as a new clipping path.
*
* @param rule Either {@link PathPaintingRenderInfo#EVEN_ODD_RULE} or {@link PathPaintingRenderInfo#NONZERO_WINDING_RULE}
*/
void ClipPath(int rule);
调用
RenderPath
定义如何绘制路径(填充其内部和抚摸路径本身的任何组合)。
即。要识别下划线,您必须收集通过/**
* Called when the current path should be rendered.
*
* @param renderInfo Contains information about the current path which should be rendered.
* @return The path which can be used as a new clipping path.
*/
Path RenderPath(PathPaintingRenderInfo renderInfo);
提供的路径片段,并在ModifyPath
来电后立即决定是否可以描述一个或多个下划线。
理论上的下划线也可以不同的方式创建,例如:使用位图图像,但我不知道pdf生产者这样做。
顺便说一句,在您的示例中,PDF下划线始终显示为使用RenderPath
到行起点,MoveTo
到结尾,然后LineTo
到简单地绘制抚摸路径。因此,您将分别获得两个Stroke
个调用(一个具有操作值ModifyPath
,一个具有MOVETO
)和一个LINETO
调用(具有操作RenderPath
)每个下划线。