C# wkhtmltopdf HTML中带有重定向输入/输出流的相对路径赢得';行不通

C# wkhtmltopdf HTML中带有重定向输入/输出流的相对路径赢得';行不通,c#,.net,stdin,relative-path,wkhtmltopdf,C#,.net,Stdin,Relative Path,Wkhtmltopdf,我正在使用wkhtmltopdf.exe(最终版本0.12.0)从html文件生成pdf文件,我使用.NETC来实现这一点# 我的问题是让javascript、样式表和图像只通过在html中指定相对路径来工作。现在,如果我使用绝对路径,它就可以工作了。但是它不适用于相对路径,这使得整个html生成有点复杂。我将我所做的归结为以下示例: string CMDPATH = @"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe"; string HTML

我正在使用wkhtmltopdf.exe(最终版本0.12.0)从html文件生成pdf文件,我使用.NETC来实现这一点#

我的问题是让javascript、样式表和图像只通过在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();
在这个阶段我真的需要一些投入。因此,非常感谢您的帮助

仅供参考,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);
    }
}
编辑:我的新阮解决方案。

我无法使它与相对路径一起工作。因此,我所做的是一个方法,用根路径在所有路径前面加上前缀。它解决了我的问题,也可能解决了你的问题:

/// <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;
}
//
///将src=“x”或href=“x”中的basedir x预先添加到输入html文本中
/// 
///最初的html
///要预结束的basedir
///新的html
公共静态字符串MakeRelativePathsAbsolute(字符串html、字符串basedir)
{
string pathpattern=“(?:href=[\”]| src=[\”])(.*?[\”];
//SM20140214:测试chrome和wkhtmltopdf.exe是否都能理解“C:\Dir\..\image.png”和“C:\Dir\.\image.png”
//路径组合(“C:/
html=Regex.Replace(html、pathpattern、新的MatchEvaluator((匹配)=>
{
字符串newpath=UrlEncode(Path.Combine(basedir,match.Groups[1].Value));
如果(!string.IsNullOrEmpty(match.Groups[1].Value))
{
字符串结果=match.Groups[0]。Value.Replace(match.Groups[1]。Value,newpath);
返回结果;
}
其他的
{
返回UrlEncode(match.Groups[0].Value);
}
}));
返回html;
}
私有静态字符串url编码(字符串url)
{
url=url.Replace(“,“%20”)。Replace(“#“,“%23”);
返回url;
}

我尝试了不同的System.Uri.Escape***方法,如System.Uri.EscapeDataString()。但他们最终对wkhtmltopdf进行了严格的url编码以理解它。由于时间不够,我只进行了上面快速而肮脏的url编码。

快速查看,我认为问题可能在于

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位于同一文件夹中…所以请尝试将
工作目录设置为该目录,看看会发生什么情况。

AppDomain.CurrentDomain.BaseDirectory是“C:\Development\Tests\WKHTMLOTPDFTEST\WKHTMLOTPDFTEST\bin\Debug“这也是我运行命令行表达式的位置。所以我不认为这是问题所在。也许你可以将绝对路径添加到
test.html
sohbogo.png
,以及你对问题运行命令的位置;它将提供更多信息并阻止像我这样的错误答案:)嘿,伙计,你想出办法了吗?我现在的处境和你一样…:)你好,尼奥。我编辑了我的问题,来解释a是如何解决这个问题的。希望你能用它做点什么。
"c:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe" test.html test.pdf