Вставить шрифты для плоской формы PDF с PDFBox - PullRequest
0 голосов
/ 29 декабря 2018

Я заполняю PDF-форму с помощью PDFBox, которую сглажаю перед сохранением.Форма имеет собственный шрифт для текста, а также поля формы.Когда я открываю выходной документ (со сглаженными полями) на устройстве, на котором не установлен этот пользовательский шрифт, шрифт обычного текста по-прежнему правильный, но шрифт сглаженных полей отображается с запасным (?) Шрифтом.На устройстве, на котором установлен этот пользовательский шрифт, все выглядит так, как ожидалось.

Есть ли способ принудительно использовать один и тот же пользовательский шрифт для всего текста после выравнивания формы?

Код (упрощенно)) используется для заполнения PDF-формы с помощью PDFBox:

public class App
{
    public static void main(String[] args) throws IOException {
        String formTemplate = "src/main/resources/fonts.pdf";
        String filledForm = "src/main/resources/fonts_out.pdf";
        PDDocument pdfDocument = PDDocument.load(new File(formTemplate));
        PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
        acroForm.getField("text").setValue("Same font in form text field (updated with PDFBox)");
        acroForm.setNeedAppearances(true);
        acroForm.refreshAppearances();
        acroForm.flatten();
        pdfDocument.save(filledForm);
        pdfDocument.close();
    }
}

PDF-файлов: Ввод Ввод

Ожидаемый:

Expected

Результат, если в системе не установлен шрифт:

Result when font is not installed on system

1 Ответ

0 голосов
/ 02 января 2019

Некоторые замечания для вашего PDF (вышеупомянутые проблемы с кодировкой отсутствуют - просто незнание от моего имени):

  1. Шрифт SansDroid не встроен в PDF.Это исправлено заменой шрифта F2 на недавно внедренный шрифт F5.

  2. Флаг NeedAppearances установлен, что означает, что поля формы не отображаются.Любой читатель должен (заново) создать их.PDFBox не делает это автоматически перед выравниванием, поэтому я добавил эту часть

  3. Чтобы не вызывать больше предупреждений об отсутствующих шрифтах, я полностью удалил шрифт F2.

  4. Я запускаю исходный PDF через предварительный просмотр, и он выдает мне следующее предупреждение: " Отсутствует требуемый ключ / подтип. Путь: -> Pages-> Kids -> [0] -> Annots -> [0] -> AP-> N"Ключ существует, однако, похоже, что возникла ошибка с появлением поля формы.Если я удалю / N, ошибка исчезнет.Поток "/ Tx BMC EMC" - возможно, отсутствует какой-либо EOL?Но поскольку в любом случае внешний вид восстанавливается, ошибка исчезает.

С помощью следующего кода шрифт DroidSans встраивается в PDF:

File pdf = new File("Fonts.pdf");
final PDDocument document = PDDocument.load(pdf);

FileInputStream fontFile = new FileInputStream(new File("DroidSans.ttf"));
PDFont font = PDType0Font.load(document, fontFile, false);

//1. embedd and register the font (Catalog dict)
PDAcroForm pDAcroForm = document.getDocumentCatalog().getAcroForm();
//create a new font resource
PDResources res = pDAcroForm.getDefaultResources();
if (res == null) res = new PDResources();
COSName fontName = res.add(font);
pDAcroForm.setDefaultResources(res);

//2. Now change the font of form field to the newly added font
PDField field = pDAcroForm.getField("text");
//field.setValue("Same font in form text field (updated with PDFBox)");

COSDictionary dict = field.getCOSObject();
COSString defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);

if (defaultAppearance != null){
    String currentValue = dict.getString(COSName.DA);
    //replace the font - this should be improved with a more general version
    dict.setString(COSName.DA,currentValue.replace("F2", fontName.getName()));

    //remove F2 completely
    COSDictionary resources = res.getCOSObject();
    for(Entry<COSName, COSBase> resource : resources.entrySet()) {
        if(resource.getKey().equals(COSName.FONT)) {
            COSObject fonts = (COSObject)resource.getValue();
            COSDictionary fontDict = (COSDictionary)fonts.getObject();

            COSName toBeRemoved=null;
            for(Entry<COSName, COSBase> item : fontDict.entrySet()) {
                if(item.getKey().getName().equals("F2")) {
                    toBeRemoved = item.getKey();
                }
            }
            if(toBeRemoved!=null) {
                fontDict.removeItem(toBeRemoved);
            }
        }
    }

if(pDAcroForm.getNeedAppearances()) {
    pDAcroForm.refreshAppearances();
    pDAcroForm.setNeedAppearances(false);
}

//Flatten the document
pDAcroForm.flatten();

//Save the document
document.save("Form-Test-Result.pdf");
document.close();

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

...