【问题标题】:Searching PDF for Underlined and Bolded text在 PDF 中搜索带下划线和粗体的文本
【发布时间】:2018-09-08 21:24:34
【问题描述】:

使用 iTextSharp,我如何确定已解析的文本块是否同时加粗和加下划线?

详情:
我正在尝试在 C# 中解析 .PDF 文件,专门针对粗体和下划线的文本。使用 ITextSharp,我可以从 LocationTextExtractionStrategy 派生并从传递给重写的 .RenderText 方法的 iTextSharp.text.pdf.parser.TextRenderInfo 对象中获取文本、位置、字体等。
但是,从 TextRenderInfo 对象确定文本是否为粗体和/下划线并不容易。

  • 我尝试使用 TextRenderInfo.GetFont() 查找字体属性,但未成功
  • 我目前可以确定文本是否为粗体,方法是访问 TextRenderInfo 对象上的私有图形状态字段并检查它的 .Font.PostscriptFontName 属性中是否有“粗体”一词(丑陋,但似乎可以工作。)
  • 最大的问题:我没有找到任何东西来确定文本是否带下划线。我该如何确定?

这是我目前的尝试:

        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.pdfexample2.pdf)包含在类似于我将要搜索的文本中。)

【问题讨论】:

  • @Ryan 这并不是真正的重复,该问题和答案集中在一个特定的 pdf 上,该操作的大胆识别失败了。这个问题是关于更一般的情况。
  • @RyanSingh 另外,这是关于检测粗体文本,我已经可以做到(尽管该链接显示了更好的方法)。它不包括下划线文本,这是我没有答案的部分

标签: c# pdf search itext


【解决方案1】:
  • 我尝试使用 TextRenderInfo.GetFont() 查找字体属性,但未成功

  • 我目前可以确定文本是否为粗体,方法是访问 TextRenderInfo 对象上的私有图形状态字段并检查它的 .Font.PostscriptFontName 属性中是否有单词“Bold”(丑陋,但似乎可以工作.)

我不太明白这种区别。 TextRenderInfo.GetFont()TextRenderInfo 的私​​有 Graphics State 字段的 Font 属性完全相同。

话虽如此,但这确实是确定胆量的主要方法之一。

粗体在 PDF 中的书写是通过使用

实现的
  • 显式粗体字体(这是更好的方法);在这种情况下,可以尝试通过

    来确定字体是否为粗体
    • 查看字体名称:它可能包含子字符串“bold”或类似的内容;

    • 查看字体的一些可选属性,例如字体粗细,但请注意,它们是可选的...

    • 检查嵌入的字体文件(如果适用)。

    这些方法都不是万无一失的;

  • 与非粗体文本的字体相同,但使用特殊技术使它们显得粗体(又名穷人的粗体),例如

    • 不仅可以填充字形轮廓,还可以沿着它画一条更粗的线,以获得大胆的印象,

    • 绘制字形两次,第二次略微移位,也是为了给人一种大胆的印象。

下划线 在 PDF 中的书写通常是通过在文本下方显式地绘制一条线或一个非常细的矩形来实现的。您可以尝试通过实现IExtRenderListener 来检测此类行,用它解析有问题的页面以确定行位置,然后在文本提取期间与文本位置匹配。两者也可以一次性完成,但请注意,下划线不需要在文本之前绘制,甚至不需要在其后不久绘制,pdf 制作者可能首先绘制所有文本,然后才绘制所有下划线。此外,我还遇到了一个有趣的结构,非常短(例如 1pt)非常宽(例如 50pt)的垂直线实际上被视为水平线......

IExtRenderListener 扩展了IRenderListener 三个新方法ModifyPathRenderPathClipPath。每当绘制某个路径时,无论是单条线、矩形还是一些非常复杂的路径,您都会首先得到许多 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 提供的路径片段,并在RenderPath 调用到来时决定它们是否可以描述一个或多个下划线。

理论上,下划线也可以以不同的方式创建,例如使用位图图像,但我不知道 pdf 制作者这样做。

顺便说一句,在您的示例中,PDF 下划线似乎始终使用MoveTo 绘制到行的起点,使用LineTo 绘制到它的结尾,然后使用Stroke 来简单地描边路径。因此,对于每个下划线,您将分别获得两个ModifyPath 调用(一个具有操作值MOVETO,一个具有LINETO)和一个RenderPath 调用(具有操作STROKE)。

【讨论】:

  • 虽然我似乎在 IExtRenderListener.PaintPath 方法中看到了下划线,但我不知道它们是在哪里绘制的。如何从传递给方法的 PathPaintingRenderInfo 对象中获取线条的位置?
  • 我在回答中添加了IExtRenderListener 接口的简短说明。本质上,您首先通过其ModifyPath 获取路径部分,然后以下RenderPath(我假设您在编写 PaintPath 时是指该方法)告诉您这些部分是如何绘制的。
  • 我在使用 Example2.pdf 之类的文档时遇到了下划线算法的问题(链接添加有问题)它遵循 MOVETO 后跟 LINETO 的相同模式,但是 MOVETO 始终为 (0 ,0) 并且 LINETO 始终为 ({Negative number}, 0) 此外,渲染信息对象具有非标准变换矩阵,其中 value[Matrix.I31] 类似于 Right Margin X 坐标,并且 value [Matrix.I32]在750到780之间,是否可以得到下划线的绝对坐标?
  • 是的。只需将 MoveTo 和 LineTo 坐标与当前变换矩阵相乘即可​​。
  • 我刚刚检查了您的 Example2.pdf。如上所述下划线在PDF中的书写通常是通过在文本下方显式地绘制一条线或一个非常细的矩形来实现的。第二个文档中的下划线没有得到 MOVETO 和 LINETO,因为在那里下划线是使用细矩形创建的,即你得到一个 ModifyPath 调用,操作为 RECT
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-15
  • 1970-01-01
  • 2011-05-18
  • 2012-07-20
相关资源
最近更新 更多