首页 > 解决方案 > 尝试从缓冲区读取字节到 int 时进程挂起。wkhtmltopdf

问题描述

我的方法使用Wkhtmltopdf带有Process. 我找不到它挂起的原因。当有一个带有 HTML 的大字符串时,我想当有 30 页或更多页面时它会挂起。但是,如果页面较少,一切正常。我可以看到 Wkhtmltopdf.exe 进程Task Manager,它不会永远退出。hanged当我用Wkhtmltopdf停止我的 MVC 项目时, it creates normallyPDF 就像它会等待一些东西。当然,手动地,Wkhtmltopdf 可以毫无问题地创建所有内容。这不是这篇文章的重复。这里我在尝试将字节读入 int 时遇到问题。

public IActionResult createPdf()
{
    string html = "content";

    Process p;
    ProcessStartInfo psi = new ProcessStartInfo();

    psi.FileName = "...\\wkhtmltopdf.exe";
    psi.WorkingDirectory = "...\\wkhtmltopdf\\bin";

    psi.UseShellExecute = false;
    psi.CreateNoWindow = true;
    psi.RedirectStandardInput = true;
    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.StandardOutputEncoding = System.Text.Encoding.UTF8;
    psi.Arguments = "-O landscape --footer-left qwe --footer-center [page]/[topage] --footer-right --footer-font-size 9 --no-stop-slow-scripts --zoom 0.8 --dpi 300 - - ";

    p = Process.Start(psi);

    byte[] pdf = null;

    try
    {
        // Get PDF as bytes without temp files
        using(StreamWriter stdin = new StreamWriter(p.StandardInput.BaseStream, Encoding.UTF8))
        {
              stdin.AutoFlush = true;
              stdin.Write(html);
         }

         byte[] buffer = new byte[32768];
         using(var ms = new MemoryStream())
         {
              while(true)
              {
                   // HANGS HERE!!!
                   int read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length); 

                   if(read <= 0)
                   {
                       break;
                   }       
                   ms.Write(buffer, 0, read);
              }
              pdf = ms.ToArray();
          }      
    }
    ...


}

标签: c#asp.net-mvcwkhtmltopdf

解决方案


我设法通过使用PdfSharp将分离的pdf 文件合并为一个来解决这个问题,而不是将连接的内容作为一个传递。它持续时间更长一点,但至少它有效。除了库(如果您像我一样使用 MVC,则排除版本警告),您可能需要安装以排除可能导致的编码错误。我的方法不使用临时文件,只使用字节,最后它将创建的 pdf 发送到浏览器。wkhtmltopdfPdfSharpPdfSharp.CoreSystem.Text.Encoding.CodePagesPdfSharp

using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;

public IActionResult createPdf()
{
    string html = "";
    byte[] pdf = null;

    using(PdfDocument doc = new PdfDocument())
    {
        for(int i = 0; i < files.Length; i++)
        {
            html = "html content";

            Process p;
            ProcessStartInfo psi = new ProcessStartInfo();

            psi.FileName = "...\\wkhtmltopdf.exe";
            psi.WorkingDirectory = "...\\wkhtmltopdf\\bin";

            psi.UseShellExecute = false;
            psi.CreateNoWindow = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.StandardOutputEncoding = System.Text.Encoding.UTF8;
            psi.Arguments = "-O landscape --footer-left qwe --footer-center [page]/[topage] --footer-right --footer-font-size 9 --no-stop-slow-scripts --zoom 0.8 --dpi 300 - - ";

            p = Process.Start(psi);

            using(StreamWriter stdin = new StreamWriter(p.StandardInput.BaseStream, Encoding.UTF8))
            {
                stdin.AutoFlush = true;
                stdin.Write(html);
            }

            byte[] buffer = new byte[32768];
            byte[] currentPdf = null;
            using(var ms = new MemoryStream())
            {
                while(true)
                {
                    int read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length); 

                    if(read <= 0)
                    {
                        break;
                    }       
                    ms.Write(buffer, 0, read);
                 }
                 currentPdf = ms.ToArray();
             }

             p.StandardOutput.Close();
             p.WaitForExit(10000);
             p.Close();     

             MemoryStream currentPDF = new MemoryStream(currentPdf);

             // Merge separated pdfs into one
// Solves encoding errors   
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

             using(PdfDocument pdfDoc = PdfReader.Open(currentPDF, PdfDocumentOpenMode.Import))
             {
                 for(int j = 0; j < pdfDoc.PageCount; j++)
                 {
                     doc.AddPage(pdfDoc.Pages[j]);
                 }
             }

             currentPDF.Close();
        }

        // Get merged pdfs as bytes
        MemoryStream rms = new MemoryStream();
        doc.Save(rms, false);
        pdf = rms.ToArray();
        rms.Close();
    }

    MemoryStream PDF = new MemoryStream(pdf);

    // Return PDF to browser
    return new FileStreamResult(PDF, "application/x-msdownload")
    {
        FileDownloadName = "mergedPdfs.pdf"
    }; 
}

推荐阅读