匿名用户
做起来其实相当棘手,但整个机制还是足够灵活的,能够容纳这种需求。
我们将致力于支持以下语法:
Display in portrait
display in landscape
content
.....
content
After portrait
首先,我们需要将HTML内容转换为元素,然后将这些元素添加到文档中,而不是直接的HTML->PDF转换。这是必要的,因为在HTML的情况下,CSS规范规定了一个单独的页面大小处理机制,它不够灵活,无法满足您的需求,因此我们将使用本机iText布局机制。
其思想是,除了通过向areabreak传递参数来自定义新页面大小之外,我们还将更改pdfdocument的默认页面大小,以便使用该自定义新页面大小创建所有后续页面。为此,我们需要一直通过pdfdocument。高级代码如下所示:PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFilePath));
ConverterProperties properties = new ConverterProperties();
properties.setTagWorkerFactory(new CustomTagWorkerFactory(pdfDocument));
Document document = new Document(pdfDocument);
List elements = HtmlConverter.convertToElements(new FileInputStream(inputHtmlPath), properties);
for (IElement element : elements) {
if (element instanceof IBlockElement) {
document.add((IBlockElement) element);
}
}
pdfDocument.close();
自定义标记工作者工厂也几乎没有变化--它只是将pdfdocument传递给标记工作者:private static class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
PdfDocument pdfDocument;
public CustomTagWorkerFactory(PdfDocument pdfDocument) {
this.pdfDocument = pdfDocument;
}
@Override
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if ("landscape".equalsIgnoreCase(tag.name())) {
return new LandscapeDivTagWorker(tag, context, pdfDocument);
}
return null;
}
}
grandapedivtagworker的思想是创建一个div包装器,将标记的内部内容放在那里,并且用areabreak元素包围它-前一个元素将强制以横向方向断开新的页面,并更改整个文档的默认页面大小,而后一个元素将所有内容还原-强制拆分为纵向页面大小,并将默认页面大小设置为纵向页面大小。注意,我们还将使用setnextrenderer为areabreak设置一个自定义呈现器,以便在出现中断时实际设置默认页面大小:private static class LandscapeDivTagWorker extends DivTagWorker {
private PdfDocument pdfDocument;
public LandscapeDivTagWorker(IElementNode element, ProcessorContext context, PdfDocument pdfDocument) {
super(element, context);
this.pdfDocument = pdfDocument;
}
@Override
public IPropertyContainer getElementResult() {
IPropertyContainer baseElementResult = super.getElementResult();
if (baseElementResult instanceof Div) {
Div div = new Div();
AreaBreak landscapeAreaBreak = new AreaBreak(new PageSize(PageSize.A4).rotate());
landscapeAreaBreak.setNextRenderer(new DefaultPageSizeChangingAreaBreakRenderer(landscapeAreaBreak, pdfDocument));
div.add(landscapeAreaBreak);
div.add((IBlockElement) baseElementResult);
AreaBreak portraitAreaBreak = new AreaBreak(new PageSize(PageSize.A4));
portraitAreaBreak.setNextRenderer(new DefaultPageSizeChangingAreaBreakRenderer(portraitAreaBreak, pdfDocument));
div.add(portraitAreaBreak);
baseElementResult = div;
}
return baseElementResult;
}
}
自定义区域分隔呈现器的实现非常简单--我们只将默认页面大小设置为pdfdocument--其余的都是通过默认实现来完成的,我们从:private static class DefaultPageSizeChangingAreaBreakRenderer extends AreaBreakRenderer {
private PdfDocument pdfDocument;
private AreaBreak areaBreak;
public DefaultPageSizeChangingAreaBreakRenderer(AreaBreak areaBreak, PdfDocument pdfDocument) {
super(areaBreak);
this.pdfDocument = pdfDocument;
this.areaBreak = areaBreak;
}
@Override
public LayoutResult layout(LayoutContext layoutContext) {
pdfDocument.setDefaultPageSize(areaBreak.getPageSize());
return super.layout(layoutContext);
}
}
因此,您将得到与屏幕截图中类似的页面设置: