我正在尝试使用itextsharp库从html文件生成pdf,但是我有一个问题,当我将html转换为pdf时,html文件的某些特殊字符被替换为'?'。标志。 (例如€)
这是我的代码:
var elements = XMLWorkerHelper.ParseToElementList(html, null);
foreach (var element in elements)
{
document.Add(element);
}
XMLWorkerHelper是itextsharp库的类。我只希望我的pdf与我的html文件生成相同。
如果使用XMLWorkerHelper.ParseToElementList(String, String)
,则iTextSharp将要求.Net运行时通过调用System.Text.Encoding.Default.GetBytes()
来确定文件的内容。
根据文档,System.Text.Encoding.Default.GetBytes()
获取操作系统当前ANSI代码页的编码
还有(重点):
不同的计算机可以使用不同的编码作为默认值,并且默认的编码甚至可以在一台计算机上更改。因此,从一台计算机流向另一台计算机或什至在同一台计算机上不同时间检索的数据可能是翻译错误。此外,Default属性使用最佳拟合后备将不支持的字符映射到代码页支持的字符返回的编码。由于这两个原因,通常不建议使用默认编码。为确保对编码的字节进行正确的解码,应将Unicode编码(例如UTF8Encoding或UnicodeEncoding)与前导一起使用。另一种选择是使用更高级别的协议来确保使用相同的格式进行编码和解码。
因此,从上面您会看到,在文件中没有任何有关如何解释原始字节的信息时,.Net将仅使用本地System.Text.Encoding.Default
来解释它们。真正有趣的是,如果将代码原样100%移至另一台计算机,则可能会得到不同的结果,因为该计算机可能设置了不同的代码页。
最佳解决方案是完全避免代码页。为此,只需将文件另存为Unicode兼容格式(例如UTF8),并包含BOM即可明确声明您的意图。 BOM是可选的(有些人对此不屑一顾),但是它也是在缺少其他信息(例如HTTP标头或便利贴)的情况下最明确的方法。
第二个选择是使用适当的编码重新实现code page。 SourceForge现在显然已经关闭,所以这里是该方法的主体:
XMLWorkerHelper.ParseToElementList()
以/**
* Parses an HTML string and a string containing CSS into a list of Element objects.
* The FontProvider will be obtained from iText's FontFactory object.
*
* @param html a String containing an XHTML snippet
* @param css a String containing CSS
* @return an ElementList instance
*/
public static ElementList ParseToElementList(String html, String css) {
// CSS
ICSSResolver cssResolver = new StyleAttrCSSResolver();
if (css != null) {
ICssFile cssFile = XMLWorkerHelper.GetCSS(new MemoryStream(Encoding.Default.GetBytes(css)));
cssResolver.AddCss(cssFile);
}
// HTML
CssAppliers cssAppliers = new CssAppliersImpl(FontFactory.FontImp);
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
htmlContext.AutoBookmark(false);
// Pipelines
ElementList elements = new ElementList();
ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, end);
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
// XML Worker
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser p = new XMLParser(worker);
p.Parse(new MemoryStream(Encoding.Default.GetBytes(html)));
return elements;
}
开头的倒数第二行代码是您要更改的内容。由于我们不知道文件的字节是什么(显然计算机也不知道),因此我们无法告诉您将编码器切换到什么位置。
总结一下,这实际上根本不是iTextSharp问题,这实际上是.Net运行时的默认行为。 iTextSharp在没有信息的情况下仅使用系统默认值。
p.parse(new StringReader(html));
这对我有用