заменить строку с текстом Unicode в PDF-файл, используя PDFbox? - PullRequest
0 голосов
/ 26 мая 2018

Мне нужно прочитать строки из PDF-файла и заменить его текстом Unicode. Если это ASCII-символы, все в порядке.Но с символами Unicode он показывает вопросительные знаки / нежелательный текст. Нет проблем с файлом шрифта (ttf). Я могу записать текст Unicode в файл PDF с другим классом (PDFContentStream).С этим классом нет возможности заменить текст, но мы можем добавить новый текст.

Образец текста Unicode

Bɐɑɒ

проблема (столбец адреса)

https://drive.google.com/file/d/1DbsApTCSfTwwK3txsDGW8sXtDG_u-VJv/view?usp=sharing

Я использую PDFBox.Пожалуйста, помогите мне с этим .....

проверьте код, который я использую .....

    enter image description herepublic static PDDocument _ReplaceText(PDDocument document, String searchString, String replacement)
        throws IOException {
    if (StringUtils.isEmpty(searchString) || StringUtils.isEmpty(replacement)) {
        return document;
    }

    for (PDPage page : document.getPages()) {

        PDResources resources = new PDResources();
        PDFont font = PDType0Font.load(document, new File("arial-unicode-ms.ttf"));
        //PDFont font2 = PDType0Font.load(document, new File("avenir-next-regular.ttf"));
        resources.add(font);
        //resources.add(font2);
        //resources.add(PDType1Font.TIMES_ROMAN);
        page.setResources(resources);
        PDFStreamParser parser = new PDFStreamParser(page);
        parser.parse();
        List tokens = parser.getTokens();

        for (int j = 0; j < tokens.size(); j++) {
            Object next = tokens.get(j);
            if (next instanceof Operator) {
                Operator op = (Operator) next;

                String pstring = "";
                int prej = 0;

                // Tj and TJ are the two operators that display strings in a PDF
                if (op.getName().equals("Tj")) {
                    // Tj takes one operator and that is the string to display so lets update that
                    // operator
                    COSString previous = (COSString) tokens.get(j - 1);
                    String string = previous.getString();
                    string = string.replaceFirst(searchString, replacement);
                    previous.setValue(string.getBytes());
                } else if (op.getName().equals("TJ")) {
                    COSArray previous = (COSArray) tokens.get(j - 1);
                    for (int k = 0; k < previous.size(); k++) {
                        Object arrElement = previous.getObject(k);
                        if (arrElement instanceof COSString) {
                            COSString cosString = (COSString) arrElement;
                            String string = cosString.getString();

                            if (j == prej) {
                                pstring += string;
                            } else {
                                prej = j;
                                pstring = string;
                            }
                        }
                    }

                    if (searchString.equals(pstring.trim())) {
                        COSString cosString2 = (COSString) previous.getObject(0);
                        cosString2.setValue(replacement.getBytes());

                        int total = previous.size() - 1;
                        for (int k = total; k > 0; k--) {
                            previous.remove(k);
                        }
                    }
                }
            }
        }

        // now that the tokens are updated we will replace the page content stream.
        PDStream updatedStream = new PDStream(document);
        OutputStream out = updatedStream.createOutputStream(COSName.FLATE_DECODE);
        ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
        tokenWriter.writeTokens(tokens);
        out.close();
        page.setContents(updatedStream);
    }

    return document;
}

1 Ответ

0 голосов
/ 28 мая 2018

Ваш код полностью нарушает PDF, ср.вывод Adobe Preflight:

Preflight output

Причина очевидна: ваш код

PDResources resources = new PDResources();
PDFont font = PDType0Font.load(document, new File("arial-unicode-ms.ttf"));
resources.add(font);
page.setResources(resources);

отбрасывает ранее существующую страницу Ресурсы и ваша замена содержит только один шрифт, имя которого вы позволяете PDFBox выбирать произвольно.

Вы не должны удалять существующие ресурсы, поскольку они используются в вашем документе.


При проверке содержимого вашей страницы PDF становится очевидным, что кодировка первоначально используемых шрифтов T1_0 и T1_1 либо является однобайтовой кодировкой, либосмешанное однобайтовое кодирование;младшие однобайтовые значения выглядят как ASCII-подобные.

Я бы предположил, что кодировка WinAnsiEncoding или ее подмножество.Как следствие, ваша задача

прочитать строки из PDF-файла и заменить его текстом Unicode

не может быть реализована как простая замена, по крайней мере, с произвольнойНужно помнить код Unicode.


Вместо этого вы можете реализовать:

  • Сначала запустите исходный PDF-файл через специальный инструмент для удаления текста, который вместо извлечения простого текста ищетваши строки заменить и вернуть свои позиции.Здесь есть множество вопросов и ответов, которые показывают вам, как определить координаты строк в подклассах стриппера текста, в последнее время этот .
  • Затем удалите эти оригинальные строки из вашего PDF.В вашем случае подход, аналогичный исходному коду выше (очевидно, без удаления ресурса), замена строк одинаково длинными строками пробелов может сработать, даже если это грязный хак.
  • Наконец добавьте свои замены вопределенные позиции, используя PDFContentStream в режиме добавления;для этого добавьте ваш новый шрифт к существующим ресурсам.

Однако имейте в виду, что PDF не предназначен для такого использования.Шаблоны PDF можно использовать в качестве фона для нового контента, но попытка заменить контент в нем обычно является плохим дизайном, приводящим к неприятностям.Если вам нужно пометить позиции в шаблоне, используйте аннотации, которые можно легко удалить во время заполнения.Или используйте для начала формы AcroForm, встроенную технологию PDF-форм.

...