java - 使用 iText 的 pdf 交互式表单的外观问题

标签 java pdf pdf-generation itext

我一直在关注“第 8 章:填写交互式表单”iText 示例(代码和 pdf 位于 http://itextpdf.com/examples/iia.php?id=154 ),并注意到一些与外观相关的问题,这些问题也体现在示例 pdf 中。

该示例具有单选按钮列表(圆圈内的经典点)和复选框列表(带有红色背景的交叉框)。到目前为止,一切都很好。然而,以编程方式填写这些字段后生成的 pdf 在视觉上不一致。单选按钮已全部恢复为正方形,并且选定的(“西类牙语”)内部有一个十字形(?)十字而不是点。这些字段仍然可以编辑。当我选择不同的单选按钮时,之前选择的单选按钮将恢复为空圆圈。新选择的字段已从空方 block 变为虚线圆圈。这也可以通过复选框观察到。

有什么办法可以在填充字段的同时保留其原始外观吗?

谢谢!

编辑 - 这是我使用的代码的简化:

public void buildPdf() throws Exception {

    Document document = new Document(PageSize.A4);

    File file = new File("/test.pdf");
    final PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));

    document.open();

    PdfPCell cell = new PdfPCell();

    PdfRadioGroupTable group = new PdfRadioGroupTable("ndna", Arrays.asList("Not Available", "Not Applicable"), writer, Locale.ENGLISH, DEFAULT);

    cell.addElement(group);

    PdfPTable table = new PdfPTable(1);

    table.addCell(cell);

    cell = new PdfPCell();      

    cell.setCellEvent(new ActionEvent(writer, "http://localhost:8080/entrypointpdf"));

    table.addCell(cell);

    document.add(table);

    group.addAnnotations();

    document.close();
}

这是 Action 事件

class ActionEvent implements PdfPCellEvent {

        private PdfWriter writer;
        private String submissionUrl;

        public ActionEvent(PdfWriter writer, String submissionUrl) {
            this.writer = writer;
            this.submissionUrl = submissionUrl;
        }

        @Override
        public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {

            PushbuttonField submit = new PushbuttonField(writer, position, "submit") {

                @Override
                public PdfFormField getField() throws IOException, DocumentException {

                    PdfFormField field = super.getField();

                    field.setAction(PdfAction.createSubmitForm(submissionUrl, null, 0));

                    return field;
                }
            };
            submit.setText("CLICK ME");
            submit.setTextColor(BaseColor.BLUE);
            submit.setFont(DEFAULT.getCalculatedBaseFont(false));
            submit.setVisibility(PushbuttonField.VISIBLE);

            try {
                writer.addAnnotation(submit.getField());
            } catch (Exception ignore) {
            }
        }
    }

这是 PdfRadioGroupTable

public class PdfRadioGroupTable extends PdfPTable {

    private PdfWriter writer;
    public PdfFormField radioGroup;

    public PdfRadioGroupTable(String name, List<String> choices, PdfWriter writer, Locale locale, Font font) {
        super(2);

        this.writer = writer;

        setWidthPercentage(100);
        try {
            setTotalWidth(new float[] { 14, 400 });
        } catch (DocumentException ignore) {
        }

        radioGroup = PdfFormField.createRadioButton(writer, true);
        radioGroup.setFieldName(name);

        PdfPCell cell;

        for (String choice : choices) {
            cell = new PdfPCell();

            cell.setBorder(0);
            cell.setPaddingBottom(5);

            cell.setUseAscender(true);
            cell.setUseDescender(true);
            cell.setVerticalAlignment(PdfPCell.ALIGN_CENTER);

            cell.setCellEvent(new RadioCellEvent(radioGroup, choice));

            addCell(cell);

            cell = new PdfPCell();

            cell.setBorder(0);

            cell.setPaddingBottom(5);
            cell.setPaddingLeft(6);

            cell.setUseAscender(true);
            cell.setUseDescender(true);
            cell.setVerticalAlignment(PdfPCell.ALIGN_CENTER);

            cell.addElement(new Phrase(choice), font));

            addCell(cell);
        }
    }

    class RadioCellEvent implements PdfPCellEvent {

        protected PdfFormField radioGroup;
        protected String value;

        public RadioCellEvent(PdfFormField radioGroup, String value) {
            this.radioGroup = radioGroup;
            this.value = value;
        }

        @Override
        public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {

            RadioCheckField radio = new RadioCheckField(writer, position, null, value);

            radio.setChecked(false);

            radio.setBorderColor(GrayColor.GRAYBLACK);
            radio.setBackgroundColor(GrayColor.GRAYWHITE);
            radio.setCheckType(RadioCheckField.TYPE_CIRCLE);

            try {
                PdfFormField field = radio.getRadioField();

                writer.addAnnotation(field);
                radioGroup.addKid(field);

            } catch (Exception exception) {
                throw new ExceptionConverter(exception);
            }
        }
    }
}   

以下是当单击 pdf 中的按钮(在 acrobat 中)时服务器端发生的情况:

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "inline; filename=\"your.pdf\"");

        try {
            FdfReader fdf = new FdfReader(request.getInputStream());

            File pdfFile = new File("/test.pdf");

            InputStream is = new FileInputStream(pdfFile);

            PdfReader reader = new PdfReader(is);

            File resultFile = new File(System.currentTimeMillis() + "_" + pdfFile.getName());
            FileOutputStream out = new FileOutputStream(resultFile);

            PdfStamper stamper = new PdfStamper(reader, out);

            AcroFields fields = stamper.getAcroFields();
            fields.setFields(fdf);

            // EXTRACT VALUES HERE                                  

            stamper.setFormFlattening(true);

            stamper.close();
            reader.close();

            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            bos.write(FilesUtilities.read(resultFile));

            OutputStream os = response.getOutputStream();
            bos.writeTo(os);
            os.flush();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

所以基本上我生成了一个带有一个单选组和一个按钮的 pdf 文件。该按钮导致 pdf 字段被导入,其想法是以先前生成的 pdf 的形式将“收据”发送回用户,其中包含与用户选择/值和导入状态字段相同的字段(正常、丢失、错误数据等)(我在上面的代码中省略了该部分,因为该部分工作正常)。我的问题是,返回的 pdf 中的单选字段看起来与原始 pdf 中的可编辑字段完全不同(它们甚至不再看起来像单选按钮)。

Before

Returned

我尝试使用

fields.setFieldProperty("ndna", "setfflags", PdfFormField.FF_READ_ONLY, null);

并通过此禁用表单展平会导致返回的 pdf 中出现相同的替代外观。

非常感谢您的帮助,因为我已经为此苦苦挣扎了一段时间......

安东尼

最佳答案

这似乎是某些版本的 iText 上的错误。我在 iTextSharp 5.5.5 版本中遇到了同样的问题,升级到 5.5.9 版本后解决了。我用“nuget”来做到这一点。这是一个链接:https://www.nuget.org/packages/iTextSharp/5.5.9

关于java - 使用 iText 的 pdf 交互式表单的外观问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32906739/

相关文章:

java - 无法将字符串转换为整数

javascript - 使用 jquery ajax 下载 pdf 文件

html - 是@page :last really something?

python-3.x - Reportlab 中的表拆分重叠页眉

pdf - 用于从各种文档类型生成 pdf 的命令行工具?

java - 如何绘制从相机到 3D 区域的投影线?

java - 防止 JAXB 将字符串转换为数字 (JSON)

java - 使用 phantomJs Selenium 滚动

java - iText 添加 LTV 信息

r - 如何将绘图附加到现有 pdf 文件