我们采用的TuesPechkin来把html页面生成pdf,现在遇到一个问题是我们的两台服务器调用相同的代码生成的pdf会有细微差别,两者转换的byte数组长度一样,但是对比后发现并不完全相等,导致的结果就是其中一台服务器生成的pdf某些地方的文字会有重叠。
求大佬指点应该怎么处理啊,或者有没有其他更好用的html转pdf插件推荐
之前有个老项目就是html转pdf,我当时用的wkhtmltopdf。
下载地址 https://wkhtmltopdf.org/downloads.html
下面我写的帮助类
/// <summary>
/// PDF帮助类
/// Creator:oBehavior
/// Creation Time:2022年6月1日10:30:12
/// </summary>
public class PDFHelper
{
//wkhtmltopdf 物理路径,C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe
private static string wkhtmltopdf_path = ConfigurationManager.AppSettings["wkhtmltopdf"];
/// <summary>
/// html地址转pdf,含页眉页脚
/// </summary>
/// <param name="url">html网址,例如:www.baidu.com</param>
/// <param name="modelName">模块名称,例如:仪器使用和维护记录</param>
/// <param name="header_left">页眉左</param>
/// <param name="header_right">页眉右</param>
/// <param name="footer_left">页脚左</param>
/// <param name="footer_center">页脚中</param>
/// <param name="foot_right">页脚右</param>
/// <returns>消息实体</returns>
public static Result HtmlToPDF(
string url,
string modelName = "default",
string header_left = "",
string header_right = "",
string footer_left = "",
string footer_center = "",
string foot_right = "")
{
try
{
if (string.IsNullOrWhiteSpace(url))
{
throw new Exception("操作失败!参数URL不得为空.");
}
if (!File.Exists(wkhtmltopdf_path))
{
throw new Exception($"操作失败!路径无效,未找到wkhtmltopdf.exe(路径:{wkhtmltopdf_path})");
}
//pdf文件物理路径
string fileName = GetFilePath("PDF_files", modelName) + modelName + DateTime.Now.ToString("_yyyyMMddHHmmssfffff") + ".pdf";
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = wkhtmltopdf_path;
processStartInfo.WorkingDirectory = Path.GetDirectoryName(wkhtmltopdf_path);
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.Arguments = GetArguments(url, fileName, true, header_left, header_right, footer_left, footer_center, foot_right);
Process process = new Process();
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
///用于查看是否返回错误信息
//StreamReader srone = process.StandardError;
//StreamReader srtwo = process.StandardOutput;
//string ss1 = srone.ReadToEnd();
//string ss2 = srtwo.ReadToEnd();
//srone.Close();
//srone.Dispose();
//srtwo.Close();
//srtwo.Dispose();
process.Close();
process.Dispose();
return new Result(true, fileName);
}
catch (Exception ex)
{
return new Result(ex.Message);
}
}
/// <summary>
/// html地址转pdf,含页眉页脚
/// </summary>
/// <param name="url">html网址,例如:www.baidu.com</param>
/// <param name="modelName">模块名称,例如:仪器使用和维护记录</param>
/// <param name="crosswise">是否横向,默认false,不横向</param>
/// <param name="header_left">页眉左</param>
/// <param name="header_right">页眉右</param>
/// <param name="footer_left">页脚左</param>
/// <param name="footer_center">页脚中</param>
/// <param name="foot_right">页脚右</param>
/// <returns>消息实体</returns>
public static Result HtmlToPDF2(
string url,
string modelName = "default",
string templateName = "default",
bool crosswise = false,
string header_left = "",
string header_right = "",
string footer_left = "",
string footer_center = "",
string foot_right = "")
{
try
{
if (string.IsNullOrWhiteSpace(url))
{
throw new Exception("操作失败!参数URL不得为空.");
}
if (!File.Exists(wkhtmltopdf_path))
{
throw new Exception($"操作失败!路径无效,未找到wkhtmltopdf.exe(路径:{wkhtmltopdf_path})");
}
//pdf文件物理路径
string urlName = "\\" + modelName + "_" + templateName + DateTime.Now.ToString("_yyyyMMddHHmmssfffff") + ".pdf";
string fileName = GetFilePath("PDF_files", modelName) + urlName;
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = wkhtmltopdf_path;
processStartInfo.WorkingDirectory = Path.GetDirectoryName(wkhtmltopdf_path);
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.Arguments = GetArguments(url, fileName, crosswise, header_left, header_right, footer_left, footer_center, foot_right);
Process process = new Process();
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
///用于查看是否返回错误信息
//StreamReader srone = process.StandardError;
//StreamReader srtwo = process.StandardOutput;
//string ss1 = srone.ReadToEnd();
//string ss2 = srtwo.ReadToEnd();
//srone.Close();
//srone.Dispose();
//srtwo.Close();
//srtwo.Dispose();
process.Close();
process.Dispose();
return new Result(true, "\\PDF_files\\" + modelName + urlName);
}
catch (Exception ex)
{
return new Result(ex.Message);
}
}
/// <summary>
/// url地址转pdf,无页眉页脚
/// </summary>
/// <param name="url">html网址,例如:www.baidu.com</param>
/// <param name="modelName">模块名称,例如:仪器使用和维护记录</param>
/// <returns>消息实体</returns>
public static Result HtmlToPDF(string url, string modelName)
{
try
{
if (!File.Exists(wkhtmltopdf_path))
{
throw new Exception($"操作失败!路径无效,未找到wkhtmltopdf.exe(路径:{wkhtmltopdf_path})");
}
//pdf文件物理路径
string fileName = GetFilePath("PDF_files", modelName) + "\\" + modelName + DateTime.Now.ToString("_yyyyMMddHHmmssfffff") + ".pdf";
Process p = Process.Start(wkhtmltopdf_path, url + " \"" + fileName + "\"");
p.WaitForExit();
return new Result(true, fileName);
}
catch (Exception ex)
{
return new Result(ex.Message);
}
}
/// <summary>
/// HTML文本内容转HTML文件,无页眉页脚
/// </summary>
/// <param name="strHtml">HTML文本内容</param>
/// <returns>Result</returns>
public static Result HtmlTextConvertFile(string strHtml)
{
if (string.IsNullOrEmpty(strHtml))
{
throw new Exception($"操作失败!HTML文本不得为空(路径:{strHtml})");
}
try
{
string path = AppDomain.CurrentDomain.BaseDirectory.ToString() + @"html\";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string fileName = path + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".html";
FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
StreamWriter streamWriter = new StreamWriter(fileStream, Encoding.Default);
streamWriter.Write(strHtml);
streamWriter.Flush();
streamWriter.Close();
streamWriter.Dispose();
fileStream.Close();
fileStream.Dispose();
return new Result(true, fileName);
}
catch (Exception ex)
{
return new Result(ex.Message);
}
}
/// <summary>
/// 生成静态页面保存
/// </summary>
/// <param name="url">html网址,例如:www.baidu.com</param>
/// <param name="modelName">模块名称,例如:仪器使用和维护记录</param>
/// <returns>消息实体</returns>
public static Result GetHtml(string url, string modelName)//url参数为将要生成的那个动态页面的地址,savepath为要存放地址
{
try
{
//pdf文件物理路径
string fileName = GetFilePath("PDF_files_html", modelName) + "\\" + modelName + DateTime.Now.ToString("_yyyyMMddHHmmssfffff") + ".html";
string Result;
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(request.GetRequestStream(), System.Text.Encoding.GetEncoding("utf-8")))//这里根据网站的编码格式而定
{
Result = reader.ReadToEnd();
reader.Close();
}
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.GetEncoding("utf-8"));
sw.WriteLine(Result);
sw.Close();
fs.Close();
response.Close();
return new Result(true, fileName);
}
catch (Exception ex)
{
return new Result(ex.Message);
}
}
#region 内部函数
/// <summary>
/// 根据模块名称获取文件路径
/// </summary>
/// <param name="folder">文件夹</param>
/// <param name="modelName">模块名称,例如:仪器使用和维护记录</param>
/// <returns>文件路径</returns>
private static string GetFilePath(string folder, string modelName)
{
string path = HttpRuntime.AppDomainAppPath.ToString() + folder + "\\" + modelName;
if (Directory.Exists(path) == false)//如果不存在就创建file文件夹
{
Directory.CreateDirectory(path);
}
return path;
}
/// <summary>
/// 获取命令行参数
/// </summary>
/// <param name="htmlPath"></param>
/// <param name="savePath"></param>
/// <param name="crosswise">是否横向,默认false,不横向</param>
/// <param name="header_left">页眉左</param>
/// <param name="header_right">页眉右</param>
/// <param name="footer_left">页脚左</param>
/// <param name="footer_center">页脚中</param>
/// <param name="foot_right">页脚右</param>
/// <returns></returns>
private static string GetArguments(string htmlPath, string savePath,
bool crosswise = false,
string header_left = "",
string header_right = "",
string footer_left = "",
string footer_center = "",
string foot_right = "")
{
if (string.IsNullOrEmpty(htmlPath))
{
throw new Exception("HTML local path or network address can not be empty.");
}
if (string.IsNullOrEmpty(savePath))
{
throw new Exception("The path saved by the PDF document can not be empty.");
}
StringBuilder stringBuilder = new StringBuilder();
if (crosswise)
{
stringBuilder.Append(" -O Landscape "); //设置横向生成pdf
}
stringBuilder.Append(" --margin-top 20 "); //设置页面的上边距,单位毫米(mm)
stringBuilder.Append(" --margin-bottom 20 "); //设置页面的下边距,单位毫米(mm)
stringBuilder.Append(" --page-height 350 "); //页面高度
stringBuilder.Append(" --page-width 210 "); //页面宽度
stringBuilder.Append(" --header-spacing 5 "); //设置页眉与内容之间的间距,单位毫米(mm)(默认值为:0)
stringBuilder.Append(" --footer-spacing 5 "); //设置页脚与内容之间的间距,单位毫米(mm)(默认值为:0)
stringBuilder.Append(" --header-center \"第[page]页共[topage]页\" "); //设置居中显示页眉
if (!string.IsNullOrWhiteSpace(header_left))
{
stringBuilder.Append($" --header-left {header_left} ");
}
if (!string.IsNullOrWhiteSpace(header_right))
{
stringBuilder.Append($" --header-right {header_right} ");
}
if (!string.IsNullOrWhiteSpace(footer_left))
{
stringBuilder.Append($" --footer-left {footer_left} ");
}
if (!string.IsNullOrWhiteSpace(footer_center))
{
stringBuilder.Append($" --footer-center {footer_center} ");
}
if (!string.IsNullOrWhiteSpace(foot_right))
{
stringBuilder.Append($" --footer-right {foot_right} ");
}
stringBuilder.Append(" " + htmlPath + " "); //本地 HTML 的文件路径或网页 HTML 的URL地址
stringBuilder.Append(" " + savePath + " "); //生成的 PDF 文档的保存路径
return stringBuilder.ToString();
}
#endregion
}
多谢,我试用一下
很好用,生成的pdf格式非常完美!
但是有个问题,用您的代码生成内容不太多的pdf没问题,后来测试了一个20多页带不少图片的就一直等待,测试后发现把这句代码去掉就好了:process.WaitForExit()
去掉后生成的pdf也很完美
我不知道是什么原理,记录一下供大家看到的话参考
如果两台服务器使用相同的代码生成的PDF在某些地方有重叠文字的问题,可能是由于两台服务器的环境设置、字体渲染或其他因素导致的差异。以下是一些可能的解决方法和替代方案:
检查服务器环境:确保两台服务器的操作系统、浏览器版本、字体设置等环境是相同的。如果存在差异,尝试将环境调整为相同配置,以确保生成的PDF结果一致。
检查字体设置:字体在HTML转PDF过程中起着重要的作用。确保两台服务器上使用的字体文件是相同的,并且正确地配置在转换过程中。可以尝试将字体文件放置在统一的位置,并在代码中指定字体文件的路径。
使用其他HTML转PDF插件:如果问题无法通过调整环境和字体解决,可以考虑尝试其他的HTML转PDF插件或库。一些常用的选择包括wkhtmltopdf、WeasyPrint、PDFKit等。这些工具也提供了将HTML转换为PDF的功能,并且可能在不同的服务器上产生一致的结果。您可以根据自己的需求和技术栈选择合适的工具。
调试和日志记录:为了更好地理解问题的原因,可以在代码中添加调试和日志记录功能。尝试输出生成PDF过程中的详细信息,例如使用的字体、渲染参数、版本信息等。这样可以帮助您更好地理解两台服务器之间差异的具体原因,并更有针对性地解决问题。
请注意,由于TuesPechkin的具体配置和使用情况有限,建议查阅其官方文档、论坛或社区,以获取更具体的指导和解决方案。另外,选择其他HTML转PDF工具时,也要确保仔细评估其功能、性能和适用性,以满足您的具体需求。
谢谢,改用wkhtmltopdf了,非常满意它不会破坏表格和文字的效果
既然都重叠了,而且字节数组中有的不一样,说明转换过程中,文字的轮廓信息有的可能偏小,文字的边界变小了,就往里面挤,就重叠了。文字的轮廓信息有哪些因素决定,我能想到的是字体。但一般导出都用的常见字体,系统的字体肯定是很全的,很大可能不是字体缺失的原因。
1.比较一下输入的html字符串,看有什么不同没,1是文字比较 2是转换成字节比较。
2.看有没有什么图片什么的,也不一样。去掉图片试试会不会一样了。
3.每次导出同样的内容都是相同的地方发生了重叠吗,如果是的话,在看看把那些重叠的文字单独多弄几份,看会不会重复。去掉了这些重叠的文字,又会不会重复。
4.换种字体试试,字体缩小试试,在html上加文字间距样式
谢谢,对比太麻烦,改用wkhtmltopdf了,非常满意它不会破坏表格和文字的效果