PDFBox:来自 PdfTextStripper 的不可见文本(不是剪辑路径或颜色问题)

PDFBox: Invisible text from PdfTextStripper (not clip path or color issue)

文件示例:test

在 table 的第 2 行,在“3500 RENT”之后 PdfTextStripper 返回了 2 个文本标记(“1”、“1”),但实际上在原始PDF。 我知道它可能是一个剪辑路径(比如 post here) or a color issue (like in the post )。

但是,在这种情况下,它看起来像是通过其他方式隐藏的...剪辑路径不重叠,并且这些标记的颜色为黑色。

还能是什么?

这是颜色问题,'1' 打印成白色。

使情况有点特别的是,正在使用的ColorSpace不是您的off-the-shelfDeviceRGBDeviceGray 但是 Separation 颜色 space,以及 Separation 颜色中的颜色值 space s 始终被视为减色。因此,0.0 的色调值表示使用给定着色剂可以获得的最浅颜色,1.0 表示最暗。此约定与 DeviceCMYK 颜色分量相同,但与 DeviceGrayDeviceRGB 的约定相反。

(参见 ISO 32000-1 第 8.6.6.4 节“分离色彩空间”)

内景

您的内容流是这样开始的:

/Cs8 cs 1 scn

Cs8分离颜色space:

/Cs8 [/Separation /Black [/ICCBased 17 0 R] 18 0 R] 

带有 ICCBased 备用 space 又具有 DeviceRGB 作为备用 space

17 0 obj
<<
/Length 2597
/Alternate /DeviceRGB
/Filter /FlateDecode
/N 3
>>
stream
[...ICC profile...]
endstream
endobj 

以及通过样本到替代颜色的色调变换 space

18 0 obj
<<
/Length 779
/BitsPerSample 8
/Decode [0 1 0 1 0 1]
/Domain [0 1]
/Encode [0 254]
/Filter /FlateDecode
/FunctionType 0
/Range [0 1 0 1 0 1]
/Size [255]
>>
stream
[...255 samples from (255,255,255) to (35,31,32)...]
endstream
endobj 

您的内容流继续绘制 headers 和第一行的开头,然后是

/TT2 1 Tf
0 scn
13.559 0 TD
6.8438 Tc
<00140014>Tj
1 scn 

0 scn 将颜色设置为最浅 Cs8 BLACK 分离颜色,由样本映射到屏幕上的 (255,255,255),这将是非常白的,6.8438 Tc设置大字符间距(导致两个'1'之间的空隙),<00140014>Tj绘制两个'1',1 scn切换回最暗的Cs8 BLACK 分离颜色由样本映射到屏幕上的 (35,31,32),这将是一种非常深的灰色。

使用 PDFBox

在评论中你说

when I debug it in processTextPosition(TextPosition text), gs.getNonStrokingColor() has same value for those "1" tokens as for others tokens and is actually black

要使用 PDFBox 识别这一点,您必须告诉它 PDFTextStripper 寻找通用颜色 space 选择和颜色选择运算符 csscn 并扩展 processTextPosition 就像这样 proof-of-concept:

PDFTextStripper stripper = new PDFTextStripper() {
    @Override
    protected void processTextPosition(TextPosition text) {
        PDGraphicsState gs = getGraphicsState();
        PDColor color = gs.getNonStrokingColor();
        float[] currentComponents = color.getComponents();
        if (!Arrays.equals(components, currentComponents)) {
            System.out.print(Arrays.toString(currentComponents));
            components = currentComponents;
        }
        System.out.print(text.getUnicode());
        super.processTextPosition(text);
    }
    
    float[] components;
};

stripper.addOperator(new SetNonStrokingColorSpace());
stripper.addOperator(new SetNonStrokingColorN());

(ExtractText 测试 testTestSeparation)

有了这些设置,您就可以得到

[1.0]TenantLeaseStart ... 3,500.00RENT[0.0]11[1.0]16,133.33

如您所见,颜色分量以 1.0 开头,对于两个“1”,它是 0.0,此后它再次变为 1.0,直到下一个 运行不可见的“1”。