문제

This question already has an answer here:

After 10 hours and trying 4 other HTML to PDF tools I'm about ready to explode.

wkhtmltopdf sounds like an excellent solution...the problem is that I can't execute a process with enough permissions from asp.net so...

Process.Start("wkhtmltopdf.exe","http://www.google.com google.pdf");

starts but doesn't do anything.

Is there an easy way to either:

-a) allow asp.net to start processes (that can actually do something) or
-b) compile/wrap/whatever wkhtmltopdf.exe into somthing I can use from C# like this: WkHtmlToPdf.Save("http://www.google.com", "google.pdf");

도움이 되었습니까?

해결책

You could also use Pechkin

.NET Wrapper for WkHtmlToPdf DLL, library that uses Webkit engine to convert HTML pages to PDF.

Nuget packages:

Pechkin.Synchronized

Pechkin

다른 팁

I just started a new project to provide a C# P/Invoke wrapper around wkhtmltopdf.

You can checkout my code at: https://github.com/pruiz/WkHtmlToXSharp

Greets.

Thanks to Paul, I have found the good wrapper written by Codaxy, which can also be easily downloaded via NuGet.

After a few trials, I have managed this MVC action, that instantly creates and returns the PDF file as a stream:

public ActionResult Pdf(string url, string filename)
{
    MemoryStream memory = new MemoryStream();
    PdfDocument document = new PdfDocument() { Url = url };
    PdfOutput output = new PdfOutput() { OutputStream = memory };

    PdfConvert.ConvertHtmlToPdf(document, output);
    memory.Position = 0;

    return File(memory, "application/pdf", Server.UrlEncode(filename));
}

Here, the Pdf* classes have been implemented in the wrapper, with a nice, clean code, unfortunately lacking documentation.

Within the converter, the URL will be converted to a PDF, stored in a temporary file, copied to the stream that we have given as parameter, and afterwards the PDF file is deleted.

Finally, we have to push the stream as FileStreamResult.

Do not forget to set the output stream's Position to zero, otherwise you will see PDF files being downloaded as zero bytes of size.

Here is the actual code I used. Please feel free to edit this to get rid of some of the smells and other terribleness...I know its not that great.

using System;
using System.Diagnostics;
using System.IO;
using System.Web;
using System.Web.UI;

public partial class utilities_getPDF : Page
{
    protected void Page_Load(Object sender, EventArgs e)
    {
        string fileName = WKHtmlToPdf(myURL);

        if (!string.IsNullOrEmpty(fileName))
        {
            string file = Server.MapPath("~\\utilities\\GeneratedPDFs\\" + fileName);
            if (File.Exists(file))
            {
                var openFile = File.OpenRead(file);
                // copy the stream (thanks to http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances-c)
                byte[] buffer = new byte[32768];
                while (true)
                {
                    int read = openFile.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                    {
                        break;
                    }
                    Response.OutputStream.Write(buffer, 0, read);
                }
                openFile.Close();
                openFile.Dispose();

                File.Delete(file);
            }
        }
    }

    public string WKHtmlToPdf(string Url)
    {
        var p = new Process();

        string switches = "";
        switches += "--print-media-type ";
        switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
        switches += "--page-size Letter ";
        // waits for a javascript redirect it there is one
        switches += "--redirect-delay 100";

        // Utils.GenerateGloballyUniuqueFileName takes the extension from
        // basically returns a filename and prepends a GUID to it (and checks for some other stuff too)
        string fileName = Utils.GenerateGloballyUniqueFileName("pdf.pdf");

        var startInfo = new ProcessStartInfo
                        {
                            FileName = Server.MapPath("~\\utilities\\PDF\\wkhtmltopdf.exe"),
                            Arguments = switches + " " + Url + " \"" +
                                        "../GeneratedPDFs/" + fileName
                                        + "\"",
                            UseShellExecute = false, // needs to be false in order to redirect output
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
                            WorkingDirectory = Server.MapPath("~\\utilities\\PDF")
                        };
        p.StartInfo = startInfo;
        p.Start();

        // doesn't work correctly...
        // read the output here...
        // string output = p.StandardOutput.ReadToEnd();

        //  wait n milliseconds for exit (as after exit, it can't read the output)
        p.WaitForExit(60000);

        // read the exit code, close process
        int returnCode = p.ExitCode;
        p.Close();

        // if 0, it worked
        return (returnCode == 0) ? fileName : null;
    }
}

I can't comment so I post this as an 'answer' to the comments of above answer How to use wkhtmltopdf.exe in ASP.net

If --redirect-delay doesn't work, try --javascript-delay See here for all the options: https://github.com/antialize/wkhtmltopdf/blob/master/README_WKHTMLTOPDF

Or do wkhtmltopdf -H for extended help (afaik same output as above link).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top