25

how to pass html as a string instead of url in wkhtmltopdf using asp.net, c#?

2
  • It'd probably be easiest to redirect stdin and pass the string that way. You could also write the text to a file (though that's not going to scale very well, of course). Commented Jan 10, 2011 at 20:49
  • Could you please show an example? Commented Jan 10, 2011 at 20:50

3 Answers 3

38

STDIn and STDOut have been redirected in this example, so you shouldn't need files at all.

public static class Printer
{
    public const string HtmlToPdfExePath = "wkhtmltopdf.exe";

    public static bool GeneratePdf(string commandLocation, StreamReader html, Stream pdf, Size pageSize)
    {
        Process p;
        StreamWriter stdin;
        ProcessStartInfo psi = new ProcessStartInfo();

        psi.FileName = Path.Combine(commandLocation, HtmlToPdfExePath);
        psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);

        // run the conversion utility
        psi.UseShellExecute = false;
        psi.CreateNoWindow = true;
        psi.RedirectStandardInput = true;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;

        // note: that we tell wkhtmltopdf to be quiet and not run scripts
        psi.Arguments = "-q -n --disable-smart-shrinking " + (pageSize.IsEmpty? "" : "--page-width " + pageSize.Width +  "mm --page-height " + pageSize.Height + "mm") + " - -";

        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 true;
        } catch {
            return false;

        } 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);
        }
    }
}
Sign up to request clarification or add additional context in comments.

15 Comments

no need to Close and Dispose the Process, it does the same thing. Just dispose it, or put it in a using construct. Same goes for Streams..
+1 Great post, I wrote about it recently using similar code: megustaulises.com/2012/12/…
Great post it helped a lot
what is the purpose of ` - - ` at the end of the arguments ? I know it has something to do with outputting to STDOUT, but is that a wkhtmltopdf construct, or will that work for any command line?
@Walter Stabosz see here code.google.com/p/wkhtmltopdf/wiki/Usage. Using - tells wkhtmltopdf to use a standard stream.
|
16

Redirecting STDIN is probably the easiest way to accomplish what you're trying to do.

One method of redirecting STDIN with wkhtmltopdf (in ASP.Net) is as follows:

    private void WritePDF(string HTML)
    {
        string inFileName,
                outFileName,
                tempPath;
        Process p;
        System.IO.StreamWriter stdin;
        ProcessStartInfo psi = new ProcessStartInfo();

        tempPath = Request.PhysicalApplicationPath + "temp\\";
        inFileName = Session.SessionID + ".htm";
        outFileName = Session.SessionID + ".pdf";

        // run the conversion utility
        psi.UseShellExecute = false;
        psi.FileName = "c:\\Program Files (x86)\\wkhtmltopdf\\wkhtmltopdf.exe";
        psi.CreateNoWindow = true;
        psi.RedirectStandardInput = true;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;

        // note that we tell wkhtmltopdf to be quiet and not run scripts
        // NOTE: I couldn't figure out a way to get both stdin and stdout redirected so we have to write to a file and then clean up afterwards
        psi.Arguments = "-q -n - " + tempPath + outFileName;

        p = Process.Start(psi);

        try
        {
            stdin = p.StandardInput;
            stdin.AutoFlush = true;

            stdin.Write(HTML);
            stdin.Close();

            if (p.WaitForExit(15000))
            {
                // NOTE: the application hangs when we use WriteFile (due to the Delete below?); this works
                Response.BinaryWrite(System.IO.File.ReadAllBytes(tempPath + outFileName));
                //Response.WriteFile(tempPath + outFileName);
            }
        }
        finally
        {
            p.Close();
            p.Dispose();
        }

        // delete the pdf
        System.IO.File.Delete(tempPath + outFileName);
    }

Note that the code above assumes that there's a temp directory available in your application directory. Also, you must explicitly enable write access to that directory for the user account used when running the IIS process.

3 Comments

I can't get this to work with referenced images and stylesheets. It that possible? When I run the commandline with files on disk it works.
@smerlung Make sure that the web app has access to the files that you're referencing. When running from the command line, you're running as your login; when running from the web server, you're running as the web server login which may not have access to the files you're using. Also, make sure that the path to the files makes sense from that location as well. For example, if you're referencing ..\styles\style.css then there needs to be a styles directory, 'above' where you're running the program, that contains the style.css file.
I got it working by using absolute paths. But that isn't very nice. I understand what your saying, but my problem is that I don't understand where the process is "running". I've tried different options for WorkingDirectory but couldn't figure it out?
3

I know this is an older post, but I want future developers to have this option. I had the same need, and the idea of having to start a background process just to get a PDF inside of a web app is terrible.

Here's another option: https://github.com/TimothyKhouri/WkHtmlToXDotNet

It's a .NET native wrapper around wkhtmltopdf.

Sample code here:

var pdfData = HtmlToXConverter.ConvertToPdf("<h1>COOOL!</h1>");

Note, it's not thread-safe as of right now - I'm working on that. So just use a monitor or something or a lock.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.