Switch between ColumnDocumentRenderer and DocumentRenderer in same page?


Switch between ColumnDocumentRenderer and DocumentRenderer in same page?



I was testing few things with iText7 and I have a scenario where I need to have DocumentRenderer paragraph at the top and then start the ColumnDocumentRender with 2 columns right below it on the same page. The problem I am having is when I change the content on same page it overlaps content from DocumentRenderer with content from ColumnDocumentRenderer. I believe it is because one render does not know about the other render and contents starts from the top of the page. I followed this tutorial but it only shows how to add content to the next page. It does say



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



But can anyone show me exactly how we can achieve this?


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();
}



I need something like this:



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.





One solution I am thinking now is using ColumnDocumentRenderer throughout and set Column number as 1 at the top and then use column number as 2 at the bottom. I don't know if this will help but just thinking if it is possible.
– comwiz756
Jun 28 at 14:05





I tried reproducing your problem, but either I misunderstood the question, or I can't reproduce the problem. Please comment on my answer.
– Bruno Lowagie
Jun 28 at 14:40





@BrunoLowagie any solutions that I can look into? MultiColumnText did the trick for old versions of iText. i.stack.imgur.com/s53A0.png
– comwiz756
Jun 28 at 17:44





1 Answer
1



I have taken this code: C02E08_JekyllHydeV4



And I updated it according to what you have in your question:


//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();



The result looks like this:



enter image description here



enter image description here



enter image description here



I think that's the behavior you are looking for. If it's not, please explain what goes wrong.



UPDATE:



After clarifying the question, it is clear that the above answer doesn't solve the problem. This is the solution to the actual problem:



We need to create a custom ParagraphRenderer to determine a Y-position:
class MyParagraphRenderer extends ParagraphRenderer {


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;
}

}



When we add the first paragraph, we need to use this custom ParagraphRenderer:


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);



We can now get the Y position we need like this: renderer.getY(); we use this Y position to define a first set of columns:


renderer.getY()


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)};



We could use this set of columns to create a ColumnDocumentRenderer, but if more than one page is needed to render all the content, then the offset of the columns on the second page will be wrong, hence we also create a custom ColumnDocumentRenderer:


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;
}
}



This ColumnDocumentRenderer accepts two sets of columns, one set will be used on the first page, the second set will be used on all subsequent pages. This is how we define and apply the custom ColumnDocumentRenderer:


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));



Now the result looks like this:



enter image description here



Depending on the distance you want between the first page-wide paragraph and the subsequent content in the columns, you can adjust the value of renderer.getY() - offSet * 2.


renderer.getY() - offSet * 2





I need something like this: i.stack.imgur.com/s53A0.png
– comwiz756
Jun 28 at 14:54





Thank you Bruno for all your help! :)
– comwiz756
Jun 28 at 14:55





Just wondering if is it a limitation on the library itself right now to achieve this? Or is it doable?
– comwiz756
Jun 28 at 15:45





It is doable, but I don't have the time to answer now. Part of the solution can be found here: developers.itextpdf.com/content/…
– Bruno Lowagie
Jun 28 at 18:18





this is very helpful. Thank you. I think it would be nice to add this solution to developers.itextpdf.com/content/itext-7-building-blocks/… as well. Would help a lot for folks like me. Thanks again!
– comwiz756
2 days ago







By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

how to run turtle graphics in Colaboratory

Export result set on Dbeaver to CSV