仅更改生成的 PDF 中某些页面的页面方向(创建于 html)
Change page orientation for only some pages in the resulting PDF (created out of html)
我只想更改 PDF 文档中特定几页的页面方向。 PDF 文档是使用 html2pdf 从 html 模板创建的。它是这样的:如果页面内容(通常是 table)太宽而不能正确地以纵向显示,则以横向显示页面。
按照[如何将页面旋转为横向且页面内容应为纵向 iTextpdf][1]
中的提示进行操作
[1]: 我已经创建了自定义标签和 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 中提取当前页面以及如何仅更改这些页面的页面方向?
在下面的回答中,我将展示如何按照您想要的方式处理 table 属性设置为横向的 class。
首先,让我们为这样的 table 创建一个自定义 css 应用程序。其目的是在 table 标签上设置自定义 属性(例如,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 文件,而是 IElements 列表 html 的形式(你对最后一行特别感兴趣):
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);
}
}
}
正如你在上面的代码片段中看到的那样,我打破了页面(设置下一页的大小),添加了元素然后再次设置下一个布局区域的大小,以便下一页之后包含该元素的页面将具有默认页面大小)。
结果是这样的:
但是有一些限制:
1) 一般来说,pdf文件不仅仅是渲染在页面上的一组元素。在 HtmlConverter.convertToPdf 下,iText 还处理一些其他功能(轮廓等)。然而,对于您的目的而言,该方法似乎非常有效。
2) 如您所见,我没有检查是否有一些 table 不是 body 标签的直接子代。实际上,为了在一般情况下正确执行,您需要修改循环:检查所有元素的子元素(可能使用 `AbstractElement#getChildren())并在其中放置一些 AreaBreaks。但这感觉像是另一个问题。
我只想更改 PDF 文档中特定几页的页面方向。 PDF 文档是使用 html2pdf 从 html 模板创建的。它是这样的:如果页面内容(通常是 table)太宽而不能正确地以纵向显示,则以横向显示页面。
按照[如何将页面旋转为横向且页面内容应为纵向 iTextpdf][1]
中的提示进行操作[1]:
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 中提取当前页面以及如何仅更改这些页面的页面方向?
在下面的回答中,我将展示如何按照您想要的方式处理 table 属性设置为横向的 class。
首先,让我们为这样的 table 创建一个自定义 css 应用程序。其目的是在 table 标签上设置自定义 属性(例如,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 文件,而是 IElements 列表 html 的形式(你对最后一行特别感兴趣):
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);
}
}
}
正如你在上面的代码片段中看到的那样,我打破了页面(设置下一页的大小),添加了元素然后再次设置下一个布局区域的大小,以便下一页之后包含该元素的页面将具有默认页面大小)。
结果是这样的:
但是有一些限制:
1) 一般来说,pdf文件不仅仅是渲染在页面上的一组元素。在 HtmlConverter.convertToPdf 下,iText 还处理一些其他功能(轮廓等)。然而,对于您的目的而言,该方法似乎非常有效。
2) 如您所见,我没有检查是否有一些 table 不是 body 标签的直接子代。实际上,为了在一般情况下正确执行,您需要修改循环:检查所有元素的子元素(可能使用 `AbstractElement#getChildren())并在其中放置一些 AreaBreaks。但这感觉像是另一个问题。