如何使用IText确定文本的人工粗体样式和人工轮廓样式

时间:2014-01-16 22:10:53

标签: java validation pdf itext

目前我正在使用iText进行PDF评估。评估时我遇到了人工BOLD和人工大纲样式的问题。 任何人都可以帮我看看是否可以使用iText API检查PDF文档中的人工大胆样式和人工轮廓样式? 请在下面找到示例PDF:

https://docs.google.com/file/d/0BzaBYVk1XnP_SGRqRDBwTG8tVUE/edit?pli=1

1 个答案:

答案 0 :(得分:2)

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的重点文本提取。因此,您必须创建自己的文本提取策略。

通过使用以下测试渲染侦听器,您可以获得转发到您的策略的事件的第一印象(文本提取策略是特殊的渲染侦听器,具有用于请求侦听器收集的文本的附加方法;此处的示例侦听器输出到stdout;因此,不需要额外的方法):

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(笔画),相关的颜色在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中的第二个(描边),CMYK中为黑色。

因此,在渲染侦听器中,您将不得不寻找这样的文本渲染调用模式。

您可能希望首先复制LocationTextExtractionStrategy,使用呈现模式和颜色信息扩展其TextChunk辅助类,并在renderText中创建实例时相应填充这些字段。

只要消化了所有页面事件,就可以使用与LocationTextExtractionStrategy.getResultantText(TextChunkFilter)类似的方法将块粘合在一起。但是,除了现有的实现之外,您还必须检查相同(或几乎相同,参见上面的最终大纲)位置的块。如果它们包含相同的文本,并且它们的渲染模式和相关颜色显示上面的图案,则您可以使用人工粗体或轮廓文本,并且可以根据需要对其进行处理。

BTW,虽然iText转发识别这些人工样式所需的信息,但它不直接允许访问其TextRenderInfo对象中的转换矩阵。但是,你需要这个来识别人工斜体样式,正如我对PDFBox相关问题的回答中所解释的那样。但是,从版本5.4.5开始,它作为私有成员 textToUserSpaceTransformMatrix出现在那里。因此,使用反射,也可以访问该成员(如果没有安全管理员禁止它)并识别人工斜体。