iText 确实允许您识别文档中使用的人工粗体和轮廓样式。
这些样式是如何创建的
具有人工样式的文档已经成为前一个问题How to determine artificial bold style ,artificial italic style and artificial outline style of a text using PDFBOX 的焦点,有关如何在您的文档中创建这些样式的更详细说明,可以在my answer 那里找到。
简短的总结:
人工粗体文本的创建方法是先以常规模式绘制字母,填充字母区域,然后以轮廓模式绘制,沿字母边框绘制一条线,均为黑色,CMYK 0, 0, 0, 1;这会留下字母更厚的印象。
人工轮廓文本的创建方法是先以白色、CMYK 0、0、0、0 的常规模式绘制字母,填充字母区域,然后以轮廓模式绘制,沿字母画一条线边框,黑色,CMYK 0、0、0、1;这会留下白底黑字的印象。
如何识别这些样式
了解这些样式是如何创建的,您可以尝试使用 iText 识别这些创建模式。幸运的是,iText 在其解析事件中转发了所需的信息。
很明显,iText 中包含的文本提取策略不识别开箱即用的人工样式,因为创建此类人工样式的方法有很多,而样式提取不是 iText 的重点文本提取。因此,您必须创建自己的文本提取策略。
您可以通过使用以下测试渲染侦听器来获得转发到您的策略的事件的第一印象(文本提取策略是特殊的渲染侦听器,具有用于请求侦听器收集的文本的附加方法;示例侦听器here输出到标准输出;因此,不需要额外的方法):
class StyleAnalyzer implements RenderListener
{
public void beginTextBlock() { }
public void endTextBlock() { }
public void renderImage(ImageRenderInfo renderInfo) { }
public void renderText(TextRenderInfo renderInfo)
{
System.out.printf("%s - %d - %s - %s - %s\n",
renderInfo.getBaseline().getStartPoint(),
renderInfo.getTextRenderMode(),
toString(renderInfo.getFillColor()),
toString(renderInfo.getStrokeColor()),
renderInfo.getText());
}
String toString(BaseColor color)
{
if (color instanceof CMYKColor)
{
CMYKColor cmyk = (CMYKColor) color;
return String.format("CMYK[%3.1f %3.1f %3.1f %3.1f]",
cmyk.getCyan(), cmyk.getMagenta(), cmyk.getYellow(), cmyk.getBlack());
}
return String.valueOf(color);
}
}
你可以这样使用它:
PdfReader reader = new PdfReader("artificial text.pdf");
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
System.out.println("start point - rendering mode - fill color - stroke color - text\n");
parser.processContent(1, new StyleAnalyzer());
对于人工粗体文本,对于单词“This”,您会得到如下输出(稍微重新格式化):
start point - rendering mode - fill color - stroke color - text
66.36,729.86,1.0 - 0 - CMYK[0,0 0,0 0,0 1,0] - null - T
66.36,729.86,1.0 - 1 - CMYK[0,0 0,0 0,0 1,0] - CMYK[0,0 0,0 0,0 1,0] - T
81.11,729.86,1.0 - 0 - CMYK[0,0 0,0 0,0 1,0] - null - h
81.11,729.86,1.0 - 1 - CMYK[0,0 0,0 0,0 1,0] - CMYK[0,0 0,0 0,0 1,0] - h
96.11,729.86,1.0 - 0 - CMYK[0,0 0,0 0,0 1,0] - null - i
96.11,729.86,1.0 - 1 - CMYK[0,0 0,0 0,0 1,0] - CMYK[0,0 0,0 0,0 1,0] - i
104.86,729.86,1.0 - 0 - CMYK[0,0 0,0 0,0 1,0] - null - s
104.86,729.86,1.0 - 1 - CMYK[0,0 0,0 0,0 1,0] - CMYK[0,0 0,0 0,0 1,0] - s
因此,对于每个字母,您会收到两个文本渲染调用,都在相同的位置和相同的文本,第一个在渲染模式 0 (fill),第二个在模式 1 (stroke),相关颜色在 CMYK 中始终为黑色。
对于人工大纲文本,您会得到以下“This”一词的输出(稍微重新格式化):
66.0,661.75,1.0 - 0 - CMYK[0,0 0,0 0,0 0,0] - null - T
66.0,661.75,1.0 - 1 - CMYK[0,0 0,0 0,0 0,0] - CMYK[0,0 0,0 0,0 1,0] - T
79.0,661.75,1.0 - 0 - CMYK[0,0 0,0 0,0 0,0] - null - h
79.0,661.75,1.0 - 1 - CMYK[0,0 0,0 0,0 0,0] - CMYK[0,0 0,0 0,0 1,0] - h
92.5,661.75,1.0 - 0 - CMYK[0,0 0,0 0,0 0,0] - null - i
92.5,661.75,1.0 - 1 - CMYK[0,0 0,0 0,0 0,0] - CMYK[0,0 0,0 0,0 1,0] - i
99.25,661.75,1.0 - 0 - CMYK[0,0 0,0 0,0 0,0] - null - s
99.250015,661.75,1.0 - 1 - CMYK[0,0 0,0 0,0 0,0] - CMYK[0,0 0,0 0,0 1,0] - s
因此,对于每个字母,您都会收到两个文本渲染调用,都在(几乎)相同的位置和相同的文本,第一个在渲染模式 0(fill)中使用 CMYK 中的白色,模式 1 中的第二个(stroke),CMYK 中为黑色。
因此,在您的渲染侦听器中,您将不得不寻找此类文本渲染调用模式。
您可能希望从复制LocationTextExtractionStrategy 开始,使用渲染模式和颜色信息扩展其TextChunk 帮助器类,并在renderText 中创建实例时相应地填充这些字段。
一旦消化了所有页面事件,您就可以使用类似于LocationTextExtractionStrategy.getResultantText(TextChunkFilter) 的方法将这些块粘合在一起。但是,除了现有的实现之外,您还必须检查相同(或几乎相同,请参见上面的最终大纲's')位置的块。如果它们包含相同的文本,并且它们的渲染模式和相关颜色从上方显示图案,则您可以使用人工粗体或轮廓文本,并且可以根据需要对其进行处理。
顺便说一句,虽然 iText 转发识别这些人工样式所需的信息,但它不允许直接访问其 TextRenderInfo 对象中的转换矩阵。但是,您需要这个来识别人工斜体样式,如我对 PDFBox 相关问题的回答中所述。但是,它作为 私人成员 textToUserSpaceTransformMatrix 存在于 5.4.5 版中。因此,使用反射,您也可以访问该成员(如果没有安全管理器禁止它)并识别人工斜体。