gpt4 book ai didi

html - 使用iText将HTML转换为PDF

转载 作者:行者123 更新时间:2023-11-28 09:08:18 26 4
gpt4 key购买 nike

我之所以发布此问题,是因为许多开发人员或多或少以不同的形式提出了相同的问题。我将亲自回答这个问题(我是iText Group的创始人/首席技术官),这样它就可以成为“ Wiki-answer”。如果堆栈溢出的“文档”功能仍然存在,那么这将是文档主题的不错选择。

源文件:

我正在尝试将以下HTML文件转换为PDF:

<html>
<head>
<title>Colossal (movie)</title>
<style>
.poster { width: 120px;float: right; }
.director { font-style: italic; }
.description { font-family: serif; }
.imdb { font-size: 0.8em; }
a { color: red; }
</style>
</head>
<body>
<img src="img/colossal.jpg" class="poster" />
<h1>Colossal (2016)</h1>
<div class="director">Directed by Nacho Vigalondo</div>
<div class="description">Gloria is an out-of-work party girl
forced to leave her life in New York City, and move back home.
When reports surface that a giant creature is destroying Seoul,
she gradually comes to the realization that she is somehow connected
to this phenomenon.
</div>
<div class="imdb">Read more about this movie on
<a href="www.imdb.com/title/tt4680182">IMDB</a>
</div>
</body>
</html>


在浏览器中,此HTML如下所示:

enter image description here

我遇到的问题:

HTMLWorker根本不考虑CSS

使用 HTMLWorker时,我需要创建一个 ImageProvider以避免出现错误消息,该错误通知我找不到图像。我还需要创建一个 StyleSheet实例来更改某些样式:

public static class MyImageFactory implements ImageProvider {
public Image getImage(String src, Map<String, String> h,
ChainedProperties cprops, DocListener doc) {
try {
return Image.getInstance(
String.format("resources/html/img/%s",
src.substring(src.lastIndexOf("/") + 1)));
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

public static void main(String[] args) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("results/htmlworker.pdf"));
document.open();
StyleSheet styles = new StyleSheet();
styles.loadStyle("imdb", "size", "-3");
HTMLWorker htmlWorker = new HTMLWorker(document, null, styles);
HashMap<String,Object> providers = new HashMap<String, Object>();
providers.put(HTMLWorker.IMG_PROVIDER, new MyImageFactory());
htmlWorker.setProviders(providers);
htmlWorker.parse(new FileReader("resources/html/sample.html"));
document.close();
}


结果看起来像这样:

enter image description here

由于某些原因, HTMLWorker还会显示 <title>标记的内容。我不知道如何避免这种情况。标头中的CSS根本没有解析,我必须使用 StyleSheet对象在代码中定义所有样式。

在查看代码时,我发现不赞成使用许多对象和方法:

enter image description here

因此,我决定升级为使用XML Worker。



使用XML Worker时找不到图像

我尝试了以下代码:

public static final String DEST = "results/xmlworker1.pdf";
public static final String HTML = "resources/html/sample.html";
public void createPdf(String file) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new FileInputStream(HTML));
document.close();
}


这产生了以下PDF:

enter image description here

缺省字体为Helvetica,而不是Times-Roman。这对于iText是典型的(我应该在HTML中明确定义字体)。否则,似乎会尊重CSS,但是图像丢失了,并且我没有收到错误消息。

使用 HTMLWorker引发了异常,我能够通过引入 ImageProvider来解决此问题。让我们看看这是否适用于XML Worker。

并非所有XML样式在XML Worker中都受支持

我这样修改我的代码:

public static final String DEST = "results/xmlworker2.pdf";
public static final String HTML = "resources/html/sample.html";
public static final String IMG_PATH = "resources/html/";
public void createPdf(String file) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();

CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return IMG_PATH;
}
});

PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream(HTML));

document.close();
}


我的代码更长了,但是现在图像被渲染了:

enter image description here

该图像比我使用 HTMLWorker渲染时的图像大,这告诉我考虑了 width类的CSS属性 poster,但是 float属性被忽略。我该如何解决?

剩下的问题:

