I would like to change page orientation for just specific few pages in my PDF document. The PDF document is created out of html template using html2pdf. It goes like this: if th
In the answer below I'm going to show how tables with the class attribute set as landscape can be procesed in the way you want.
First of all, let's create a custom css applier for such tables. Its purpose would be to set a custom property on a table tag (for example, 10001). Then during the layout we will check that property and decide whether to change the pagesize or not.
class CustomCssApplierFactory extends DefaultCssApplierFactory {
@Override
public ICssApplier getCustomCssApplier(IElementNode tag) {
if ("table".equals(tag.name()) && "landscape".equals(tag.getAttribute(AttributeConstants.CLASS))) {
return new CustomLandscapeCssApplier();
}
return null;
}
}
class CustomLandscapeCssApplier extends TableTagCssApplier {
@Override
public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker) {
super.apply(context, stylesContainer, tagWorker);
IPropertyContainer container = tagWorker.getElementResult();
if (null != container) {
container.setProperty(10001, true);
}
}
}
Now let's convert your html not to a pdf file, but to a list of IElements which form that html (you're particularly interested in the last line):
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(pdfDest));
Document document = new Document(pdfDocument);
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setCssApplierFactory(new CustomCssApplierFactory());
List<IElement> list = HtmlConverter.convertToElements(new FileInputStream(htmlSource), converterProperties);
Now let's add these elements to the document one by one and check whether the current element (the element to be added) has the magic 10001 property. If not then just add the element. If it exists, let's break the page and set the size of the next page while breaking:
for (IElement element : list) {
if (element instanceof IBlockElement) {
if (!element.hasProperty(10001)) {
document.add((IBlockElement) element);
} else {
document.add(new AreaBreak(new PageSize(PageSize.A4).rotate()));
document.add((IBlockElement) element);
document.getPdfDocument().setDefaultPageSize(PageSize.A4);
}
}
}
As you can see in the snippet above, I broke the page (setting the size of the next page), added the element and then again set the size of the next layout area, so that the next page after the one that contains the element would have the default pagesize).
That's how the result looks like:
There are some limitations however:
1) Generally speaking, the pdf file is not just a set of elements rendered on the page. Under HtmlConverter.convertToPdf iText handles some other features as well (outlines, etc). However it seems that for your purposes the method works perfectly.
2) As you can see, I do not check whether there are some tables which are not the direct children of the body tag. Actually, in order to perform correctly in a general case, you need to modify the loop: check the children of all the elements (probably with `AbstractElement#getChildren()) and place some AreaBreaks inside them. But that feels like another question.