0

我创建 pdf 并且我需要在工作流中进行后处理来更新内容,为此最好的查找方法是创建带有注释的 PdfFormField。

在创建带有注释的字段后,我可以通过 AcroField 对象搜索位置并获取页面和位置。

public static List<FieldPosition> getPositions(PdfReader pdfReader, String name) {
        AcroFields acroFields = pdfReader.getAcroFields();
        List<FieldPosition> fieldPositions = acroFields.getFieldPositions(name);
        return fieldPositions;
    }

您可以在如下位置绘制文本:

public static void writeString(PdfReader pdfReader, PdfStamper pdfStamper, String name, String valueStr, Font fontType, float leftDiff,
            float bottomDiff) throws IOException, DocumentException {
        Phrase pagePhrase = new Phrase(valueStr, fontType);

        float left;
        float bottom;
        List<FieldPosition> fieldPositions = getPositions(pdfReader, name);
        if (fieldPositions != null) {
            for (FieldPosition fieldPos : fieldPositions) {
                left = fieldPos.position.getLeft() + leftDiff;
                bottom = fieldPos.position.getBottom() + bottomDiff;
                PdfContentByte cover = pdfStamper.getOverContent(fieldPos.page);
                ColumnText.showTextAligned(cover, Element.ALIGN_LEFT, pagePhrase, left, bottom, 0);
            }
        }
    }

您可以在此处查看创建表单字段的示例http://itextpdf.com/examples/iia.php?id=157 上面的示例使用简单的 iText API 与表格和单元格(您可以看到单元格用于获取矩形对于领域)

我尝试以两种方式创建相同的字段。为单元格(td)或字段(输入或其他)创建处理器

TagProcessorFactory tagProcessorFactory = Tags.getHtmlTagProcessorFactory();
tagProcessorFactory.addProcessor(new XHTMLTableTagProcessor(), new String[] { "table" });
tagProcessorFactory.addProcessor(new XHTMLCellMarkTagProcessor(writer), new String[] { "td" });
tagProcessorFactory.addProcessor(new XHTMLInputMarkTagProcessor(writer), new String[] { "input" });
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(tagProcessorFactory);

细胞处理器

public class XHTMLCellMarkTagProcessor extends AbstractTagProcessor {

    private PdfWriter writer;

    public XHTMLCellMarkTagProcessor(PdfWriter writer) {
        this.writer = writer;
    }

    @Override
    public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
        String mark = "mark";
        String strMark = tag.getAttributes().get(mark);
        String strName = tag.getAttributes().get("name");

        boolean isMark = StringUtils.isAlpha(strMark) && strMark.equalsIgnoreCase("true");

        System.out.println(String.format(currentContent.size() + "<<< %s %s ", strName, strMark));

        List<Element> retval = super.end(ctx, tag, currentContent);
        if (isMark && StringUtils.isNotBlank(strName)) {
            for (Element element : retval) {
                if (element instanceof PdfPCell) {
                    final TextField nameField = new TextField(writer, new Rectangle(0, 0, 1, 5), strName);
                    try {

                        final PdfFormField formField = nameField.getTextField();
                        final int width = 1;

                        PdfPCellEvent cellEvent = new PdfPCellEvent() {
                            @Override
                            public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
                                try {
                                    formField.setWidget(new Rectangle(position.getLeft(), position.getBottom(), position.getLeft() + width,
                                            position.getTop()), PdfAnnotation.HIGHLIGHT_NONE);
                                    writer.addAnnotation(formField);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        };

                        ((PdfPCell) element).setCellEvent(cellEvent);

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        return retval;
    }
}

无论是否调用父元素,元素始终为零,不存在表或 div 等单元格的默认处理器 获取错误:java.lang.IllegalArgumentException:PdfPTable 构造函数中的列数必须大于零。

输入处理器

public class XHTMLInputMarkTagProcessor extends AbstractTagProcessor {

    private PdfWriter writer;

    public XHTMLInputMarkTagProcessor(PdfWriter writer) {
        this.writer = writer;
    }

    @Override
    public List<Element> start(final WorkerContext ctx, final Tag tag) {
        List<Element> elements = super.start(ctx, tag);
        try {
            String mark = "mark";
            String strMark = tag.getAttributes().get(mark);
            String strType = tag.getAttributes().get("type");
            String strName = tag.getAttributes().get("name");
            String strSize = tag.getAttributes().get("size");
            String strValue = tag.getAttributes().get("value");

            boolean isMark = StringUtils.isAlpha(strMark) && strMark.equalsIgnoreCase("true");
            int size = StringUtils.isNumeric(strSize) ? new Integer(strSize.trim()) : 0;

            System.out.println(String.format("<<< %s %s %s %s %s", strName, strType, strMark, strSize, size));

            if (isMark && StringUtils.isNotBlank(strType) && strType.equals("text")) {
                TextField nameField = new TextField(writer, new Rectangle(100, 100, 100, 50), strName);
                nameField.setBackgroundColor(BaseColor.GREEN);
                PdfFormField formField = nameField.getTextField();
                formField.setValueAsString(strValue);
                formField.setWidget(new Rectangle(100, 100, 100, 100), PdfAnnotation.HIGHLIGHT_PUSH);
                writer.addAnnotation(formField);
                //System.out.println("ADDDD");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return elements;
    }
}

我在结果 PDF 中什么也看不到。 无法将 TextField 对象添加到元素列表,因为没有扩展 Element 接口

4

1 回答 1

0

解决方案是使用 td TagProcessor 扩展 TableData 处理器,如下所示:

public class XHTMLCellMarkTagProcessor extends TableData {

    private PdfWriter writer;

    public XHTMLCellMarkTagProcessor(PdfWriter writer) {
        this.writer = writer;
    }

    @Override
    public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
        String mark = "mark";
        String strMark = tag.getAttributes().get(mark);
        String strName = tag.getAttributes().get("name");
        boolean isMark = StringUtils.isAlpha(strMark) && strMark.equalsIgnoreCase("true");

        List<Element> retval = super.end(ctx, tag, currentContent);

        if (isMark && StringUtils.isNotBlank(strName)) {
            for (Element element : retval) {
                if (element instanceof PdfPCell) {
                    final TextField namedField = new TextField(writer, new Rectangle(0, 0, 10, 5), strName);
                    try {

                        final PdfFormField formField = namedField.getTextField();
                        final int width = 0;

                        PdfPCellEvent cellEvent = new PdfPCellEvent() {
                            @Override
                            public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvas) {
                                try {
                                    formField.setWidget(new Rectangle(position.getLeft(), position.getBottom(), position.getLeft() + width,
                                            position.getTop()), PdfAnnotation.HIGHLIGHT_NONE);
                                    writer.addAnnotation(formField);

                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        };

                        ((PdfPCell) element).setCellEvent(cellEvent);

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        return retval;
    }
}
于 2015-09-30T21:49:34.847 回答