【问题标题】:replace string with unicode text in pdf file using PDFbox?使用PDFbox在pdf文件中用unicode文本替换字符串?
【发布时间】:2018-11-05 20:49:47
【问题描述】:

我需要从 PDF 文件中读取字符串并将其替换为 Unicode 文本。如果是 ASCII 字符,一切都很好。但是对于 Unicode 字符,它会显示问号/垃圾文本。字体文件(ttf)没有问题我可以将 unicode 文本写入具有不同类(PDFContentStream)的 pdf 文件。使用这个类,没有替换文本的选项,但我们可以添加新文本。

示例 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;
}

【问题讨论】:

  • 您知道文本提取适用于 PDFTextStripper 类吗?您所做的是直接在内容流上工作。大约 50% 的 PDFBox 代码是用来制作真正的文本。

标签: java pdf unicode pdfbox


【解决方案1】:

您的代码完全破坏了 PDF,参见。 Adobe Preflight 输出:

原因很明显,你的代码

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

删除预先存在的页面资源,您的替换只包含一个字体,您允许 PDFBox 任意选择其名称。

您不得删除文档中使用的现有资源。


检查您的 PDF 页面的内容很明显,最初使用的字体 T1_0T1_1 的编码要么是单字节编码,要么是混合单/多-字节编码;较低的单字节值似乎是类似 ASCII 编码的。

我会假设编码是 WinAnsiEncoding 或其子集。作为推论你的任务

从 PDF 文件中读取字符串并将其替换为 Unicode 文本

不能作为简单的替换来实现,至少不能考虑任意 Unicode 代码点。


你可以实现的是:

  • 首先通过自定义文本剥离器运行源 PDF,而不是提取纯文本搜索要替换的字符串并返回它们的位置。这里有许多问题和答案向您展示了如何确定文本剥离器子类中字符串的坐标,最近的一个是this one
  • 接下来从您的 PDF 中删除这些原始字符串。在您的情况下,类似于您上面的原始代码的方法(显然不会丢弃资源),用同样长的空格字符串替换字符串可能会起作用,即使它是一个肮脏的黑客。
  • 最后在附加模式下使用PDFContentStream 在确定的位置添加替换;为此添加您的新字体到现有资源中。

但请注意,PDF 不是为这样使用而设计的。模板 PDF 可用作新内容的背景,但尝试替换其中的内容通常是一种糟糕的设计,会导致麻烦。如果您需要在模板中标记位置,请使用在填写过程中可以轻松删除的注释。或者使用原生 PDF 表单技术 AcroForm 表单。

【讨论】:

  • 嗨,mkl,建议我一种方法如何做到这一点?动态生成pdf会很困难,因为我们需要使用坐标...
  • 看看 "你可以实现的是:" 我的回答的一部分:您首先使用自定义的PDFTextStripper 确定坐标,而不是提取纯文本搜索要替换的字符串并返回它们的位置。这里有很多关于在PDFTextStripper 派生类中提取坐标的问题。
猜你喜欢
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
相关资源
最近更新 更多