Сменить средство визуализации документа - невозможно рисовать элементы на уже очищенных страницах - PullRequest
0 голосов
/ 20 июня 2020

Согласно ответу Алексея this case , мы можем использовать различные средства визуализации с настроенным RootLayoutArea для достижения такого поведения макета, как показано ниже.

Индивидуальный макет документа

Вот код:

public void ManipulatePdf(String dest)
{
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
    Document doc = new Document(pdfDoc, PageSize.A4);
    doc.SetMargins(36, 36, 36, 36);

    Paragraph p = new Paragraph();
    p.SetBorder(new SolidBorder(0.5f));
    for (int i = 1; i <= 500; i++)
    {
        p.Add(new Text(i + " "));
    }
    doc.Add(p);

    RootLayoutArea endOfFullWidthContentArea = (RootLayoutArea)doc.GetRenderer().GetCurrentArea();

    ExtendedDocumentRenderer renderer1 = new ExtendedDocumentRenderer(doc,
        new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(), endOfFullWidthContentArea.GetBBox().Clone().SetWidth(200)));
    doc.SetRightMargin(doc.GetRightMargin() + doc.GetPageEffectiveArea(PageSize.A4).GetWidth() - 200);
    doc.SetRenderer(renderer1);

    //The paragraph drawn in the left
    Paragraph p1 = new Paragraph();
    p1.SetBorder(new SolidBorder(0.5f));
    for (int i = 1; i <= 500; i++)
    {
        p1.Add(new Text(i + " "));
    }
    doc.Add(p1);

    ExtendedDocumentRenderer renderer2 = new ExtendedDocumentRenderer(doc,
        new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(),
            endOfFullWidthContentArea.GetBBox().Clone().MoveRight(200 + 20)
                .SetWidth(endOfFullWidthContentArea.GetBBox().GetWidth() - 200 - 20)));
    doc.SetRightMargin(36);
    doc.SetLeftMargin(200 + 36 + 20);
    doc.SetRenderer(renderer2);
    Paragraph p2 = new Paragraph();
    for (int i = 1; i <= 1000; i++)
    {
        p2.Add(new Text(i + " "));
    }
    doc.Add(p2);

    //Compute which free area is lower in the document
    RootLayoutArea areaColumn1 = (RootLayoutArea)renderer1.GetCurrentArea();
    RootLayoutArea areaColumn2 = (RootLayoutArea)renderer2.GetCurrentArea();
    RootLayoutArea downArea =
        areaColumn1.GetPageNumber() > areaColumn2.GetPageNumber() ? areaColumn1 :
        (areaColumn1.GetPageNumber() < areaColumn2.GetPageNumber() ? areaColumn2 :
            (areaColumn1.GetBBox().GetTop() < areaColumn2.GetBBox().GetTop() ? areaColumn1 : areaColumn2));

    doc.SetMargins(36, 36, 36, 36);
    DocumentRenderer renderer3 = new ExtendedDocumentRenderer(doc,
        new RootLayoutArea(downArea.GetPageNumber(), downArea.GetBBox().Clone().SetX(36).SetWidth(doc.GetPageEffectiveArea(PageSize.A4).GetWidth())));
    doc.SetRenderer(renderer3);

    Paragraph p3 = new Paragraph();
    for (int i = 1; i <= 1000; i++)
    {
        p3.Add(new Text(i + " "));
    }
    doc.Add(p3);

    doc.Close();
}

private class ExtendedDocumentRenderer : DocumentRenderer
{
    public ExtendedDocumentRenderer(Document document, RootLayoutArea currentArea) : base(document)
    {
        this.currentArea = new RootLayoutArea(currentArea.GetPageNumber(), currentArea.GetBBox().Clone());
        this.currentPageNumber = this.currentArea.GetPageNumber();
    }
}

Мы видим, что абзац 1 в левом столбце занимает две страницы, а абзац 2 - три страницы, в этом сценарии код работает хорошо .

