【问题标题】:PDFBox: Invisible text from PdfTextStripper (not clip path or color issue)PDFBox:来自 PdfTextStripper 的不可见文本(不是剪辑路径或颜色问题)
【发布时间】:2018-04-26 13:56:06
【问题描述】:

文件示例:test

在表格的第 2 行,在“3500 RENT”之后,PdfTextStripper 返回了 2 个文本标记(“1”、“1”),但实际上在原始 PDF 中不可见。 我知道这可能是剪辑路径(如帖子here)或颜色问题(如帖子here)。

但是,在这种情况下,它似乎被其他方式隐藏了......剪辑路径不重叠,并且这些标记的颜色为黑色。

还能是什么?

【问题讨论】:

    标签: java pdf pdfbox


    【解决方案1】:

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

    使情况有点特别的是,使用的 ColorSpace 不是您现成的 DeviceRGBDeviceGray 而是一个Separation 颜色空间,Separation 颜色空间中的颜色值始终被视为减色。因此,0.0 的色调值表示使用给定着色剂可以实现的最亮颜色,而 1.0 表示最暗。此约定与 DeviceCMYK 颜色分量相同,但与 DeviceGrayDeviceRGB 的约定相反。

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

    内部视图

    您的内容流开始如下:

    /Cs8 cs 1 scn
    

    Cs8是一个Separation色彩空间:

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

    具有 ICCBased 备用空间,而该备用空间又具有 DeviceRGB 作为备用空间

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

    以及通过采样到备用色彩空间的色调变换

    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 
    

    您的内容流继续绘制标题和第一行开头的操作,然后

    /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' 之间的间隙中),&lt;00140014&gt;Tj 绘制了两个 '1',1 scn 切换回由样本映射到 (35,31,32) 的最暗 Cs8 BLACK 分色屏幕上的颜色将是非常深的灰色。

    带PDFBox

    在你说的评论中

    当我在processTextPosition(TextPosition text) 中调试它时,gs.getNonStrokingColor() 对那些“1”标记与其他标记具有相同的值,实际上是黑色的

    要使用 PDFBox 识别这一点,您必须告诉其 PDFTextStripper 查找通用颜色空间选择和颜色选择运算符 csscn 并扩展 @987654334 @like 在这个概念验证中:

    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”。

    【讨论】:

    • 但是,当我在 processTextPosition(TextPosition text) 中调试它时, gs.getNonStrokingColor() 对于那些“1”标记与其他标记具有相同的值,实际上是黑色的......这是其他的吗财产我可以查处理吗?在此先感谢 看起来没有其他人知道这个 PDFBox 库...
    • @DmitryK 我在答案中添加了一个概念验证,以展示如何查看这些颜色变化。
    • 好吧,但这是否意味着 [0.0] 总是意味着文本不可见?看起来没有,因为在其他文档中 float[] currentComponents = color.getComponents();是 [0.0] 字符在屏幕上可见。所以这并不能完全说明文本是不可见的......
    • 这些数字的含义当然要根据色彩空间来确定。在上面的代码中,我仅表明您声称 PDFBox 将“1”和其他文本的颜色都报告为黑色,如果注册了适当的运算符,则该声明是错误的。
    • 哦,知道了,所以在 SetNonStrokingColorSpace 我应该得到这个颜色空间定义,然后在 processTextPosition 中使用它?
    猜你喜欢
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2011-08-08
    • 1970-01-01
    • 2013-11-11
    • 2016-10-19
    相关资源
    最近更新 更多