PDFBOX acroForm 已填充,但在 Acrobat 阅读器中打开时,值消失 [英] PDFBOX acroForm filled but when opened in Acrobat reader values disappears

查看:70
本文介绍了PDFBOX acroForm 已填充,但在 Acrobat 阅读器中打开时,值消失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 PDF 表格,我想用 PDFBOX 填写它.它有效,表单已填写,我用其他阅读器或浏览器打开,我可以看到值,但是当我尝试在 Adob​​e Reader 中打开时,值消失了,我尝试了各种可能的方法来找出原因但值不可见.

我有模板表单,我使用它并填写数据、重命名字段并将其合并到其他文档中,然后重做该过程,直到填写完所有表单.

我不确定这是否与我的代码或 Adob​​e 阅读器有关.

我需要填写的 PDF 表格链接

这是我填充表单的代码.

<预><代码>抽象类 AbstractPDFFormFiller;{私有 val 记录器 = LogManager.getLogger()私有 val 合并 = PDFMergerUtility()私人 VAL PAGE_SIZE = 12fun fillForm(templatePath: String, data: List, headerParam: Map): PDDocument {val 块 = getDataChunks(data)val totalPages = chunks.size如果(总页数 == 1){val sourceDocument = getTemplate(templatePath)val 表单 = sourceDocument.documentCatalog.acroFormfillHeader(form, headerParam, totalPages, totalPages, data)填充数据(表单,数据,总页数)返回源文档} 别的 {val resultDocument = PDDocument()chunks.forEachIndexed { currentPage, it ->val sourceDocument = getTemplate(templatePath)val 表单 = sourceDocument.documentCatalog.acroFormfillHeader(form, headerParam, currentPage, totalPages, it)填充数据(表单,它,当前页)//合并PDFForm(resultDocument, sourceDocument)sourceDocument.save(C:\\Users\\\\Documents\\Downloads\\$currentPage.pdf")sourceDocument.close()}mergeFromDisk(File("C:\\Users\\Documents\\Downloads"),resultDocument)返回结果文档}}有趣的 mergeFromDisk(folderPath:File, resultDoc:PDDocument){folderPath.listFiles()?.forEach {合并PDFForm(resultDoc,PDDocument.load(它))}}私人乐趣合并PDFForm(目的地:PDDocument,来源:PDDocument){尝试 {source.documentCatalog.acroForm.flatten()merge.acroFormMergeMode = PDFMergerUtility.AcroFormMergeMode.JOIN_FORM_FIELDS_MODEmerge.appendDocument(目的地,来源)merge.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly())} catch (e: 异常) {e.printStackTrace()}}fun getTemplate(templatePath: String): PDDocument {val s = javaClass.classLoader?.getResource(templatePath)?.openStream()返回 PDDocument.load(s)}private fun getDataChunks(data: List): List>{返回 data.chunked(PAGE_SIZE)}有趣的 setValue(形式:PDAcroForm,完全限定名称:字符串,值:字符串,重命名:布尔 = 假,reNameTo:字符串?){val 字段 = form.getField(fullyQualifiedName)field.setValue(值)如果(重命名)重命名字段(形式=形式,fullQualifiedName = fullQualifiedName,newName = "${field.fullyQualifiedName}_$reNameTo";)}fun renameField(form: PDAcroForm,fullyQualifiedName: String, newName: String) {val 字段 = form.getField(fullyQualifiedName)?: throw IllegalArgumentException(未找到 $fullyQualifiedName 的字段")if (field.actions != null && field.actions.f != null) field.actions.f = null尝试 {field.partialName = newName} catch (e: 异常) {logger.fatal(无法重命名为 PDF 表单名称 {} 到新名称 {}",fullyQualifiedName, newName)}}抽象的乐趣 fillHeader(形式:PDAcroForm,地图:地图<字符串,字符串>,当前页面:整数,总页数:Int,数据:列表<T>)抽象有趣的填充数据(表单:PDAcroForm,数据:列表<T>,当前页面:Int)}类 DiversionDataFormFiller : AbstractPDFFormFiller() {私有 val 记录器 = LogManager.getLogger()覆盖乐趣 fillHeader(形式:PDAcroForm,地图:地图<字符串,字符串>,当前页面:整数,总页数:Int,数据:列表){form.getField("Product Type").setValue(map["Product Type"])form.getField("Type of Schedule").setValue(map["Type of Schedule"])form.getField("LA Revenue Account Number").setValue(map["LA Revenue Account Number"])form.getField("Company Name").setValue(map["Company Name"])form.getField("Filling Period").setValue(map["Filling Period"])form.getField("Page").setValue((currentPage + 1).toString())form.getField("of").setValue(totalPage.toString())form.getField("Total").setValue(data.stream().mapToDouble(DiversionData::quantity).sum().toString())renameField(form, "Product Type", "Product Type_$currentPage")renameField(form, "Type of Schedule", "Type of Schedule_$currentPage")renameField(form, "LA Revenue Account Number", "LA Revenue Account Number_$currentPage")renameField(form, "Company Name", "Company Name_$currentPage")renameField(form, "Filling Period", "Filling Period_$currentPage")renameField(form, "Total", "Total_$currentPage")renameField(form, "Page", "Page_$currentPage")renameField(form, of", of_$currentPage")}覆盖乐趣填充数据(表单:PDAcroForm,数据:列表,当前页面:Int){val fieldTree = form.fieldTreedata.forEachIndexed { i, element ->fieldTree.forEach {if (it.fieldType == "Tx") {尝试 {if (it.fullyQualifiedName.startsWith(Date") && it.partialName == i.toString()) {记录器.信息(将 {} 重命名为 {},{}",it.fullyQualifiedName,${it.fullyQualifiedName}_$currentPage",it.partialName)/* it.setValue(Util.dateToStr(element.date, "MM/dd/yy"))renameField(form, it.fullyQualifiedName, "${it.partialName}_$currentPage")*/设定值(形式,it.fullyQualifiedName,Util.dateToStr(element.date, "MM/dd/yy"),真的,$currentPage")} else if (it.fullyQualifiedName.startsWith("Name2") && it.partialName == i.toString()){it.setValue(element.shipperTaxPayerNumber)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Name") && it.partialName == i.toString()){it.setValue(element.supplierTaxPayerNumber)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Diversion Number") && it.partialName == i.toString()){it.setValue(element.importNumber)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("FEIN2") && it.partialName == i.toString()){it.setValue(element.shipperTaxPayerNumber)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("FEIN") && it.partialName == i.toString()){it.setValue(element.supplierTaxPayerNumber)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Mode") && it.partialName == i.toString()){it.setValue("J")renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Manifest") && it.partialName == i.toString()){it.setValue(element.billOfLading)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Doc. Number") && it.partialName == i.toString()){it.setValue(element.billOfLading)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("Net gallons") && it.partialName == i.toString()){it.setValue(element.quantity.toString())renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")} else if (it.fullyQualifiedName.startsWith("New") && it.partialName == i.toString()){it.setValue(element.revisedDestination)renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")}} 捕获(例如:IOException){ex.printStackTrace()}}}}}}

数据类定义

数据类 DiversionData(val 终端IRSCode:字符串,val FuelType:字符串,val 供应商TaxPayerNumber:字符串,val shipperTaxPayerNumber:字符串,价值数量:双,val originalDestination: 字符串,val 修订目的地:字符串,val importNumber:字符串?,生效日期:本地日期,val billOfLading:字符串,)

测试填写表格

 @Testpublic void fillFormUsingNewKotlinClass() 抛出 IOException {列表diversionData = new ArrayList<>();for (int i = 0; i <20; i++) {DiversionData d = 新的 DiversionData(终端代码"+我,常规"+我,供应商税"+我,托运人税"+我,1000 + 我,TX",洛杉矶",0000"+我,LocalDate.now().plusDays(i),123456"+我);diversionData.add(d);}//E:/​​repo/gasjobber-docker/gasjobber-api/src/main/resources/字符串路径 = "templates/taxFormsPDF/LA/5402(7_06)F.pdf";DiversionDataFormFiller 填充器 = new DiversionDataFormFiller();映射<字符串,字符串>param = new HashMap<>();param.put(产品类型",065");param.put("Type of Schedule","22");param.put(LA 收入帐号",3264660001");param.put(公司名称",测试公司");param.put("Filling Period","2020-12");PDDocument 文档 = fillForm(path,diversionData,param);document.save(new File("C:\\Users\\Documents\\Downloads\\testpdf.pdf"));文档.close();}

解决方案

页面 /AA/O 条目(打开页面时应执行的操作")具有以下内容:

if (!bReset){this.resetForm();bReset = true;}

所以表单被重置了.

即使手动填写表单并保存、关闭并重新打开,也会发生这种情况.也许这是formupack"的演示版本这是故意的.

您可以通过像这样删除页面/AA 条目来防止这种情况

document.getPage(0).setActions(null);

或者只是删除/O 条目

document.getPage(0).getActions().setO(null);

I have PDF form, I am trying to fill it with PDFBOX. It works, form is filled and I open with other reader or browser, I can see values, however When I tries to open in Adobe Reader values disappears, I tried every possible way to find out why But values, are not visible.

I have template form, that I use and fill data, rename fields, and merge it into other document, and redo that process until all forms are filled up.

I am not sure if this related to my code or Adobe reader.

Link to PDF form I need to fill

here is my code to populate form.


abstract class AbstractPDFFormFiller<T> {

    private val logger = LogManager.getLogger()
    private val merge = PDFMergerUtility()

    private val PAGE_SIZE = 12

    fun fillForm(templatePath: String, data: List<T>, headerParam: Map<String, String>): PDDocument {
        val chunks = getDataChunks(data)
        val totalPages = chunks.size

        if (totalPages == 1) {
            val sourceDocument = getTemplate(templatePath)
            val form = sourceDocument.documentCatalog.acroForm
            fillHeader(form, headerParam, totalPages, totalPages, data)
            fillData(form, data, totalPages)
            return sourceDocument
        } else {
            val resultDocument = PDDocument()
            chunks.forEachIndexed { currentPage, it ->
                val sourceDocument = getTemplate(templatePath)
                val form = sourceDocument.documentCatalog.acroForm
                fillHeader(form, headerParam, currentPage, totalPages, it)
                fillData(form, it, currentPage)
//                mergePDFForm(resultDocument, sourceDocument)
                sourceDocument.save("C:\\Users\\\\Documents\\Downloads\\$currentPage.pdf")
                sourceDocument.close()
            }
            mergeFromDisk(File("C:\\Users\\Documents\\Downloads"),resultDocument)
            return resultDocument
        }
    }

    fun mergeFromDisk(folderPath:File, resultDoc:PDDocument){
        folderPath.listFiles()?.forEach {
            mergePDFForm(resultDoc, PDDocument.load(it))
        }
    }

    private fun mergePDFForm(destination: PDDocument, source: PDDocument) {
        try {
            source.documentCatalog.acroForm.flatten()
            merge.acroFormMergeMode = PDFMergerUtility.AcroFormMergeMode.JOIN_FORM_FIELDS_MODE
            merge.appendDocument(destination, source)
            merge.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun getTemplate(templatePath: String): PDDocument {
        val s = javaClass.classLoader?.getResource(templatePath)?.openStream()
        return PDDocument.load(s)
    }

    private fun getDataChunks(data: List<T>): List<List<T>> {
        return data.chunked(PAGE_SIZE)
    }

    fun setValue(
        form: PDAcroForm,
        fullyQualifiedName: String,
        value: String,
        rename: Boolean = false,
        reNameTo: String?
    ) {
        val field = form.getField(fullyQualifiedName)
        field.setValue(value)
        if (rename)
            renameField(
                form = form,
                fullyQualifiedName = fullyQualifiedName,
                newName = "${field.fullyQualifiedName}_$reNameTo"
            )
    }

    fun renameField(form: PDAcroForm, fullyQualifiedName: String, newName: String) {
        val field = form.getField(fullyQualifiedName)
            ?: throw IllegalArgumentException("Field with $fullyQualifiedName not found")
        if (field.actions != null && field.actions.f != null) field.actions.f = null
        try {
            field.partialName = newName
        } catch (e: Exception) {
            logger.fatal("Cannot rename to PDF form name {} to new name {}", fullyQualifiedName, newName)
        }
    }


    abstract fun fillHeader(
        form: PDAcroForm,
        map: Map<String, String>,
        currentPage: Int,
        totalPage: Int,
        data: List<T>
    )

    abstract fun fillData(form: PDAcroForm, data: List<T>, currentPage: Int)
}


class DiversionDataFormFiller : AbstractPDFFormFiller<DiversionData>() {
    private val logger = LogManager.getLogger()

    override fun fillHeader(
        form: PDAcroForm,
        map: Map<String, String>,
        currentPage: Int,
        totalPage: Int,
        data: List<DiversionData>
    ) {
        form.getField("Product Type").setValue(map["Product Type"])
        form.getField("Type of Schedule").setValue(map["Type of Schedule"])
        form.getField("LA Revenue Account Number").setValue(map["LA Revenue Account Number"])
        form.getField("Company Name").setValue(map["Company Name"])
        form.getField("Filling Period").setValue(map["Filling Period"])
        form.getField("Page").setValue((currentPage + 1).toString())
        form.getField("of").setValue(totalPage.toString())
        form.getField("Total").setValue(data.stream().mapToDouble(DiversionData::quantity).sum().toString())
        renameField(form, "Product Type", "Product Type_$currentPage")
        renameField(form, "Type of Schedule", "Type of Schedule_$currentPage")
        renameField(form, "LA Revenue Account Number", "LA Revenue Account Number_$currentPage")
        renameField(form, "Company Name", "Company Name_$currentPage")
        renameField(form, "Filling Period", "Filling Period_$currentPage")
        renameField(form, "Total", "Total_$currentPage")
        renameField(form, "Page", "Page_$currentPage")
        renameField(form, "of", "of_$currentPage")
    }

    override fun fillData(form: PDAcroForm, data: List<DiversionData>, currentPage: Int) {
        val fieldTree = form.fieldTree
        data.forEachIndexed { i, element ->
            fieldTree.forEach {
                if (it.fieldType == "Tx") {
                    try {
                        if (it.fullyQualifiedName.startsWith("Date") && it.partialName == i.toString()) {
                            logger.info(
                                "renaming {} to {}, {}",
                                it.fullyQualifiedName,
                                "${it.fullyQualifiedName}_$currentPage",
                                it.partialName
                            )
/*                            it.setValue(Util.dateToStr(element.date, "MM/dd/yy"))
                            renameField(form, it.fullyQualifiedName, "${it.partialName}_$currentPage")*/
                            setValue(
                                form,
                                it.fullyQualifiedName,
                                Util.dateToStr(element.date, "MM/dd/yy"),
                                true,
                                "$currentPage"
                            )
                        } else if (it.fullyQualifiedName.startsWith("Name2") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.shipperTaxPayerNumber)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Name") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.supplierTaxPayerNumber)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Diversion Number") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.importNumber)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("FEIN2") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.shipperTaxPayerNumber)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("FEIN") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.supplierTaxPayerNumber)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Mode") && it.partialName == i.toString()
                        ) {
                            it.setValue("J")
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Manifest") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.billOfLading)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Doc. Number") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.billOfLading)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("Net gallons") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.quantity.toString())
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        } else if (it.fullyQualifiedName.startsWith("New") && it.partialName == i.toString()
                        ) {
                            it.setValue(element.revisedDestination)
                            renameField(form, it.fullyQualifiedName, "${it.fullyQualifiedName}_$currentPage")
                        }
                    } catch (ex: IOException) {
                        ex.printStackTrace()
                    }
                }
            }
        }
    }
}

