Apache PDFBox 替换缺少字符的文本结果
Apache PDFBox replace text results in few character missed
尝试使用 Apache PDFBox 版本 2.0.2 进行文本替换(使用以下代码)会产生一个输出,其中少数字符不会显示,主要是大写字符。例如,用 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 替换,输出在 pdf 中显示为 "ABCDEF HIJKLM OP RST W Y "。这是一些错误吗?或者我们有一些解决方法来处理这些字符。
public static PDDocument replaceText(PDDocument document, String searchString, String replacement) throws IOException {
if (StringUtils.isEmpty(searchString) || StringUtils.isEmpty(replacement)) {
return document;
}
PDPageTree pages = document.getDocumentCatalog().getPages();
for (PDPage page : pages) {
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;
//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();
string = StringUtils.replaceOnce(string, searchString, replacement);
cosString.setValue(string.getBytes());
}
}
}
}
}
// now that the tokens are updated we will replace the page content stream.
PDStream updatedStream = new PDStream(document);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
page.setContents(updatedStream);
out.close();
}
return document;
}
引用自
https://pdfbox.apache.org/2.0/migration.html
为什么删除了 ReplaceText 示例?
ReplaceText 示例已被删除,因为它给人一种错误的错觉,即文本可以轻松替换。正如内容流的这段摘录所示,单词经常被拆分:
[ (Do) -29 (c) -1 (umen) 30 (tation) ] TJ
字体子集会出现其他问题:例如,如果只使用 a、b 和 c 的字形,它们将被编码为十六进制 0、1 和 2,因此您将找不到“abc” .此外,您不能将“c”替换为“d”,因为它不属于子集。
您也可能遇到连字问题,例如“ff”、“fl”、“fi”、“ffi”、“ffl”,在很多字体中都可以用一个代码来表示。要自己理解这一点,请使用 PDFDebugger 查看任何文件并查看页面的“内容”条目。
=========================================== =========================
根据您的描述,初始文件一直在使用字体子集,缺少字符 G、N、Q、V 和 Y。
不,没有简单的解决方法。您必须从内容流中删除不需要的文本,然后在正确的位置附加一个新的内容流,其中包含您想要的文本和新字体。
P.S。当前的 PDFBox 版本是 2.0.7,不是 2.0.2。
尝试使用 Apache PDFBox 版本 2.0.2 进行文本替换(使用以下代码)会产生一个输出,其中少数字符不会显示,主要是大写字符。例如,用 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 替换,输出在 pdf 中显示为 "ABCDEF HIJKLM OP RST W Y "。这是一些错误吗?或者我们有一些解决方法来处理这些字符。
public static PDDocument replaceText(PDDocument document, String searchString, String replacement) throws IOException {
if (StringUtils.isEmpty(searchString) || StringUtils.isEmpty(replacement)) {
return document;
}
PDPageTree pages = document.getDocumentCatalog().getPages();
for (PDPage page : pages) {
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;
//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();
string = StringUtils.replaceOnce(string, searchString, replacement);
cosString.setValue(string.getBytes());
}
}
}
}
}
// now that the tokens are updated we will replace the page content stream.
PDStream updatedStream = new PDStream(document);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
page.setContents(updatedStream);
out.close();
}
return document;
}
引用自 https://pdfbox.apache.org/2.0/migration.html
为什么删除了 ReplaceText 示例?
ReplaceText 示例已被删除,因为它给人一种错误的错觉,即文本可以轻松替换。正如内容流的这段摘录所示,单词经常被拆分:
[ (Do) -29 (c) -1 (umen) 30 (tation) ] TJ
字体子集会出现其他问题:例如,如果只使用 a、b 和 c 的字形,它们将被编码为十六进制 0、1 和 2,因此您将找不到“abc” .此外,您不能将“c”替换为“d”,因为它不属于子集。
您也可能遇到连字问题,例如“ff”、“fl”、“fi”、“ffi”、“ffl”,在很多字体中都可以用一个代码来表示。要自己理解这一点,请使用 PDFDebugger 查看任何文件并查看页面的“内容”条目。
=========================================== =========================
根据您的描述,初始文件一直在使用字体子集,缺少字符 G、N、Q、V 和 Y。
不,没有简单的解决方法。您必须从内容流中删除不需要的文本,然后在正确的位置附加一个新的内容流,其中包含您想要的文本和新字体。
P.S。当前的 PDFBox 版本是 2.0.7,不是 2.0.2。