Вопрос по pdf, java – Сочетание XFA с PDFBox

4

Я хотел бы заполнить форму PDF с java-библиотекой PDFBox. Форма PDF создается с помощью Adobe Live Designer, поэтому она использует формат XFA.

Я пытаюсь найти ресурсы по заполнению форм XFA PDF с помощью PDFBox, но пока мне не повезло. Я видел, что метод PDAcroForm.setXFA доступен в API, но я не вижу, как его использовать.

Знаете ли вы, можно ли заполнить форму PDF с PDFBox? Если да, есть ли где-нибудь пример кода или учебник для достижения этой цели? Если нет, каковы лучшие альтернативы для достижения этой цели?

Ваш Ответ

4   ответа
5

Вопрос конкретно определяет библиотеку PDFBox в теме; вам не нужен iText, манипулирование XFA можно выполнить с помощью объекта PDXFA, доступного в PDFBox 1.8.

Большое спасибо Маруану Сахьюну за его великолепную работу над PDFBox + XFA.

Этот код работает только при удалении всей защиты в PDDocument.
Также предполагается, что объект COS в PDXFA является COSStream. Упрощенный пример ниже читает поток XML и записывает его обратно в PDF.

 PDDocument doc = PDDocument.load("filename");
 doc.setAllSecurityToBeRemoved(true);

 PDDocumentCatalog docCatalog = doc.getDocumentCatalog();
 PDAcroForm form = docCatalog.getAcroForm();

 PDXFA xfa = form.getXFA();
 COSBase cos = xfa.getCOSObject();
 COSStream coss = (COSStream) cos;
 InputStream cosin = coss.getUnfilteredStream();
 Document document = documentBuilder.parse(cosin);

 COSStream cosout = new COSStream(new RandomAccessBuffer());
 OutputStream out = cosout.createUnfilteredStream();

 TransformerFactory tFactory = TransformerFactory.newInstance();
 Transformer transformer = tFactory.newTransformer();
 DOMSource source = new DOMSource(xmlDoc);
 StreamResult result = new StreamResult(out);
 transformer.transform(source, result);

 PDXFA xfaout = new PDXFA(cosout);
 form.setXFA(xfaout);
@JammyDodger У меня похожая проблема. Я хочу прочитать содержимое из файла XFA, используя PDFBox. Я не могу понять, как. Можете ли вы добавить код для этого или хотя бы объяснить приведенный выше код.
Код JammyDodger показывает только, как получить доступ к XML и как его вернуть. Не показывайте, как найти поля, как установить значения ... DocumentBuilder - это javax.xml.parsers.DocumentBuilder, получаемый с помощью javax.xml.parsers.DocumentBuilderFactory, насколько я вижу. неопределенная переменная xmlDoc - это документ (мое предположение)
Я использовал приведенный выше код и немного обеспокоен, так как результирующий файл довольно большой. PDF-файл начинается с 647 КБ PDF. Новый PDF 14000kb. Кто-нибудь знает, как можно уменьшить размер нового файла. Можно ли установить какой-либо тип сжатия при записи обратно в файл PDF?
В приведенном выше коде, что такое «documentBuilder» ?
2

