更改结果PDF中仅某些页面的页面方向(由html创建) [英] Change page orientation for only some pages in the resulting PDF (created out of html)

查看:160
本文介绍了更改结果PDF中仅某些页面的页面方向(由html创建)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只想更改PDF文档中特定页面的页面方向. PDF文档是使用html2pdf从html模板创建的.它是这样的:如果页面(通常是表格)的内容太宽而无法以纵向显示,则以横向显示页面.

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 the content of the page (typically a table) is too wide to be properly shown in portrait orientation, show page in landscape.

遵循[如何将页面旋转为横向且页面内容应以纵向iTextpdf格式] [1]

Following the hint in [how to rotate pages into landscape and page content should be in portrait iTextpdf][1]

[1]:

[1]: how to rotate pages into landscape and page content should be in portrait iTextpdf I have created my custom tag and TagWorker.

public class LandscapeTagWorker extends BodyTagWorker {

public LandscapeTagWorker(IElementNode element, ProcessorContext context) {
    super(element, context);
}

/**
 * @param element
 * @param context
 * @see com.itextpdf.html2pdf.attach.ITagWorker#processEnd(com.itextpdf.html2pdf.html.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext)
 */
@Override
public void processEnd(IElementNode element, ProcessorContext context) {
    super.processEnd(element, context);
    String value = element.getAttribute("value");
     if ( "true".equalsIgnoreCase(value) ) {
        PdfDocument doc = context.getPdfDocument();

        doc.setDefaultPageSize(doc.getDefaultPageSize().rotate());
     }
}

}

问题是:首先,这什么都不做.即使可行,我也不想更改整个文档的方向,而只是更改找到<landscape value="true">内容的页面的方向.

The problems are: first, this does nothing. Even if it would work, I do not want to change the orientation of the whole document, just orientation of the pages where the content of the <landscape value="true">is found.

如何从ProcessorContext/PdfDocument中提取当前页面,以及如何仅更改那些页面的页面方向?

How can I extract the current page(s) out of ProcessorContext/PdfDocument and how to change page orientation of only those pages?

推荐答案

在下面的答案中,我将展示如何以所需方式处理将class属性设置为landscape的表.

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.

首先,让我们为此类表创建一个自定义css应用程序.其目的是在表标签上设置自定义属性(例如10001).然后在布局期间,我们将检查该属性并决定是否更改页面大小.

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

现在让我们将您的html 不是转换为pdf文件,而是转换为形成该html的 IElements列表 (您特别对最后一行感兴趣):

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

现在,让我们将这些元素一一添加到文档中,并检查当前元素(要添加的元素)是否具有魔术10001属性.如果没有,则只需添加元素.如果存在,让我们分页,并在分页时设置下一页的大小:

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

如您在上面的代码段中所见,我将页面弄碎了(设置下一页的大小),添加了元素,然后再次设置下一个布局区域的大小,这样,下一页之后的下一页包含该元素将具有默认的pagesize.

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

结果就是这样:

但是有一些限制:

1)一般来说,pdf文件不仅仅是页面上呈现的一组元素.在HtmlConverter.convertToPdf下,iText还可以处理其他一些功能(轮廓等).但是,对于您来说,该方法似乎可以正常工作.

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)如您所见,我没有检查是否有一些表不是body标签的直接子代.实际上,为了在一般情况下正确执行,您需要修改循环:检查所有元素的子元素(可能使用AbstractElement#getChildren()),并在其中放置一些AreaBreaks.但这听起来像是另外一个问题.

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.

这篇关于更改结果PDF中仅某些页面的页面方向(由html创建)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