首先,HTML 和 PDF 并不相关,尽管它们是大约在同一时间创建的。 HTML 旨在传达更高级别的信息,例如段落和表格。尽管有方法可以控制它,但最终还是由浏览器来绘制这些更高层次的概念。 PDF 旨在传达文件和文件must无论它们在何处呈现,“看起来”都是一样的。
在 HTML 文档中,您可能有一个 100% 宽的段落,根据显示器的宽度,它可能需要 2 行或 10 行,当您打印它时,它可能需要 7 行,当您在手机上查看它时,它可能需要取20行。然而,PDF 文件,must be独立于渲染设备,因此无论您的屏幕尺寸如何必须始终渲染完全一样。
因为musts如上所述,PDF 不支持“表格”或“段落”等抽象内容。 PDF 支持三种基本内容:文本、线条/形状和图像。(还有其他东西,例如注释和电影,但我在这里尽量保持简单。)在 PDF 中,您不会说“这是一个段落,浏览器做您的事情!”。相反,您会说,“使用这种精确的字体在这个精确的 X,Y 位置绘制此文本,不用担心,我之前已经计算过文本的宽度,所以我知道它将全部适合这条线”。你也不会说“这是一张桌子”,而是说“在这个确切的位置绘制这个文本,然后在我之前计算过的另一个确切的位置绘制一个矩形,所以我知道它会出现在文本周围”。
其次,iText 和 iTextSharp 解析 HTML 和 CSS。就是这样。 ASP.Net、MVC、Razor、Struts、Spring 等都是 HTML 框架,但 iText/iTextSharp 100% 不知道它们。与 DataGridViews、Repeaters、Templates、Views 等相同,它们都是特定于框架的抽象。这是your负责从您选择的框架中获取 HTML,iText 不会帮助您。如果你得到一个异常说The document has no pages
或者你认为“iText 没有解析我的 HTML”,这几乎可以肯定你实际上并不 有 HTML,你只是认为你这样做。
第三,已经存在多年的内置类是HTMLWorker
然而这已被替换为XMLWorker
(Java / .Net)。零工作正在进行中HTMLWorker
它不支持 CSS 文件,并且仅对最基本的 CSS 属性提供有限的支持,实际上某些标签上的中断。如果您没有看到此文件中的 HTML 属性或 CSS 属性和值那么它可能不受支持HTMLWorker
. XMLWorker
有时可能会更复杂,但这些并发症也make it more 可扩展的.
下面的 C# 代码展示了如何将 HTML 标签解析为 iText 抽象,这些抽象会自动添加到您正在处理的文档中。 C# 和 Java 非常相似,因此转换应该相对容易。示例#1 使用内置HTMLWorker
解析 HTML 字符串。由于仅支持内联样式class="headline"
被忽略,但其他一切都应该有效。示例 #2 与第一个示例相同,只是它使用了XMLWorker
反而。示例 #3 还解析了简单的 CSS 示例。
//Create a byte array that will eventually hold our final PDF
Byte[] bytes;
//Boilerplate iTextSharp setup here
//Create a stream that we can write to, in this case a MemoryStream
using (var ms = new MemoryStream()) {
//Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
using (var doc = new Document()) {
//Create a writer that's bound to our PDF abstraction and our stream
using (var writer = PdfWriter.GetInstance(doc, ms)) {
//Open the document for writing
doc.Open();
//Our sample HTML and CSS
var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
var example_css = @".headline{font-size:200%}";
/**************************************************
* Example #1 *
* *
* Use the built-in HTMLWorker to parse the HTML. *
* Only inline CSS is supported. *
* ************************************************/
//Create a new HTMLWorker bound to our document
using (var htmlWorker = new iTextSharp.text.html.simpleparser.HTMLWorker(doc)) {
//HTMLWorker doesn't read a string directly but instead needs a TextReader (which StringReader subclasses)
using (var sr = new StringReader(example_html)) {
//Parse the HTML
htmlWorker.Parse(sr);
}
}
/**************************************************
* Example #2 *
* *
* Use the XMLWorker to parse the HTML. *
* Only inline CSS and absolutely linked *
* CSS is supported *
* ************************************************/
//XMLWorker also reads from a TextReader and not directly from a string
using (var srHtml = new StringReader(example_html)) {
//Parse the HTML
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
}
/**************************************************
* Example #3 *
* *
* Use the XMLWorker to parse HTML and CSS *
* ************************************************/
//In order to read CSS as a string we need to switch to a different constructor
//that takes Streams instead of TextReaders.
//Below we convert the strings into UTF8 byte array and wrap those in MemoryStreams
using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css))) {
using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html))) {
//Parse the HTML
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
}
}
doc.Close();
}
}
//After all of the PDF "stuff" above is done and closed but **before** we
//close the MemoryStream, grab all of the active bytes from the stream
bytes = ms.ToArray();
}
//Now we just need to do something with those bytes.
//Here I'm writing them to disk but if you were in ASP.Net you might Response.BinaryWrite() them.
//You could also write the bytes to a database in a varbinary() column (but please don't) or you
//could pass them to another function for further PDF processing.
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
System.IO.File.WriteAllBytes(testFile, bytes);
2017年更新
对于 HTML 到 PDF 的需求有好消息。作为这个答案表明, W3C 标准CSS-break-3将解决问题...这是一个候选推荐,计划在测试后于今年变成最终推荐。
由于不太标准,有一些解决方案,带有 C# 插件,如所示print-css.rocks.