遍历整个PDF和改变一些属性与一些对象在它使用iText



我正在制作一个过滤器程序,它可以将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);
    }
}

最新更新