Проследите весь PDF и измените некоторый атрибут с каким-либо объектом в нем, используя iText

Я работаю над программой-фильтром, которая превращает каждый черный текстовый блок в серый в файле PDF. Я прошел com.itextpdf.text.pdf.parser и не могу найти что-то подходящее для этой функции.

PS: я использую iTextSharp 5.5.10, для которого я не могу найти подходящий документ. Документы для iText5, кажется, работают в большинстве случаев, но есть разница. Есть ли документ для iTextSharp?

1 ответ

ОП уточнил свой вопрос в комментарии:

Мне интересно как написать парсер вроде 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 только проверяет и редактирует поток контента самой страницы, а не потоки контента отображаемых форм или шаблонов; таким образом, некоторый текст может быть не найден.

Совершенствование класса для правильного определения черного цвета, а также для рекурсивного обхода и редактирования потоков содержимого используемых шаблонов и xobjects остается в качестве упражнения для читателя.

Используйте этот подход, чтобы изменить цвет. Я использую приведенный ниже код для изменения цвета гиперссылок.

            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);
    }
}
Другие вопросы по тегам