Change page orientation for only some pages in the resulting PDF (created out of html)

后端 未结 1 516
傲寒
傲寒 2021-01-27 07:21

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

相关标签:
1条回答
  • 2021-01-27 07:44

    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.

    0 讨论(0)
提交回复
热议问题