因此,问题归结为:我有一个特定的HTML文件,尝试将其转换为PDF。我已经做了很多工作,一个接一个地解决了一个问题,但是有一个我无法解决的特定问题:如何使iText尊重定义元素位置(例如 float: right)的CSS?

附加问题:

当我的HTML包含表单元素(例如 <input>)时,这些表单元素将被忽略。

最佳答案

为什么您的代码不起作用

HTML to PDF tutorial的介绍中所述,HTMLWorker已被弃用很多年。并不是要转换完整的HTML页面。它不知道HTML页面具有<head><body>部分。它只是解析所有内容。它旨在解析小的HTML代码段,并且您可以使用StyleSheet类定义样式。不支持真正的CSS。

然后是XML Worker。 XML Worker被认为是解析XML的通用框架。作为概念验证,我们决定编写一些XHTML到PDF功能,但我们不支持所有HTML标记。例如:根本不支持表单,并且很难支持用于定位内容的CSS。 HTML中的表单与PDF中的表单有很大不同。 iText架构与HTML + CSS架构之间也存在不匹配。逐渐地,我们主要根据客户的请求扩展了XML Worker,但是XML Worker变成了一个有许多触角的怪物。

最终,我们决定从头开始重写iText,同时考虑到HTML + CSS转换的要求。结果为iText 7。在iText 7之上,我们创建了几个附加组件,在这种情况下,最重要的附加组件是pdfHTML

如何解决问题

使用最新版本的iText(iText 7.1.0 + pdfHTML 2.0.0),将HTML从问题转换为PDF的代码减少到以下代码段:

public static final String SRC = "src/main/resources/html/sample.html";
public static final String DEST = "target/results/sample.pdf";
public void createPdf(String src, String dest) throws IOException {
HtmlConverter.convertToPdf(new File(src), new File(dest));
}


结果看起来像这样:

enter image description here

如您所见,这几乎是您期望的结果。从iText 7.1.0 / pdfHTML 2.0.0开始,默认字体为Times-Roman。 CSS受到尊重:图像现在在右侧浮动。

一些其他想法。

当我给出升级到iText 7 / pdfHTML 2的建议时,开发人员通常会反对升级到iText版本。请允许我回答我听到的前3个论点:

我需要使用免费的iText,而iText 7不是免费的/ pdfHTML附件是封闭源。

iText 7是使用AGPL发行的,就像iText 5和XML Worker一样。 AGPL允许在开源项目的上下文中免费使用。如果您要分发封闭的源代码/专有产品(例如,您在SaaS上下文中使用iText),则不能免费使用iText;在这种情况下,您必须购买商业许可证。对于iText 5,这已经是正确的;对于iText 7仍然如此,对于iText 5之前的版本: you shouldn't use these at all。关于pdfHTML:最初的版本确实仅作为封闭源代码软件提供。我们在iText集团内部进行了广泛的讨论:一方面,有人希望避免那些不听开发人员的公司的大规模滥用,因为那些开发人员告诉我们开放源代码不是开源的力量。和免费一样。开发人员告诉我们,他们的老板强迫他们做错事,并且他们无法说服老板购买商业许可证。另一方面,有人争论说我们不应该因为老板的错误行为而惩罚开发商。最终,赞成开放源代码pdfHTML的人们(即iText的开发人员)赢得了争论。请证明它们没有错,并正确使用iText:如果免费使用iText,请遵守AGPL;如果您在封闭源环境中使用iText,请确保您的老板购买了商业许可证。

我需要维护旧系统,并且必须使用旧的iText版本。

认真吗维护还涉及应用升级并迁移到您正在使用的软件的新版本。如您所见,使用iText 7和pdfHTML时所需的代码非常简单,并且比以前所需的代码更少出错。迁移项目不应该花费太长时间。

我才刚刚开始,对iText 7一无所知。我只有在完成项目后才发现。

这就是为什么我要发布此问题和答案。将自己视为极端程序员。扔掉所有代码,然后重新开始。您会注意到它的工作量没有您想象的那么多,而且由于iText 5正在逐步淘汰,您知道自己使项目变得面向未来时会睡得更好。我们仍然为付费客户提供支持,但是最终,我们将完全停止支持iText 5。

关于html - 使用iText将HTML转换为PDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26601714/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com