Data class defination

data class DiversionData(
    val terminalIRSCode: String,
    val fuelType: String,
    val supplierTaxPayerNumber: String,
    val shipperTaxPayerNumber: String,
    val quantity: Double,
    val originalDestination: String,
    val revisedDestination: String,
    val importNumber: String?,
    val date: LocalDate,
    val billOfLading: String,
)

test to fill the form

   @Test
    public void fillFormUsingNewKotlinClass() throws IOException {
        List<DiversionData> diversionData = new ArrayList<>();

        for (int i = 0; i < 20; i++) {
            DiversionData d = new DiversionData(
                "terminal_Code" + i,
                "Regular" + i,
                "Supplier tax" + i,
                "shipper tax" + i,
                1000 + i,
                "TX",
                "LA",
                "0000" + i,
                LocalDate.now().plusDays(i),
                "123456" + i
            );
            diversionData.add(d);
        }
        //E:/repo/gasjobber-docker/gasjobber-api/src/main/resources/
        String path = "templates/taxFormsPDF/LA/5402(7_06)F.pdf";
        DiversionDataFormFiller filler = new DiversionDataFormFiller();
        Map<String, String> param = new HashMap<>();
        param.put("Product Type","065");
        param.put("Type of Schedule","22");
        param.put("LA Revenue Account Number","3264660001");
        param.put("Company Name","Test CO.");
        param.put("Filling Period","2020-12");
        PDDocument document =  filler.fillForm(path,diversionData,param);
        document.save(new File("C:\\Users\\Documents\\Downloads\\testpdf.pdf"));
        document.close();
    }

解决方案

The page /AA/O entry ("An action that shall be performed when the page is opened") has this:

if (!bReset)
{
    this.resetForm();
    bReset = true;
}

So the form is reset.

This happens even if the form is filled manually and saved, closed and reopened. Maybe this is a demo version of "formupack" that does this on purpose.

You could prevent this by removing the page /AA entry like this

document.getPage(0).setActions(null);

or just remove the /O entry

document.getPage(0).getActions().setO(null);

这篇关于PDFBOX acroForm 已填充,但在 Acrobat 阅读器中打开时,值消失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