Контекст
Я пишу код Java, который заполняет PDF-формы, используя PDFBox, с некоторыми пользовательскими данными.Некоторые входные данные написаны на китайском языке.
Когда я сгенерировал PDF, у меня не было ошибок в журналах, но отображаемый текст абсолютно не совпадает.
То, что у меня сейчас есть
Вот что я делаю:
В файле PDF я указал шрифт SimSun для поля с помощью Adobe Pro.Этот шрифт обрабатывает упрощенные китайские символы.
У меня установлен шрифт SimSun на моем сервере.
PDFBox не отображает никаких ошибок (еслиЯ удаляю шрифт SimSun со своего сервера, затем резервный PDFBox для другого шрифта, который не может отображать символы).Так что я думаю, что он может найти шрифт и использовать его.
Что я пробовал
Мне удалось сделать эту работу, но мне пришлось вручную загрузить шрифтв коде и добавьте его в PDF (см. примеры ниже).Но это не решение, так как это означает, что мне придется каждый раз загружать шрифт и добавлять его в PDF.Я также должен был бы сделать то же самое для многих других языков.
Насколько я понял, PDFBox должен иметь возможность использовать любые шрифты, установленные на сервере.
Ниже приведен тестовый класс, которыйпробует 3 разных подхода.Пока работает только последний:
Классическое поколение
Просто поместите китайские иероглифы в текстовое поле, ничего не меняя.Символы отображаются неправильно (некоторые из них отсутствуют, а отображаемые не соответствуют вводу).
![rendering-issue](https://i.stack.imgur.com/EhAgs.png)
Генерация со встроенным шрифтом
Попробуйте внедрить шрифт SimSun в PDF-файл с помощью метода PDResource.add(font)
.Результат такой же, как и в первом методе.
Вставить шрифт и использовать его
Я встраиваю шрифт SimSun и Я также перезаписываю шрифт, используемый в TextField , чтобыиспользуйте шрифт SimSun, который я только что добавил.Этот подход работает.
![correct-render](https://i.stack.imgur.com/J2kgc.png)
После нескольких чтений я обнаружил, что проблема может быть связана с версией используемого мной шрифта.Windows 8 (которую я использую для создания формы) использует v5.04 шрифта Simsun .
Я использую v2.10 на моем ноутбуке и на моих серверах.основанный на Linux (я не могу найти v5.04).
Однако я не знаю:
- Если проблема действительно в этом.
- Если у меня есть право использовать этот шрифт, так как он разработан Microsoft (и Apple).
- Где найти его последнюю версию.
Я пытался использоватьдругой шрифт, но:
Так что, если у кого-то есть идея о том, как сделать это без необходимости вставлять и изменять имя шрифта в коде, это будетбудьте великолепны!
Вот PDF-файл, который я использовал , и код, который тестирует 3 метода, о которых я говорил.TextField в PDF-файле называется comment
.
package org.test;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Hello world!
*/
public class App {
private static final String SIMPLIFIED_CHINESE_STRING = "我不明白为什么它不起作用。";
public static void main(String[] args) throws IOException {
System.out.println("Hello World!");
// Test 1
classicGeneration();
// Test 2
generationWithEmbededFont();
Test 3
generationWithFontOverride();
System.out.println("Bye!");
}
/**
* Classic PDF generation without any changes to the PDF.
*/
private static void classicGeneration() throws IOException {
PDDocument document = loadPdf();
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
PDField commentField = acroForm.getField("comment");
commentField.setValue(SIMPLIFIED_CHINESE_STRING);
document.save(new File("result-classic-generation.pdf"));
}
/**
* Trying to embed the font in the PDF. It doesn't seem to work.
* The result is the same as classicGeneration method.
*/
private static void generationWithEmbededFont() throws IOException {
PDDocument document = loadPdf();
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
PDFont font = PDType0Font.load(document, new File("/usr/share/fonts/SimSun.ttf"));
PDResources res = acroForm.getDefaultResources();
if (res == null) {
res = new PDResources();
}
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
PDField commentField = acroForm.getField("comment");
commentField.setValue(SIMPLIFIED_CHINESE_STRING);
document.save(new File("result-with-embeded-font.pdf"));
}
/**
* Embed the font in the PDF and change the font used in the TextField to use this one.
* Here the PDF is correctly rendered and all the characters are displayed.
* @throws IOException
*/
private static void generationWithFontOverride() throws IOException {
PDDocument document = loadPdf();
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
PDField commentField = acroForm.getField("comment");
// Load the font
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("SimSun.ttf");
PDFont font = PDType0Font.load(document, resourceAsStream);
PDResources res = acroForm.getDefaultResources();
if (res == null) {
res = new PDResources();
}
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
// Change the font used by the TextField
COSDictionary dict = commentField.getCOSObject();
COSString defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);
if (defaultAppearance != null) {
String currentFont = dict.getString(COSName.DA);
// Retrieve the current font size and color used for the field in order to use the same but with the new font.
String regex = "[\\w]* ([\\w\\s]*)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(currentFont);
// Default font size if we fail to extract the current one
String fontSize = " 11 Tf";
if (matcher.find()) {
fontSize = " " + matcher.group(1);
}
// Change the font of the TextField.
dict.setString(COSName.DA, "/" + fontName.getName() + fontSize);
}
commentField.getCOSObject().addAll(dict);
commentField.setValue(SIMPLIFIED_CHINESE_STRING);
document.save(new File("result-with-font-override.pdf"));
}
// HELPER
private static PDDocument loadPdf() throws IOException {
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("sample.pdf");
return PDDocument.load(stream);
}
}