wkhtmltopdf outputstream & download - diaglog

后端 未结 2 450
小蘑菇
小蘑菇 2021-01-05 14:08

is it possible to get a pdf stream created by wkhtmltopdf from any html file and popup a download dialog in IE/Firefox/Chrome etc.?

At the moment I get my outputstre

相关标签:
2条回答
  • 2021-01-05 14:17

    Is this still a problem?

    I just created a new ASP.net website to test this on my computer after installing wkhtmltopdf 0.11.0 rc2 and it worked fine creating the PDF. My version was only slightly different;

    In my CSHTML I had:

    MemoryStream PDFStream = new MemoryStream();
    MemoryStream PDF = Derp.GeneratePdf(PDFStream);
    byte[] byteArray1 = PDF.ToArray();
    PDF.Flush();
    PDF.Close();
    Response.BufferOutput = true;
    Response.Clear();
    Response.ClearHeaders();
    Response.AddHeader("Content-Disposition", "attachment; filename=Test.pdf");
    Response.ContentType = "application/octet-stream";
    Response.BinaryWrite(byteArray1);
    Response.End();
    

    My Derp class

    public class Derp
    {
        public static MemoryStream GeneratePdf(MemoryStream pdf)
        {
            using (StreamReader Html = new StreamReader(@"Z:\HTMLPage.htm"))
            {
                Process p;
                StreamWriter stdin;
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = @"C:\wkhtmltopdf\wkhtmltopdf.exe";
                psi.UseShellExecute = false;
                psi.CreateNoWindow = true;
                psi.RedirectStandardInput = true;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardError = true;
                psi.Arguments = "-q -n --disable-smart-shrinking " + " - -";
                p = Process.Start(psi);
                try
                {
                    stdin = p.StandardInput;
                    stdin.AutoFlush = true;
                    stdin.Write(Html.ReadToEnd());
                    stdin.Dispose();
                    CopyStream(p.StandardOutput.BaseStream, pdf);
                    p.StandardOutput.Close();
                    pdf.Position = 0;
                    p.WaitForExit(10000);
                    return pdf;
                }
                catch
                {
                    return null;
                }
                finally
                {
                    p.Dispose();
                }
            }
        }
    
        public static void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[32768];
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, read);
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-05 14:29

    My take on this based on @Nenotlep answer. This is only the pdf generation part.

    I am using async. I created a new StreamWriter because wkhtmltopdf is expecting utf-8 by default but it is set to something else when the process starts.

    I removed p.WaitForExit(...) since I wasn't handling if it fails and it would hang anyway on await tStandardOutput. If timeout is needed, then you would have to call Wait on the different tasks with a cancellationtoken or timeout and handle accordingly.

    public static async Task<byte[]> GeneratePdf(string html, Size pageSize)
    {
        ProcessStartInfo psi = new ProcessStartInfo
        {
            FileName = @"C:\PROGRA~1\WKHTML~1\wkhtmltopdf.exe",
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardInput = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            Arguments = "-q -n --disable-smart-shrinking " 
                + (pageSize.IsEmpty ? "" : "--page-width " + pageSize.Width 
                + "mm --page-height " + pageSize.Height + "mm") + " - -";
        };
    
        using (var p = Process.Start(psi))
        using (var pdfSream = new MemoryStream())
        using (var utf8Writer = new StreamWriter(p.StandardInput.BaseStream, 
                                Encoding.UTF8))
        {
            await utf8Writer.WriteAsync(html);
            utf8Writer.Close();
            var tStdOut = p.StandardOutput.BaseStream.CopyToAsync(pdfSream);
            var tStdError = p.StandardError.ReadToEndAsync();
    
            await tStandardOutput;
            string errors = await tStandardError;
    
            if (!string.IsNullOrEmpty(errors))
            {
                //deal with errors
            }
    
            return pdfSream.ToArray();
        }
    }
    

    Things I haven't included in there but could be useful as a reference:

    • you can pass the authentication cookie if needed using --cookie
    • you can set the base tag with href pointing to the server of your html page for additional requests (css, image, etc) in your html page
    0 讨论(0)
提交回复
热议问题