iTextSharp HTML 到 PDF 的转换 - 无法更改字体
iTextSharp HTML to PDF conversion - unable to change font
我正在 ASP.NET MVC5 应用程序中使用来自 HTML 的 iTextSharp (5.5.7.0) 创建一些 PDF 文档,但我无法更改字体。我已经尝试了几乎所有我能在 SO 或其他资源中找到的东西。
PDF生成代码如下:
public Byte[] GetRecordsPdf(RecordsViewModel model)
{
var viewPath = "~/Template/RecordTemplate.cshtml";
var renderedReport = RenderViewToString(viewPath, model);
FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
using (var ms = new MemoryStream())
{
using (var doc = new Document())
{
doc.SetPageSize(PageSize.A4.Rotate());
using (var writer = PdfWriter.GetInstance(doc, ms))
{
doc.Open();
using (var html = new MemoryStream(Encoding.Default.GetBytes(renderedReport)))
{
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, html, Encoding.Default);
}
doc.Close();
}
}
var bytes = ms.ToArray();
return bytes;
}
}
实际 HTML 包含在 renderedReport 字符串变量中(我有强类型的 .cshtml 文件,我使用 MVC Razor 引擎渲染,然后 return HTML 在字符串中)。
我尝试注册了一些特定的字体,但没有帮助。我还尝试在我的机器上注册所有字体(如上例所示),但这也无济于事。字体已加载我已经在调试模式下检查过了。
CSS 嵌入到 HTML 文件中(在标题、样式标签中),如下所示:
body {
font-size: 7px;
font-family: Comic Sans MS;
}
(为了测试,我决定使用Comic Sans,因为我可以轻松识别它,我实际上对Arial Unicode MS更感兴趣)。
而且我实际上能够使用 CSS 中的 font-family 属性更改字体,但只能使用 iTextSharp 默认预加载的字体 - Times New Roman 、Arial、Courier 和其他一些字体(我认为是 Helvetica)。 当我将其更改为 - Comic Sans 或其他未预加载的 iTextSharp 时,会使用默认字体呈现(我会说是 Arial)。
我需要更改字体的原因是因为我在渲染的 HTML (ČĆŠĐŽčćšđž) 中有一些克罗地亚语字符,PDF 中缺少这些字符,目前我认为主要原因是 - 字体。
我错过了什么?
完成这项工作的几件事。
首先,XMLWorkerHelper
默认情况下不使用 FontFactory
,您需要使用 ParseXHtml()
的重载之一,它采用 IFontProvider
。这两个重载都要求您为 CSS 文件指定一个 Stream
,但如果您的 CSS 位于 HTML 文件中,您可以只传递 null
。幸运的是 FontFactory
有一个静态的 属性 实现了这个,你可以使用名为 FontFactory.FontImp
// **This guy**
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, null, Encoding.UTF8, FontFactory.FontImp);
其次,我知道您曾说过您出于绝望而尝试注册整个字体目录,但这可能是一个相当昂贵的调用。如果可以,请始终尝试只注册您需要的字体。虽然是可选的,但我也强烈建议您明确定义字体的别名,因为字体可以有多个名称,而且它们并不总是我们所想的那样。
FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
第三,这可能不会影响您,但是 HTML 中不存在的任何标签,即使它们在逻辑上是隐含的,也不会从 CSS 中应用样式。这听起来很奇怪所以换个说法,如果你的 HTML 只是 <p>Hello</p>
而你的 CSS 是 body{font-size: 7px;}
,则不会应用字体大小,因为你的 HTML 缺少 <body>
标签。
第四,这是可选的,但通常更容易将 HTML 和 CSS 彼此分开指定,我将在下面的示例中这样做。
你的代码已经完成了 95%,所以只需进行一些调整就可以了。我只是解析原始 HTML 和 CSS 而不是视图,但您可以根据需要进行修改。请记住(我想你知道这一点)iTextSharp 不能处理 ASP.Net,只能处理 HTML,所以你需要确保你的 ASP.Net 到 HTML 的转换过程很正常。
//Sample HTML and CSS
var html = @"<body><p>Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima. Ona su obdarena razumom i sviješću i trebaju jedna prema drugima postupati u duhu bratstva.</p></body>";
var css = "body{font-size: 7px; font-family: Comic Sans MS;}";
//Register a single font
FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
//Placeholder variable for later
Byte[] bytes;
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
doc.SetPageSize(PageSize.A4.Rotate());
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
//Get a stream of our HTML
using (var msHTML = new MemoryStream(Encoding.UTF8.GetBytes(html))) {
//Get a stream of our CSS
using (var msCSS = new MemoryStream(Encoding.UTF8.GetBytes(css))) {
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, msCSS, Encoding.UTF8, FontFactory.FontImp);
}
}
doc.Close();
}
}
bytes = ms.ToArray();
}
我正在 ASP.NET MVC5 应用程序中使用来自 HTML 的 iTextSharp (5.5.7.0) 创建一些 PDF 文档,但我无法更改字体。我已经尝试了几乎所有我能在 SO 或其他资源中找到的东西。
PDF生成代码如下:
public Byte[] GetRecordsPdf(RecordsViewModel model)
{
var viewPath = "~/Template/RecordTemplate.cshtml";
var renderedReport = RenderViewToString(viewPath, model);
FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
using (var ms = new MemoryStream())
{
using (var doc = new Document())
{
doc.SetPageSize(PageSize.A4.Rotate());
using (var writer = PdfWriter.GetInstance(doc, ms))
{
doc.Open();
using (var html = new MemoryStream(Encoding.Default.GetBytes(renderedReport)))
{
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, html, Encoding.Default);
}
doc.Close();
}
}
var bytes = ms.ToArray();
return bytes;
}
}
实际 HTML 包含在 renderedReport 字符串变量中(我有强类型的 .cshtml 文件,我使用 MVC Razor 引擎渲染,然后 return HTML 在字符串中)。
我尝试注册了一些特定的字体,但没有帮助。我还尝试在我的机器上注册所有字体(如上例所示),但这也无济于事。字体已加载我已经在调试模式下检查过了。
CSS 嵌入到 HTML 文件中(在标题、样式标签中),如下所示:
body {
font-size: 7px;
font-family: Comic Sans MS;
}
(为了测试,我决定使用Comic Sans,因为我可以轻松识别它,我实际上对Arial Unicode MS更感兴趣)。
而且我实际上能够使用 CSS 中的 font-family 属性更改字体,但只能使用 iTextSharp 默认预加载的字体 - Times New Roman 、Arial、Courier 和其他一些字体(我认为是 Helvetica)。 当我将其更改为 - Comic Sans 或其他未预加载的 iTextSharp 时,会使用默认字体呈现(我会说是 Arial)。
我需要更改字体的原因是因为我在渲染的 HTML (ČĆŠĐŽčćšđž) 中有一些克罗地亚语字符,PDF 中缺少这些字符,目前我认为主要原因是 - 字体。
我错过了什么?
完成这项工作的几件事。
首先,XMLWorkerHelper
默认情况下不使用 FontFactory
,您需要使用 ParseXHtml()
的重载之一,它采用 IFontProvider
。这两个重载都要求您为 CSS 文件指定一个 Stream
,但如果您的 CSS 位于 HTML 文件中,您可以只传递 null
。幸运的是 FontFactory
有一个静态的 属性 实现了这个,你可以使用名为 FontFactory.FontImp
// **This guy**
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, null, Encoding.UTF8, FontFactory.FontImp);
其次,我知道您曾说过您出于绝望而尝试注册整个字体目录,但这可能是一个相当昂贵的调用。如果可以,请始终尝试只注册您需要的字体。虽然是可选的,但我也强烈建议您明确定义字体的别名,因为字体可以有多个名称,而且它们并不总是我们所想的那样。
FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
第三,这可能不会影响您,但是 HTML 中不存在的任何标签,即使它们在逻辑上是隐含的,也不会从 CSS 中应用样式。这听起来很奇怪所以换个说法,如果你的 HTML 只是 <p>Hello</p>
而你的 CSS 是 body{font-size: 7px;}
,则不会应用字体大小,因为你的 HTML 缺少 <body>
标签。
第四,这是可选的,但通常更容易将 HTML 和 CSS 彼此分开指定,我将在下面的示例中这样做。
你的代码已经完成了 95%,所以只需进行一些调整就可以了。我只是解析原始 HTML 和 CSS 而不是视图,但您可以根据需要进行修改。请记住(我想你知道这一点)iTextSharp 不能处理 ASP.Net,只能处理 HTML,所以你需要确保你的 ASP.Net 到 HTML 的转换过程很正常。
//Sample HTML and CSS
var html = @"<body><p>Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima. Ona su obdarena razumom i sviješću i trebaju jedna prema drugima postupati u duhu bratstva.</p></body>";
var css = "body{font-size: 7px; font-family: Comic Sans MS;}";
//Register a single font
FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
//Placeholder variable for later
Byte[] bytes;
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
doc.SetPageSize(PageSize.A4.Rotate());
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
//Get a stream of our HTML
using (var msHTML = new MemoryStream(Encoding.UTF8.GetBytes(html))) {
//Get a stream of our CSS
using (var msCSS = new MemoryStream(Encoding.UTF8.GetBytes(css))) {
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, msCSS, Encoding.UTF8, FontFactory.FontImp);
}
}
doc.Close();
}
}
bytes = ms.ToArray();
}