Я не знаком с pdfbox, но вы можете сделать это с помощью iText (http://itextpdf.com/) как только вы получите доступ к XFA (XML) DOM.

я наконец выбрал itext. OutOfBound
4

Это лучшее, что мне удалось сделать за то время, которое я уделил этой проблеме. Я сохраняю PDF-файл (в жизненном цикле) как оптимизированный (я не тот, кто делает PDF-файл). Это часть открытия PDF, дублирование XML и последующее сохранение:

    PDDocument document = PDDocument.load(fileInputStream);
    fileInputStream.close();
    document.setAllSecurityToBeRemoved(true);

    Map<String, String> values = new HashMap<String, String>();
    values.put("variable_name", "value");


    setFields(document, values); // see code below

    PDAcroForm form = document.getDocumentCatalog().getAcroForm();
    Document documentXML = form.getXFA().getDocument();

    NodeList dataElements = documentXML.getElementsByTagName("xfa:data");
    if (dataElements != null) {
        for (int i = 0; i < dataElements.getLength(); i++) {
            setXFAFields(dataElements.item(i), values);
        }
    }

    COSStream cosout = new COSStream(new RandomAccessBuffer());

    TransformerFactory.newInstance().newTransformer()
            .transform(new DOMSource(documentXML), new StreamResult(cosout.createUnfilteredStream()));

    form.setXFA(new PDXFA(cosout));

    FileOutputStream fios = new FileOutputStream(new File(docOut + ".pdf"));
    document.save(fios);
    document.close();
    try {
        fios.flush();
    } finally {
        fios.close();
    }

затем методы, которые устанавливают значения для полей. Я установил XFA и AcroForm:

public void setXFAFields(Node pNode, Map<String, String> values) throws IOException {
    if (values.containsKey(pNode.getNodeName())) {
        pNode.setTextContent(values.get(pNode.getNodeName()));
    } else {
        NodeList childNodes = pNode.getChildNodes();
        if (childNodes != null) {
            for (int i = 0; i < childNodes.getLength(); i++) {
                setXFAFields(childNodes.item(i), values);
            }
        }
    }
}

public void setFields(PDDocument pdfDocument, Map<String, String> values) throws IOException {

    @SuppressWarnings("unchecked")
    List<PDField> fields = pdfDocument.getDocumentCatalog().getAcroForm().getFields();
    for (PDField pdField : fields) {
        setFields(pdField, values);
    }
}

private void setFields(PDField field, Map<String, String> values) throws IOException {
    List<COSObjectable> kids = field.getKids();
    if (kids != null) {
        for (COSObjectable pdfObj : kids) {
            if (pdfObj instanceof PDField) {
                setFields((PDField) pdfObj, values);
            }
        }
    } else {
        // remove the [0] from the name to match values in our map
        String partialName = field.getPartialName().replaceAll("\\[\\d\\]", "");
        if (!(field instanceof PDSignatureField) && values.containsKey(partialName)) {
            field.setValue(values.get(partialName));
        }
    }
}

Это работа, но не для всех "добрых" о выпуске жизненного цикла PDF, некоторые получили предупреждение о «расширенной функции» больше не включен, но все еще работает. Оптимизированная версия - единственная, которую я обнаружил, которая не открывает сообщение при открытии после заполнения.

Я заполняю XFA и Acroform, иначе он не будет работать во всех средствах просмотра.

-1

AcroForm для PDF со статическими полями. Если в PDF есть формы xfa, вы можете использовать itext (Java) или itextsharp (.net) для заполнения ваших данных. Единственная проблема с формами XFA заключается в том, что их нельзя сгладить с помощью itext. Единственный способ, с помощью которого я обнаружил использование bullzip или аналогичного средства создания PDF-файлов, чтобы открыть этот xfa-файл, созданный с использованием itext, и передать его через bullzip, который выплюнет сглаженную версию PDF. Надеюсь, это даст вам некоторые идеи.

Ниже код просто грубая идея, как заполнить xfa.

XfaForm xfa = pdfFormFields.Xfa;
dynamic bytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <form1> <staticform>" + "\r\n<barcode>" + barcode + "</barcode></staticform> <flowForm><Extra>" + Extra + "</Extra></flowForm> </form1>");
MemoryStream ms = new MemoryStream(bytes);
pdfStamper.AcroFields.Xfa.FillXfaForm(ms);

теперь вы можете использовать созданный вами xfa pdf и распечатать через bullzip

const string Printer_Name = & quot; Bullzip PDF Printer & quot ;;

                    PdfSettings pdfSettings = new PdfSettings();
                    pdfSettings.PrinterName = Printer_Name;
                    pdfSettings.SetValue("Output", flatten_pdf);
                    pdfSettings.SetValue("ShowPDF", "no");
                    pdfSettings.SetValue("ShowSettings", "never");
                    pdfSettings.SetValue("ShowSaveAS", "never");
                    pdfSettings.SetValue("ShowProgress", "no");
                    pdfSettings.SetValue("ShowProgressFinished", "no");
                    pdfSettings.SetValue("ConfirmOverwrite", "no");
                    pdfSettings.WriteSettings(PdfSettingsFileType.RunOnce);
                    PdfUtil.PrintFile(xfa_pdffile, Printer_Name);

выходной файл будет сглажен pdf ..

Ну мыalways нужен код. Так что, если вы можете предоставить, можете предоставить его.
Этот вопрос помечен как Java. Bullzip недоступен для Java!

Похожие вопросы