首页 新闻 会员 周边

.net 使用TuesPechkin生成pdf遇到的问题

0
[已解决问题] 解决于 2023-07-11 00:03

我们采用的TuesPechkin来把html页面生成pdf,现在遇到一个问题是我们的两台服务器调用相同的代码生成的pdf会有细微差别,两者转换的byte数组长度一样,但是对比后发现并不完全相等,导致的结果就是其中一台服务器生成的pdf某些地方的文字会有重叠。

求大佬指点应该怎么处理啊,或者有没有其他更好用的html转pdf插件推荐

hangjy的主页 hangjy | 初学一级 | 园豆:4
提问于:2023-07-05 11:03
< >
分享
最佳答案
0

之前有个老项目就是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

}
奖励园豆:5
0Behavior | 初学一级 |园豆:197 | 2023-07-05 14:50

多谢,我试用一下

hangjy | 园豆:4 (初学一级) | 2023-07-05 19:54

很好用,生成的pdf格式非常完美!
但是有个问题,用您的代码生成内容不太多的pdf没问题,后来测试了一个20多页带不少图片的就一直等待,测试后发现把这句代码去掉就好了:process.WaitForExit()

去掉后生成的pdf也很完美

我不知道是什么原理,记录一下供大家看到的话参考

hangjy | 园豆:4 (初学一级) | 2023-07-06 10:58
其他回答(2)
0

如果两台服务器使用相同的代码生成的PDF在某些地方有重叠文字的问题,可能是由于两台服务器的环境设置、字体渲染或其他因素导致的差异。以下是一些可能的解决方法和替代方案:

检查服务器环境:确保两台服务器的操作系统、浏览器版本、字体设置等环境是相同的。如果存在差异,尝试将环境调整为相同配置,以确保生成的PDF结果一致。

检查字体设置:字体在HTML转PDF过程中起着重要的作用。确保两台服务器上使用的字体文件是相同的,并且正确地配置在转换过程中。可以尝试将字体文件放置在统一的位置,并在代码中指定字体文件的路径。

使用其他HTML转PDF插件:如果问题无法通过调整环境和字体解决,可以考虑尝试其他的HTML转PDF插件或库。一些常用的选择包括wkhtmltopdf、WeasyPrint、PDFKit等。这些工具也提供了将HTML转换为PDF的功能,并且可能在不同的服务器上产生一致的结果。您可以根据自己的需求和技术栈选择合适的工具。

调试和日志记录:为了更好地理解问题的原因,可以在代码中添加调试和日志记录功能。尝试输出生成PDF过程中的详细信息,例如使用的字体、渲染参数、版本信息等。这样可以帮助您更好地理解两台服务器之间差异的具体原因,并更有针对性地解决问题。

请注意,由于TuesPechkin的具体配置和使用情况有限,建议查阅其官方文档、论坛或社区,以获取更具体的指导和解决方案。另外,选择其他HTML转PDF工具时,也要确保仔细评估其功能、性能和适用性,以满足您的具体需求。

Technologyforgood | 园豆:5675 (大侠五级) | 2023-07-06 22:35

谢谢,改用wkhtmltopdf了,非常满意它不会破坏表格和文字的效果

支持(0) 反对(0) hangjy | 园豆:4 (初学一级) | 2023-07-10 23:50
0

既然都重叠了,而且字节数组中有的不一样,说明转换过程中,文字的轮廓信息有的可能偏小,文字的边界变小了,就往里面挤,就重叠了。文字的轮廓信息有哪些因素决定,我能想到的是字体。但一般导出都用的常见字体,系统的字体肯定是很全的,很大可能不是字体缺失的原因。
1.比较一下输入的html字符串,看有什么不同没,1是文字比较 2是转换成字节比较。
2.看有没有什么图片什么的,也不一样。去掉图片试试会不会一样了。
3.每次导出同样的内容都是相同的地方发生了重叠吗,如果是的话,在看看把那些重叠的文字单独多弄几份,看会不会重复。去掉了这些重叠的文字,又会不会重复。
4.换种字体试试,字体缩小试试,在html上加文字间距样式

HelloLLLLL | 园豆:434 (菜鸟二级) | 2023-07-07 23:02

谢谢,对比太麻烦,改用wkhtmltopdf了,非常满意它不会破坏表格和文字的效果

支持(0) 反对(0) hangjy | 园豆:4 (初学一级) | 2023-07-10 23:51
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册