Wednesday, January 9, 2019

How to convert html to pdf using Puppetter from dotnet Core


Puppetter is a nodejs library developed by google which calls chromium on the background to do certain tasks. One of this tasks can be convert an html document/url into a pdf.
Since we want to use this feature from dotnet core C# there are a few steps that we must follow.

First we need the nutget package for NodeServices
Install-Package Microsoft.AspNetCore.NodeServices

Then we need to enable this NodeServices on our Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
//Register NodeService
services.AddNodeServices();// this is in package Microsoft.AspNetCore.NodeServices
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
view raw Startup.cs hosted with ❤ by GitHub

Install required node packages

npm init
npm install puppetter
npm install fs-extra
npm install uuid

Create a puppetter.js file on your solution with this contents.
module.exports = async function (callback, html, headerTemplate, footerTemplate ) {
try {
var puppeteer = require('puppeteer');
var fs = require('fs-extra');
const uuidv4 = require('uuid/v4');
var browser = await puppeteer.launch();
var page = await browser.newPage();
await page.setContent(html);
await page.emulateMedia('screen');
var outFileName = uuidv4() + "-pdf.tmp";
await page.pdf({
path: outFileName,
format: 'A4',
printBackground: true,
displayHeaderFooter: true,
headerTemplate: headerTemplate,
footerTemplate: footerTemplate,
margin: { top: "40", bottom: "40" }
}).then(function (resp) {
var pdf = fs.readFileSync(outFileName);
var array = new Uint8Array(pdf);
//Clean file
fs.remove(outFileName);
callback(null, [].slice.call(array));
});
await browser.close();
process.exit();
callback(null, new Uint8Array(pdf));
} catch (e) {
callback(e, null);
}
};
view raw puppetter.js hosted with ❤ by GitHub
Now everything is set, only step required is to call the module from C#.
[HttpGet]
public async Task<ActionResult> Pdf([FromServices] INodeServices nodeServices)
{
HttpClient hc = new HttpClient();
var htmlContent = "<h1>Super testing</h1>";
var headerTemplate = "<div></div>";
var footerTemplate= "<div class='footer' style='width: 100%; font-size:12px; text-align:right; color:white; background:black; -webkit-print-color-adjust:exact'><span class='pageNumber'></span>/<span class='totalPages'></span></div>";
var result = await nodeServices.InvokeAsync<byte[]>("./puppetter", htmlContent, headerTemplate, footerTemplate );
HttpContext.Response.ContentType = "application/pdf";
HttpContext.Response.Headers.Add("x-filename", "report.pdf");
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
HttpContext.Response.Body.Write(result, 0, result.Length);
return new ContentResult();
}
view raw controller.cs hosted with ❤ by GitHub