繁体   English   中英

PDFBOX acroForm 已填充但在 Acrobat 阅读器中打开时值消失

[英]PDFBOX acroForm filled but when opened in Acrobat reader values disappears

我有 PDF 表格,我正在尝试用 PDFBOX 填写它。 它可以工作,表格已填写,我用其他阅读器或浏览器打开,我可以看到值,但是当我尝试在 Adobe Reader 中打开时,值消失了,我尝试了所有可能的方法来找出为什么但是值不可见。

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

我不确定这是否与我的代码或 Adobe 阅读器有关。

链接到我需要填写的 PDF 表格

这是我填充表单的代码。


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()
                    }
                }
            }
        }
    }
}

数据 class 定义

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
    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();
    }

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

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

所以表格被重置了。

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

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

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

或者只是删除 /O 条目

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM