Wkhtmltopdf относительные пути в HTML с перенаправленными потоками/выходами не будут работать

Я использую wkhtmltopdf.exe(окончание версии 0.12.0) для создания PDF файлов из html файлов, я делаю это с .NET С#

Моя проблема заключается в том, чтобы работать с javascript, stylesheets и изображениями, указывая только относительные пути в html. Сейчас я работаю, если использую абсолютные пути. Но это не работает с относительными путями, что делает целое поколение html немного сложным. Я отварил то, что я делаю, до следующего примера:

string CMDPATH = @"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe";
string HTML = string.Format(
    "<div><img src=\"{0}\" /></div><div><img src=\"{1}\" /></div><div>{2}</div>",
    "./sohlogo.png",
    "./ACLASS.jpg",
    DateTime.Now.ToString());

WriteFile(HTML, "test.html");

Process p;
ProcessStartInfo psi = new ProcessStartInfo();

psi.FileName = CMDPATH;
psi.UseShellExecute = false;
psi.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;

psi.Arguments = "-q - -";

p = Process.Start(psi);

StreamWriter stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(HTML);
stdin.Dispose();

MemoryStream pdfstream = new MemoryStream();
CopyStream(p.StandardOutput.BaseStream, pdfstream);
p.StandardOutput.Close();
pdfstream.Position = 0;

WriteFile(pdfstream, "test.pdf");

p.WaitForExit(10000);
int test = p.ExitCode;

p.Dispose();

Я пробовал относительные пути, такие как:./sohlogo.png, и просто "sohlogo.png", оба отображаются корректно в браузере через html файл. Но ни один из них не работает в файле pdf. В потоке ошибок нет данных.

Следующая командная строка работает как шарм с относительными путями:

"c:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe" test.html test.pdf

На данном этапе мне действительно понадобился некоторый вклад. Поэтому любая помощь очень ценится!

Только для справки методы WriteFile и CopyStream выглядят следующим образом:

public static void WriteFile(MemoryStream stream, string path)
{
    using (FileStream writer = new FileStream(path, FileMode.Create))
    {
        byte[] bytes = stream.ToArray();
        writer.Write(bytes, 0, bytes.Length);
        writer.Flush();
    }
}

public static void WriteFile(string text, string path)
{
    using (StreamWriter writer = new StreamWriter(path))
    {
        writer.WriteLine(text);
        writer.Flush();
    }
}

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);
    }
}

EDIT: Мое обходное решение для Neo Nguyen.

Я не мог заставить это работать с относительными путями. Так что я сделал вместо этого метод, который добавляет все пути с корневым путем. Он решает мою проблему, поэтому, возможно, она решит вашу проблему:

/// <summary>
/// Prepends the basedir x in src="x" or href="x" to the input html text
/// </summary>
/// <param name="html">the initial html</param>
/// <param name="basedir">the basedir to prepend</param>
/// <returns>the new html</returns>
public static string MakeRelativePathsAbsolute(string html, string basedir)
{
    string pathpattern = "(?:href=[\"']|src=[\"'])(.*?)[\"']";

    // SM20140214: tested that both chrome and wkhtmltopdf.exe understands "C:\Dir\..\image.png" and "C:\Dir\.\image.png"
    //             Path.Combine("C:/
    html = Regex.Replace(html, pathpattern, new MatchEvaluator((match) =>
        {
            string newpath = UrlEncode(Path.Combine(basedir, match.Groups[1].Value));
            if (!string.IsNullOrEmpty(match.Groups[1].Value))
            {
                string result = match.Groups[0].Value.Replace(match.Groups[1].Value, newpath);
                return result;
            }
            else
            {
                return UrlEncode(match.Groups[0].Value);
            }
        }));

    return html;
}

private static string UrlEncode(string url)
{
    url = url.Replace(" ", "%20").Replace("#", "%23");
    return url;
}

Я пробовал различные методы System.Uri.Escape ***, такие как System.Uri.EscapeDataString(). Но они решили сделать серьезную кодировку url для wkhtmltopdf, чтобы понять это. Из-за нехватки времени я просто сделал быстрый и грязный UrlEncode выше.

Ответы

Ответ 1

Заглядывая быстро, я думаю, что проблема может быть с

psi.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;

Я думаю, что именно там указывают пути. Я предполагаю, что

"c:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe" test.html test.pdf

означает, что ваше изображение, на которое ссылается внутри test.html как src="mlp.png", находится на c:\Program Files\wkhtmltopdf\bin\mlp.png, правильно? Я думаю, что это работает, потому что ваш файл изображения находится в той же папке, что и wkhtmltopdf... поэтому попробуйте установить WorkingDirectory в этот каталог и посмотреть, что произойдет.