我正在制作一个过滤器程序,它可以将PDF文件中的每个黑色文本块变成灰色文本块。我已经遍历了com.itextpdf.text.pdf.parser,但找不到适合这个函数的东西。
PS:我使用的是iTextSharp 5.5.10,我找不到合适的文档。iText5的文档似乎在大多数情况下都可以工作,但仍然有区别。有iTextSharp的文档吗?
OP在评论中澄清了他的问题:
我想知道如何编写像
PdfTextExtractor
或其他东西的解析器。我期待BaseParser
之类的东西,但什么也没找到。所以我错过了我的方式。
如果你正在寻找类似编辑框架的东西,你可以使用这个答案中提供的PdfContentStreamEditor。
基于PdfContentStreamEditor,你可以像这样编辑PDF页面的内容流:
PdfReader pdfReader = new PdfReader(resource);
PdfStamper pdfStamper = new PdfStamper(pdfReader, result);
PdfContentStreamEditor editor = new PdfContentStreamEditor()
{
@Override
protected void write(PdfContentStreamProcessor processor, PdfLiteral operator, List<PdfObject> operands) throws IOException
{
String operatorString = operator.toString();
if (TEXT_SHOWING_OPERATORS.contains(operatorString))
{
if (currentlyReplacedBlack == null)
{
BaseColor currentFillColor = gs().getFillColor();
if (BaseColor.BLACK.equals(currentFillColor))
{
currentlyReplacedBlack = currentFillColor;
super.write(processor, new PdfLiteral("rg"), Arrays.asList(new PdfNumber(0), new PdfNumber(1), new PdfNumber(0), new PdfLiteral("rg")));
}
}
}
else if (currentlyReplacedBlack != null)
{
if (currentlyReplacedBlack instanceof CMYKColor)
{
super.write(processor, new PdfLiteral("k"), Arrays.asList(new PdfNumber(0), new PdfNumber(0), new PdfNumber(0), new PdfNumber(1), new PdfLiteral("k")));
}
else if (currentlyReplacedBlack instanceof GrayColor)
{
super.write(processor, new PdfLiteral("g"), Arrays.asList(new PdfNumber(0), new PdfLiteral("g")));
}
else
{
super.write(processor, new PdfLiteral("rg"), Arrays.asList(new PdfNumber(0), new PdfNumber(0), new PdfNumber(0), new PdfLiteral("rg")));
}
currentlyReplacedBlack = null;
}
super.write(processor, operator, operands);
}
BaseColor currentlyReplacedBlack = null;
final List<String> TEXT_SHOWING_OPERATORS = Arrays.asList("Tj", "'", """, "TJ");
};
for (int i = 1; i <= pdfReader.getNumberOfPages(); i++)
{
editor.editPage(pdfStamper, i);
}
pdfStamper.close();
(ChangeTextColor.java test testChangeBlackTextToGreenDocument
)
在PdfContentStreamEditor中,write
方法在内容流中的每个指令被调用并将其写回来。通过重写此方法并将部分不同的指令转发给超类write
,可以编辑流。
这个实现展示了如何改变给定颜色的文本的颜色。在本例中,黑色文本变为绿色。
注意,这只是一个概念验证,而不是最终和完整的解决方案。特别是
- 文本被认为是黑色的,如果其
color
表达式BaseColor.BLACK.equals(color)
是true
;由于BaseColor
及其后代类之间的相等性没有完全定义,这可能会导致一些误报。 -
PdfContentStreamEditor
只检查和编辑页面本身的内容流,不检查显示的表单对象或模式的内容流;因此,有些文本可能找不到。
改进类以正确地检测黑色,并递归地遍历和编辑所使用的模式和xobject的内容流,对于读者来说仍然是一个练习。
使用这种方法来改变颜色。我使用下面的代码来改变超链接的颜色。
PdfCanvasEditor editor = new PdfCanvasEditor() {
@Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
{
String operatorString = operator.toString();
if (SET_FILL_RGB.equals(operatorString) && operands.size() == 4) {
if (isApproximatelyEqual(operands.get(0), 0) &&
isApproximatelyEqual(operands.get(1), 0) &&
isApproximatelyEqual(operands.get(2), 1)) {
super.write(processor, new PdfLiteral("g"), Arrays.asList(new PdfNumber(0), new PdfLiteral("g")));
return;
}
}
if (SET_STROKE_RGB.equals(operatorString) && operands.size() == 4) {
if (isApproximatelyEqual(operands.get(0), 0) &&
isApproximatelyEqual(operands.get(1), 0) &&
isApproximatelyEqual(operands.get(2), 1)) {
super.write(processor, new PdfLiteral("G"), Arrays.asList(new PdfNumber(0), new PdfLiteral("G")));
return;
}
}
super.write(processor, operator, operands);
}
boolean isApproximatelyEqual(PdfObject number, float reference) {
return number instanceof PdfNumber && Math.abs(reference - ((PdfNumber)number).floatValue()) < 0.01f;
}
final String SET_FILL_RGB = "rg";
final String SET_STROKE_RGB = "RG";
};
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
editor.editPage(pdfDocument, i);
}
}