首页 > 解决方案 > 如何使用 Itext 用正确的编码替换 pdf 中的文本

问题描述

我创建了一个用于翻译 PDF 的 Java 程序。我正在使用谷歌 API 进行翻译。我在我的 Eclipse IDE 控制台上得到了正确的翻译,但是当我检查新创建的 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();

    }

请帮忙。

标签: javacharacter-encodingitextgoogle-translation-api

解决方案


根据评论,您已经改进了代码并且是

使用替换的文本正确获取更新 dd(即我正在打印的内容流)。我不知道为什么我得到一个空白的pdf

因此,我假设您的(希望有代表性的)测试 PDF 的所有感兴趣的字体都以 ANSI'ish 编码进行编码,并且文本绘图指令的文本参数包含可以正确处理的整个单词甚至短语,因为否则文本替换不会已经成为可能。

因此,这里是一个示例,如何在这种良性情况下用类似长的文本片段替换文本片段而不破坏内容流语法。在这个例子中,我只使用了一个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测试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这里的循环,您将调用您的翻译例程并 translate value


如前所述,此代码仅在某些良性情况下有效。不要期望它适用于来自野外的任意文档,特别是不适用于具有西欧字形以外的文档。


推荐阅读