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

Remove Leading from the first Paragraph on every page itext 7 java

我需要删除每页第一段中的前导 属性(固定前导)?

     PdfDocument pdf = new PdfDocument(new PdfWriter(DEST));
    Document document = new Document(pdf);
    setGridForFirstPage(pdf);
    document.setMargins(0, 25, 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 可能是这样的:

    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,否则默认渲染器将用于溢出的部分
  • 最好不要像您那样更新模型元素的属性,因为如果您想重用段落,初始属性将已经消失。相反,应该更新渲染器本身的属性(它的属性优先于模型元素的属性,即段落的属性)

这就是您如何使用这样的 class。与您的代码的唯一区别是:

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

  • 未设置第一个元素的行距

     doc.setMargins(0, 25, 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 的外观: