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-shelfDeviceRGB或DeviceGray 但是 Separation 颜色 space,以及 Separation 颜色中的颜色值 space s 始终被视为减色。因此,0.0 的色调值表示使用给定着色剂可以获得的最浅颜色,1.0 表示最暗。此约定与 DeviceCMYK 颜色分量相同,但与 DeviceGray 和 DeviceRGB 的约定相反。
(参见 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 选择和颜色选择运算符 cs 和 scn 并扩展 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”。
文件示例:test
在 table 的第 2 行,在“3500 RENT”之后 PdfTextStripper
返回了 2 个文本标记(“1”、“1”),但实际上在原始PDF。
我知道它可能是一个剪辑路径(比如 post here) or a color issue (like in the post
但是,在这种情况下,它看起来像是通过其他方式隐藏的...剪辑路径不重叠,并且这些标记的颜色为黑色。
还能是什么?
这是颜色问题,'1' 打印成白色。
使情况有点特别的是,正在使用的ColorSpace不是您的off-the-shelfDeviceRGB或DeviceGray 但是 Separation 颜色 space,以及 Separation 颜色中的颜色值 space s 始终被视为减色。因此,0.0 的色调值表示使用给定着色剂可以获得的最浅颜色,1.0 表示最暗。此约定与 DeviceCMYK 颜色分量相同,但与 DeviceGray 和 DeviceRGB 的约定相反。
(参见 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 选择和颜色选择运算符 cs 和 scn 并扩展 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”。