2012-10-26 21 views
8

Bir HTML belgesini, bir C# web uygulamasından aradığım wkhtmltopdf.exe dosyasını kullanarak PDF olarak oluşturmaya çalışıyorum.WkHtmlToPDF - stdin ve üstbilgi/altbilgi ile çalışma

HTML belgesinin, her sayfada yinelenen hem altbilgiye hem de üstbilgiye sahip olması gerekir; bu, argüman olarak --header-html <a path> belirtilerek wkhtmltopdf ile mümkündür.

Ancak, altbilgi bir Razor görünümünden dinamik olarak oluşturulur ve bu dosyayı diske geçici bir dosyada saklamak zorunda kalmaz ve bu yolu kullanır, ancak zaten belleğe alınmış HTML'yi kullanmak istiyorum. Bu belgenin kendisi için, bu yüzden gibi StandardInput akışına yazarak mümkündür:

var wkhtml = ConfigurationManager.AppSettings["WkHtmlToPdfPath"]; 
var p = new Process(); 

p.StartInfo.CreateNoWindow = true; 
p.StartInfo.RedirectStandardOutput = true; 
p.StartInfo.RedirectStandardError = true; 
p.StartInfo.RedirectStandardInput = true; 
p.StartInfo.UseShellExecute = false; 
p.StartInfo.FileName = wkhtml; 

p.StartInfo.Arguments = "-q -n --disable-smart-shrinking - -"; 
p.Start(); 

var stdin = p.StandardInput; 
stdin.AutoFlush = true; 
stdin.Write(template); 
stdin.Dispose(); 

yani başvurmak zorunda kalmadan çizgi içi geçmek, üstbilgi ve altbilgi HTML için aynı şeyi yapmak için mümkün mü geçici dosyalar? Denedim

:

stdin.Write(string.Format("--footer-html {0} ", footer)); 

Ama tabii, sadece sayan belgeye değil, bir altbilgi parçası olarak kullanılabilir.

Altbilgiyi ve üstbilgisini dinamik olarak da açmak istediğim başlıca neden (çoğunlukla) başka bir sorundan kaynaklanıyor. Dinamik bir üstbilgi ve altbilgiye sahip olmak güzel olsa da, çoğunlukla göreli yollar (örneğin: C: \ templates \ images \ logo.png) ile mutlak bir yol olan görüntülere bağlamam gereken sorunu çözerim. images/logo.png) stdin'i kullandığınızda ve sadece HTML dizgisi bloğundan geçtiğinizde çalışmaz, bu yüzden çalışma zamanında Razor ile mutlak yolu eklemem gerekir. Bu sorunu için

, ben göreli yolları maç için sürecin çalışma dizinini ayarlama denedim, ama boşuna: Ben bu sorunu çözmek olsaydı

p.StartInfo.WorkingDirectory = @"C:\templates"; 

, yani% 90 çözeceği konusundaki sorun da. Ben doğrudan çıkış akışı için gerekli sayede bu JulianR çözüldü ve ben de aşağıda başlangıç ​​kodunun bazı göz ardı edebilirsiniz Eğer değilse MVC (?) içindedir üstlenecek, ama benzer bir durum olsaydı

+2

Aynı sorunu yaşadım, ancak Wkhtmltopdf üstbilgileri/altbilgileri ayrı olarak tehdit ettiğinden (dış yollar/URL'ler aracılığıyla), dinamik verileri kendi URL'sine beslediğim bir html belgesi tanımlamayı bitirdim.Daha sonra bazı javascript ile bunları ayıkladım. – Alex

cevap

3

Not emin Bir sitenin güvenli ve giriş bölümleri nedeniyle wkhtmltopdf.

Öncelikle bir denetleyici içinde size (kendisi Üstbilgi ve altbilgi kullanabileceğini) geçerli ana sayfası ile ekran için ihtiyaç View indirebiliriz:

var view = ViewEngines.Engines.FindView(ControllerContext, myViewName, myMasterPageLayout); 

sonra bu görüş akım elde vb gerekli ViewData, TempData ve bir dizede bu depolamak (aşağıda içeriği): gerekirse

string content; 
ViewData.Model = model; 
using (var writer = new System.IO.StringWriter()) 
{ 
    var context = new ViewContext(ControllerContext, view.View, ViewData, TempData, writer); 
    view.View.Render(context, writer); 
    writer.Flush(); 
    content = writer.ToString(); 
    writer.Close(); 
} 

bu aşamada aslında dizede çıktı html değiştirebilir - örneğin Tam yolları Seninle

çıktı HTML sonra sadece wkhtmltopdf geçmesine herhangi bir yerel yollarını değiştirmek:

var p = new Process(); 
p.StartInfo.CreateNoWindow = true; 
p.StartInfo.RedirectStandardOutput = true; 
p.StartInfo.RedirectStandardError = true; 
p.StartInfo.RedirectStandardInput = true; 
p.StartInfo.UseShellExecute = false; 
//Other parameters as required 
byte[] file; 
try 
{ 
    p.Start(); 
    byte[] buffer = new byte[32768]; 

    using (System.IO.StreamWriter stdin = p.StandardInput) 
    { 
     stdin.AutoFlush = true; 
     stdin.Write(content); 
    } 


    using (MemoryStream ms = new MemoryStream()) 
    { 
     ms.Position = 0; 
     p.StandardOutput.BaseStream.CopyTo(ms); 
     file = ms.ToArray(); 
    } 

    p.StandardOutput.Close(); 
    // wait or exit 
    p.WaitForExit(60000); 

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

} 

sonra bütün sayfanın PDF içeriğe sahip bir bayt dizisi var.

+0

Bilgi için teşekkürler. Bu sorunu çözmedim ve bunun yerine raporları düzenlerken önemli ölçüde beceriksizliğe rağmen bir dizi avantajı (basitlik, yerel baskı desteği) olan Microsoft RDLC raporlarını kullandım. – JulianR