在同一页面中的 ColumnDocumentRenderer 和 DocumentRenderer 之间切换?

Switch between ColumnDocumentRenderer and DocumentRenderer in same page?

我正在用 iText7 测试一些东西,我有一个场景,我需要在顶部有一个 DocumentRenderer 段落,然后在同一页面的正下方启动 ColumnDocumentRender 2 列。我遇到的问题是,当我更改同一页面上的内容时,它会将来自 DocumentRenderer 的内容与来自 ColumnDocumentRenderer 的内容重叠。我相信这是因为一个渲染器不知道另一个渲染器并且内容从页面顶部开始。我关注了 this tutorial 但它只显示了如何将内容添加到下一页。它确实说

we'll have to instruct iText not to flush the content to the OutputStream

但是谁能告诉我我们如何才能做到这一点?

public void createPdf(String dest) throws IOException {
    PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
    Document document = new Document(pdf);
    Paragraph p = new Paragraph()
        .add("Be prepared to read a story about a London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde.");
    document.add(p);
    document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
    ... // Define column areas
    document.setRenderer(new ColumnDocumentRenderer(document, columns));
    document.add(new AreaBreak(AreaBreakType.LAST_PAGE));   
    ... // Add novel in two columns
    document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
    document.setRenderer(new DocumentRenderer(document)); 
    document.add(new AreaBreak(AreaBreakType.LAST_PAGE));
    p = new Paragraph()
        .add("This was the story about the London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde. THE END!");
    document.add(p);
    document.close();
}

我需要这样的东西:

iText7 Columns

Whenever you create a new DocumentRenderer, iText starts returns to the top of the document –that is: from the first page. This allows you to use different renderers on the same document next to each other on the same page. If that is needed, we'll have to instruct iText not to flush the content to the OutputStream; otherwise we won't have access to previous pages. In this case, we don't need to change anything on previous pages. We just want to switch to another renderer on the next page. Introducing a page break that goes to the last page will avoid that new content overwrites old content.

我已经接受了这个代码:C02E08_JekyllHydeV4

我根据你的问题更新了它:

//Initialize PDF document
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
// Initialize document
Document document = new Document(pdf);
Paragraph p = new Paragraph()
    .add("Be prepared to read a story about a London lawyer "
       + "named Gabriel John Utterson who investigates strange "
       + "occurrences between his old friend, Dr. Henry Jekyll, "
       + "and the evil Edward Hyde.");
document.add(p);
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));

//Set column parameters
...
//Define column areas
...
document.setRenderer(new ColumnDocumentRenderer(document, columns)); 
document.add(new AreaBreak(AreaBreakType.LAST_PAGE));   
// Add the full Jekyl and Hyde text
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
document.setRenderer(new DocumentRenderer(document)); 
document.add(new AreaBreak(AreaBreakType.LAST_PAGE));
p = new Paragraph()
    .add("This was the story about the London lawyer "
       + "named Gabriel John Utterson who investigates strange "
       + "occurrences between his old friend, Dr. Henry Jekyll, "
       + "and the evil Edward Hyde. THE END!");
document.add(p);
//Close document
document.close();

结果如下所示:

我认为这就是您要寻找的行为。如果不是,请说明问题所在。

更新:

弄清楚问题后,显然上面的回答没有解决问题。这是实际问题的解决方案:

我们需要创建自定义 ParagraphRenderer 来确定 Y 轴位置: class MyParagraphRenderer 扩展了 ParagraphRenderer {

    float y;

    public MyParagraphRenderer(Paragraph modelElement) {
        super(modelElement);
    }

    @Override
    public void drawBorder(DrawContext drawContext) {
        super.drawBorder(drawContext);
        y = getOccupiedAreaBBox().getBottom();
    }

    public float getY() {
        return y;
    }

}

我们在添加第一段的时候,需要用到这个自定义ParagraphRenderer:

Paragraph p = new Paragraph()
        .add("Be prepared to read a story about a London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde.");
MyParagraphRenderer renderer = new MyParagraphRenderer(p);
p.setNextRenderer(renderer);
document.add(p);

我们现在可以像这样得到我们需要的Y位置:renderer.getY();我们使用这个 Y 位置来定义第一组列:

float offSet = 36;
float gutter = 23;
float columnWidth = (PageSize.A4.getWidth() - offSet * 2) / 2 - gutter;
float columnHeight1 = renderer.getY() - offSet * 2;
Rectangle[] columns1 = {
    new Rectangle(offSet, offSet, columnWidth, columnHeight1),
    new Rectangle(offSet + columnWidth + gutter, offSet, columnWidth, columnHeight1)};

我们可以使用这组列来创建一个ColumnDocumentRenderer,但是如果需要不止一页来呈现所有内容,那么第二页上的列偏移量将是错误的,因此我们还创建了自定义 ColumnDocumentRenderer:

class MyColumnDocumentRenderer extends ColumnDocumentRenderer {

    Rectangle[] columns2;

    public MyColumnDocumentRenderer(Document document, Rectangle[] columns1, Rectangle[] columns2) {
        super(document, columns1);
        this.columns2 = columns2;
    }

    @Override
    protected PageSize addNewPage(PageSize customPageSize) {
        PageSize size = super.addNewPage(customPageSize);
        columns = columns2;
        return size;
    }
}

ColumnDocumentRenderer 接受两组列,一组将用于第一页,第二组将用于所有后续页面。这就是我们如何定义和应用自定义 ColumnDocumentRenderer:

float columnHeight2 = PageSize.A4.getHeight() - offSet * 2;
Rectangle[] columns2 = {
    new Rectangle(offSet, offSet, columnWidth, columnHeight2),
    new Rectangle(offSet + columnWidth + gutter, offSet, columnWidth, columnHeight2)};
document.setRenderer(new MyColumnDocumentRenderer(document, columns1, columns2));  

现在结果是这样的:

根据您想要的第一页宽段落与列中后续内容之间的距离,您可以调整 renderer.getY() - offSet * 2 的值。