【问题标题】:Change page orientation for only some pages in the resulting PDF (created out of html)仅更改生成的 PDF 中某些页面的页面方向(由 html 创建)
【发布时间】:2019-06-10 10:53:54
【问题描述】:

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

按照[如何将页面旋转为横向且页面内容应为纵向 iTextpdf][1]

中的提示

[1]: how to rotate pages into landscape and page content should be in portrait iTextpdf 我已经创建了我的自定义标签和 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"> 内容的页面的方向。

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

【问题讨论】:

  • 假设横向设置为 true 的元素似乎不是作为页面的第一个元素呈现的。你想让它移动到下一页吗?或者您是否希望在该页面上重新呈现之前呈现的内容并更改尺寸?
  • “风景”元素应该在一个新页面上。因此,当 html2pdf 遇到“lanscape”标签时,它应该将该内容移动到新页面并更改页面方向。

标签: java itext7 html2pdf


【解决方案1】:

在下面的答案中,我将展示如何以您想要的方式处理类属性设置为横向的表格。

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

    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 列表(您特别对最后一行感兴趣):

    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 属性。如果没有,那么只需添加元素。如果存在,我们就分页,分页时设置下一页的大小:

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

在上面的sn-p中可以看到,我打破页面(设置下一页的大小),添加元素然后再次设置下一个布局区域的大小,这样下一页之后包含该元素的页面将具有默认页面大小)。

结果如下所示:

但是有一些限制:

1) 一般来说,pdf文件不仅仅是页面上呈现的一组元素。在 HtmlConverter.convertToPdf 下,iText 还处理一些其他功能(大纲等)。但是,对于您的目的,该方法似乎非常有效。

2) 如您所见,我不检查是否有一些表不是 body 标记的直接子级。实际上,为了在一般情况下正确执行,您需要修改循环:检查所有元素的子元素(可能使用 `AbstractElement#getChildren())并在其中放置一些 AreaBreaks。但这感觉像是另一个问题。

【讨论】:

  • 感谢您提供某种解决方案。
猜你喜欢
  • 2019-07-24
  • 1970-01-01
  • 2012-12-13
  • 1970-01-01
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多