Но если мы добавим больше содержимого в абзац 1 и сделаем его охватывающим 3 страницы, как показано ниже:

//The paragraph drawn in the left has more contents
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 800; i++)
{
    p1.Add(new Text(i + " "));
}
doc.Add(p1);

Когда абзац 2 отрисовывается, он выдает исключение «Невозможно нарисовать элементы. на уже промытых страницах ». Как решить эту проблему? Спасибо!

1 Ответ

1 голос
/ 21 июня 2020

Если ваши элементы могут охватывать несколько страниц, вам необходимо применить immediateFlush=false настройку DocumentRenderer, которая передается его конструктору.

Вам нужно будет изменить свою ExtendedDocumentRenderer индивидуальную реализацию в следующем способ:

private class ExtendedDocumentRenderer : DocumentRenderer
{
    public ExtendedDocumentRenderer(Document document, RootLayoutArea currentArea) : base(document, false)
    {
        this.currentArea = new RootLayoutArea(currentArea.GetPageNumber(), currentArea.GetBBox().Clone());
        this.currentPageNumber = this.currentArea.GetPageNumber();
    }
}

И тогда вам нужно будет вызвать Document#Flush всякий раз, когда вы закончите с другим средством визуализации документов. По сути, в вашем примере кода этот вызов должен выполняться после добавления каждого нового элемента. Вот полный код:

Document doc = new Document(pdfDocument, PageSize.A4);
doc.SetMargins(36, 36, 36, 36);

Paragraph p = new Paragraph();
p.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
    p.Add(new Text(i + " "));
}
doc.Add(p);

RootLayoutArea endOfFullWidthContentArea = (RootLayoutArea)doc.GetRenderer().GetCurrentArea();

ExtendedDocumentRenderer renderer1 = new ExtendedDocumentRenderer(doc,
    new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(), endOfFullWidthContentArea.GetBBox().Clone().SetWidth(200)));
doc.SetRightMargin(doc.GetRightMargin() + doc.GetPageEffectiveArea(PageSize.A4).GetWidth() - 200);
doc.SetRenderer(renderer1);

//The paragraph drawn in the left
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 800; i++)
{
    p1.Add(new Text(i + " "));
}
doc.Add(p1);
doc.Flush();

ExtendedDocumentRenderer renderer2 = new ExtendedDocumentRenderer(doc,
    new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(),
        endOfFullWidthContentArea.GetBBox().Clone().MoveRight(200 + 20)
            .SetWidth(endOfFullWidthContentArea.GetBBox().GetWidth() - 200 - 20)));
doc.SetRightMargin(36);
doc.SetLeftMargin(200 + 36 + 20);
doc.SetRenderer(renderer2);
Paragraph p2 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
    p2.Add(new Text(i + " "));
}
doc.Add(p2);
doc.Flush();

//Compute which free area is lower in the document
RootLayoutArea areaColumn1 = (RootLayoutArea)renderer1.GetCurrentArea();
RootLayoutArea areaColumn2 = (RootLayoutArea)renderer2.GetCurrentArea();
RootLayoutArea downArea =
    areaColumn1.GetPageNumber() > areaColumn2.GetPageNumber() ? areaColumn1 :
    (areaColumn1.GetPageNumber() < areaColumn2.GetPageNumber() ? areaColumn2 :
        (areaColumn1.GetBBox().GetTop() < areaColumn2.GetBBox().GetTop() ? areaColumn1 : areaColumn2));

doc.SetMargins(36, 36, 36, 36);
DocumentRenderer renderer3 = new ExtendedDocumentRenderer(doc,
    new RootLayoutArea(downArea.GetPageNumber(), downArea.GetBBox().Clone().SetX(36).SetWidth(doc.GetPageEffectiveArea(PageSize.A4).GetWidth())));
doc.SetRenderer(renderer3);

Paragraph p3 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
    p3.Add(new Text(i + " "));
}
doc.Add(p3);
doc.Flush();

doc.Close(); 
...