Как заменить текст в PDF с правильной кодировкой с использованием Itext - PullRequest
0 голосов
/ 25 октября 2019

Я создаю Java-программу для перевода PDF-файлов. Я использую Google API для перевода. Я получаю правильный перевод на моей Eclipse IDE Console, но когда я проверяю вновь созданный pdf, либо он не переведен и не скопирован как есть, либо переведено несколько слов, либо новый pdf получается пустым и иногда поврежденным.

Я полагаю, что это как-то связано с типами кодирования и шрифтов.

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

Вот мой код:

public static final String SRC = "5587309Finnish.pdf";  

public static final String DEST = "changed.pdf";


    public static void main(String[] args) throws java.io.IOException, DocumentException {

        Translate translate = TranslateOptions.getDefaultInstance().getService();
        PdfReader reader = new PdfReader(SRC);
        int pages = reader.getNumberOfPages(); 
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(DEST));
        for(int i=1;i<=pages;i++) {
        PdfDictionary dict = reader.getPageN(i);

        PdfObject object = dict.getDirectObject(PdfName.CONTENTS);

        if (object instanceof PRStream) {
            String pageContent = 
                    PdfTextExtractor.getTextFromPage(reader, i);
            String[] word = pageContent.split(" ");

            PRStream stream = (PRStream) object;
            byte[] data = PdfReader.getStreamBytes(stream);

              String dd = new String(data, BaseFont.CP1252);


              for (int j=0; j < word.length; j++)
                {

                  Translation translation = translate.translate(word[j],Translate.TranslateOption.sourceLanguage("fi"), 
                          Translate.TranslateOption.targetLanguage("en"));
                 System.out.println(word[j]+"-->>"+translation.getTranslatedText());//here i can check the translation is correct.
                   dd = dd.replace(word[j],translation.getTranslatedText());




                }

              stream.setData(dd.getBytes());


        }
        }

        stamper.close();
        reader.close();

    }

Пожалуйста, помогите.

1 Ответ

0 голосов
/ 13 ноября 2019

Согласно комментарию, вы улучшили свой код и

получили корректно обновленный дд (т.е. поток контента, который я печатаю) с замененным текстом. Я не знаю, почему я получаю пустой pdf

. Таким образом, я предполагаю, что ваши (надеюсь репрезентативные) тестовые PDF-файлы имеют все свои представляющие интерес шрифты, закодированные в кодировках ANSI и текстовых аргументахинструкции по рисованию текста содержат целые слова или даже фразы, которые могут быть должным образом обработаны, потому что в противном случае замена текста была бы невозможна.

Таким образом, здесь приведен пример того, как можно заменить текстовые фрагменты аналогично длинными при таких благоприятных обстоятельствах. без нарушения синтаксиса потока контента. В этом примере я просто использую Map, содержащий замещающие строки. Вы можете сделать там перевод.

Сначала фрейм загружает источник, создает штамп, перебирает страницы и вызывает помощника для создания замены потока контента:

Map<String, String> replacements = new HashMap<>();
replacements.put("Förfallodatum", "Ablaufdatum");

try (   InputStream resource = SOURCE_INPUTSTREAM;
        OutputStream result = new FileOutputStream(RESULT_FILE)  ) {
    PdfReader pdfReader = new PdfReader(resource);
    PdfStamper pdfStamper = new PdfStamper(pdfReader, result);
    for (int pageNum = 1; pageNum <= pdfReader.getNumberOfPages(); pageNum++) {
        PdfDictionary page = pdfReader.getPageN(pageNum);
        byte[] pageContentInput = ContentByteUtils.getContentBytesForPage(pdfReader, pageNum);
        page.remove(PdfName.CONTENTS);
        replaceInStringArguments(pageContentInput, pdfStamper.getUnderContent(pageNum), replacements);
    }
    pdfStamper.close();
}

( EditPageContentSimple test testReplaceInStringArgumentsForklaringAvFakturan)

Метод replaceInStringArguments теперь анализирует инструкции в данном потоке содержимого, изолирует строковые аргументы и вызывает другого помощника для каждой строкиаргумент, выполняющий замену.

void replaceInStringArguments(byte[] contentBytesBefore, PdfContentByte canvas, Map<String, String> replacements) throws IOException {
    PRTokeniser tokeniser = new PRTokeniser(new RandomAccessFileOrArray(new RandomAccessSourceFactory().createSource(contentBytesBefore)));
    PdfContentParser ps = new PdfContentParser(tokeniser);
    ArrayList<PdfObject> operands = new ArrayList<PdfObject>();
    while (ps.parse(operands).size() > 0){
        for (int i = 0; i < operands.size(); i++) {
            PdfObject pdfObject = operands.get(i);
            if (pdfObject instanceof PdfString) {
                operands.set(i, replaceInString((PdfString)pdfObject, replacements));
            } else if (pdfObject instanceof PdfArray) {
                PdfArray pdfArray = (PdfArray) pdfObject;
                for (int j = 0; j < pdfArray.size(); j++) {
                    PdfObject arrayObject = pdfArray.getPdfObject(j);
                    if (arrayObject instanceof PdfString) {
                        pdfArray.set(j, replaceInString((PdfString)arrayObject, replacements));
                    }
                }
            }
        }
        for (PdfObject object : operands)
        {
            object.toPdf(canvas.getPdfWriter(), canvas.getInternalBuffer());
            canvas.getInternalBuffer().append((byte) ' ');
        }
        canvas.getInternalBuffer().append((byte) '\n');
    }
}

( EditPageContentSimple вспомогательный метод)

Метод replaceInString, в свою очередь, извлекает один строковый операнд (PdfString экземпляр), манипулирует им и возвращает версию строки с манипулированием:

PdfString replaceInString(PdfString string, Map<String, String> replacements) {
    String value = PdfEncodings.convertToString(string.getBytes(), PdfObject.TEXT_PDFDOCENCODING);
    for (Map.Entry<String, String> entry : replacements.entrySet()) {
        value = value.replace(entry.getKey(), entry.getValue());
    }
    return new PdfString(PdfEncodings.convertToBytes(value, PdfObject.TEXT_PDFDOCENCODING));
}

( EditPageContentSimple вспомогательный метод)

Вместоиз этого цикла for вы бы назвали свою процедуру перевода и перевели value.


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

...