从每页 itext 7 java 的第一段中删除前导

问题描述

我需要在每个页面的第一个 Paragrapg 中删除 Lead 属性(FixedLeading)?

     PdfDocument pdf = new PdfDocument(new PdfWriter(DEST));
    Document document = new Document(pdf);
    setGridForFirstPage(pdf);
    document.setMargins(0,25,25);
    String line = "Hello! Welcome to iTextPdf";
    Paragraph el = new Paragraph(line);
    Div div = new Div();
    for (int i = 0; i < 30; i++) {
        Paragraph element = new Paragraph();
        element.add(line + " " + i);
        element.setFixedLeading(130);
        div.add(element);
    }
    LayoutResult result = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0,document.getPdfDocument().getDefaultPageSize())));
    LayoutResult savePageResult = null;
    deleteProperties(result);
    savePageResult = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0,document.getPdfDocument().getDefaultPageSize())));
    LayoutResult nextPageResult = savePageResult.getoverfloWrenderer().layout(new LayoutContext(new LayoutArea(3,document.getPdfDocument().getDefaultPageSize())));
    deleteProperties(nextPageResult);
    document.add(div);
    document.close();

}

private static void deleteProperties(LayoutResult childRendererListParagraph) {
    List<IRenderer> childRenderers = childRendererListParagraph.getSplitRenderer().getChildRenderers();
    for (int j = 0; j < childRenderers.size(); j++) {
        IRenderer iRendererList = childRenderers.get(j);
        if (j == 0) {
            if (iRendererList != null && iRendererList.getModelElement().hasProperty(33)) {
                iRendererList.getModelElement().deleteOwnProperty(33);


            }
        }
    }
}

它只能工作两页,我尝试使用循环,但没有成功

解决方法

您的方法似乎合理:我想可以通过循环遍历所有溢出渲染器来改进它(也许,我会尝试并在某天更新答案)。

然而,有一种完全不同的方法,对我来说似乎更方便和准确:为什么不覆盖ParagraphRenderer,这样每次对应的Paragraph无法容纳时都重置前导一页(因此将移至下一页)。

这就是这样一个扩展类的样子:

    class CustomParagraphRenderer extends ParagraphRenderer {
    public CustomParagraphRenderer(Paragraph modelElement) {
        super(modelElement);
    }

    @Override
    public LayoutResult layout(LayoutContext layoutContext) {
        LayoutResult result = super.layout(layoutContext);
        if (result.getStatus() != LayoutResult.FULL) {
            if (null != result.getOverflowRenderer()) {
                result.getOverflowRenderer().setProperty(
                        Property.LEADING,result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
            } else {
                // if overflow renderer is null,that could mean that the whole renderer will overflow
                setProperty(
                        Property.LEADING,result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
            }
        }
        return result;
    }

    @Override
    // If not overriden,the default renderer will be used for the overflown part of the corresponding paragraph
    public IRenderer getNextRenderer() {
        return new CustomParagraphRenderer((Paragraph) this.getModelElement());
    }
}

我想强调的几点:

  • 在这种情况下应该始终覆盖 getNextRenderer,否则默认渲染器将用于溢出部分
  • 最好不要像您那样更新模型元素的属性,因为如果您想重用该段落,初始属性将已经消失。相反,应该更新渲染器本身的属性(它的属性优先于模型元素的属性,即段落的属性)

这就是您可以使用这样一个类的方式。与您的代码的唯一区别是:

  • setNextRenderer 被调用,以便您的段落与自定义渲染器相关联

  • 未设置第一个元素的前导

     doc.setMargins(0,25,25);
     String line = "Hello! Welcome to iTextPdf";
     Div div = new Div();
     for (int i = 0; i < 30; i++) {
         Paragraph element = new Paragraph();
         element.setNextRenderer(new CustomParagraphRenderer(element));
         element.add(line + " " + i);
         if (0 != i) {
             element.setFixedLeading(130);
         }
         div.add(element);
     }
    

这就是生成的 PDF 的样子: enter image description here