Jako bibliotekę, która zamienia html na pdf, wykorzystałem darmową bibliotekę, dostarczoną przez google, czyli wkhtmltopdf. Ta biblioteka jest dużo lepsza, od konkurencyjnej itextsharp ponieważ itextsharp na chwilę obecną nie radzi sobie z bardziej skomplikowanymi html'ami (w moim przypadku był to brak chart'ów o których wspomniałem w moim poprzednim wpisie).
Aby korzystać płynnie z wkhtmltopdf w .NET, skorzystałem z darmowej biblioteki Pechkin (link do githuba). Przykład wykorzystania pechkin'a z wkhtmltopdf można znaleźć na githubie ale również np. na blogu Ulises Reyes.
Ulises po za kilkoma przykładami użycia, informuje nas również o kilku ważnych aspektach korzystania z Pechkina:
Ok. Mamy bibliotekę (napisaną w C), do zamiany html'a w pdf. Mamy adapter, aby wykorzystać tą bibliotekę w .NET. Brakuje nam jeszcze odpowiedniego kodu, aby wykorzystać to w naszej ukochanej Nancy. Na szczęście, natknąłem się na podobny wpis na blogu Shane Mitchell link. Tam wprawdzie była wykorzystywana inna biblioteka, ale nic nie stało na przeszkodzie, aby wszystko połączyć w jedną całość i utworzyć klasę, generującą odpowiedni widok:
- It's trivial, here are some gotchas though:
- GIF Images are not supported
- Paths to images must be fully qualified as URLs (http://example.com/a/b/image.jpg) or file URIs (file://host/path)
- Resources over HTTPS cannot be fetched through URLs. You can get around this by specifying the path as a file URIs.
- References CSS files are supported, I found it easier to write inline CSS (classes in the same document enclosed in a style tag)
using Nancy;
using Nancy.Responses;
using Nancy.ViewEngines;
using Pechkin;
using Pechkin.Synchronized;
using System.Drawing.Printing;
using System.IO;
namespace Nancy.MVC
{
public static class ResponseAsPDF
{
public static Response RenderToPdfPechkin(NancyModule module, string viewName, dynamic model)
{
string content = GetPageContent(module, viewName, model);
SynchronizedPechkin sc = new SynchronizedPechkin(new GlobalConfig().SetMargins(new Margins(0, 0, 0, 0))
.SetDocumentTitle("Ololo").SetCopyCount(1).SetImageQuality(100)
.SetLosslessCompression(true).SetMaxImageDpi(-1).SetOutlineGeneration(true).SetOutputDpi(-1).SetPaperOrientation(true)
.SetPaperSize(PaperKind.Letter));
byte[] pdfBuf = sc.Convert(new ObjectConfig().SetLoadImages(true)
.SetPrintBackground(true)
.SetAllowLocalContent(true)
.SetScreenMediaType(true)
.SetRunJavascript(true)
.SetCreateExternalLinks(true), content);
return new StreamResponse(() =>
{
var pdfOutput = new MemoryStream(pdfBuf);
pdfOutput.Seek(0, SeekOrigin.Begin);
return pdfOutput;
}, "application/pdf");
}
private static string GetPageContent(NancyModule module, string viewName, dynamic model)
{
ViewLocationContext viewLocationContext = new ViewLocationContext()
{
Context = module.Context,
ModuleName = module.GetType().Name,
ModulePath = module.ModulePath
};
var rendered = module.ViewFactory.RenderView(viewName, model, viewLocationContext);
var content = "";
using (var ms = new MemoryStream())
{
rendered.Contents.Invoke(ms);
ms.Seek(0, SeekOrigin.Begin);
using (TextReader reader = new StreamReader(ms))
{
content = reader.ReadToEnd();
}
};
return content;
}
}
}
Brak komentarzy:
Prześlij komentarz