Hello folks, today we’re going to check how to convert HTML to PDF content in Node.js and also few deployment tips to get it done right.

I planned to describe the conversion through Node API service using html-pdf. This npm package depending on phantomjs. I am using it to allow more options like paper size, header & footer, border type of styles into the pdf phantom JS helping internally.

Installing NPM Dependencies And Packages

To install the npm packages, use the below command. I’m giving an example with dynamic content which will help us in real-time. To give an example of PDF conversion, I’m just going with one sample certificate template and this template allows dynamic content.

Filename: certificate.ejs

<!DOCTYPE html> <html> <head> <style> .outer-border { width: 715px; height: 535px; padding: 20px; text-align: center; border: 10px solid #787878; } .inner-border { width: 665px; height: 485px; padding: 20px; text-align: center; border: 5px solid #787878; } .title { font-size: 25pt; font-weight: bold; } .fs30 { font-size: 15pt; } .fs25 { font-size: 12pt; } .fs20 { font-size: 10pt; } </style> </head> <body> <div class="outer-border"> <div class="inner-border"> <span class="title">Certificate of Completion</span> <br/><br/> <span class="fs25"><i>This is to certify that</i></span> <br/><br/> <span class="fs30"><b><%= student.name %></b></span><br/><br/> <span class="fs25"><i>has completed the course</i></span> <br/><br/> <span class="fs30"><%= student.couse_name %></span> <br/><br/> <span class="fs20">with score of <b><%= student.grade %>%</b></span> <br/><br/><br/><br/> <span class="fs25"><i>dated</i></span><br/> <span class="fs30"><%= student.completion_date %></span> </div> </div> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 < ! DOCTYPE html > < html > < head > <style> .outer-border { width : 715px ; height : 535px ; padding : 20px ; text-align : center ; border : 10px solid #787878 ; } .inner-border { width : 665px ; height : 485px ; padding : 20px ; text-align : center ; border : 5px solid #787878 ; } .title { font-size : 25pt ; font-weight : bold ; } .fs30 { font-size : 15pt ; } .fs25 { font-size : 12pt ; } .fs20 { font-size : 10pt ; } </style> < / head > < body > < div class = "outer-border" > < div class = "inner-border" > < span class = "title" > Certificate of Completion < / span > < br / > < br / > < span class = "fs25" > < i > This is to certify that < / i > < / span > < br / > < br / > < span class = "fs30" > < b > <%= student . name %> < / b > < / span > < br / > < br / > < span class = "fs25" > < i > has completed the course < / i > < / span > < br / > < br / > < span class = "fs30" > <%= student . couse_name %> < / span > < br / > < br / > < span class = "fs20" > with score of < b > <%= student . grade %> % < / b > < / span > < br / > < br / > < br / > < br / > < span class = "fs25" > < i > dated < / i > < / span > < br / > < span class = "fs30" > <%= student . completion_date %> < / span > < / div > < / div > < / body > < / html >

NOTE: To avoid font size issues while generating PDF, go with pt(point) size format instead of px(pixel).

Read A File In Node.js Using Node FS

Using fs npm package, you can read the content from the ejs file. Here it is.

// read html content fs.readFile('certificate.ejs', 'utf8', function (err, content) { if (err) { return res.status(400).send({error: err}); } console.log(content); } 1 2 3 4 5 6 7 // read html content fs . readFile ( 'certificate.ejs' , 'utf8' , function ( err , content ) { if ( err ) { return res . status ( 400 ) . send ( { error : err } ) ; } console . log ( content ) ; }

Display Dynamic Content On HTML Page Using Node ejs

In real time, mostly we cannot maintain the static templates. Using ejs npm package we can update the part of HTML content or we can bind the dynamic values into the existing content.

// update the html content with required fields content = ejs.render(content, { student: { "name": "Reddy Sai", "couse_name": "Software Engineering Training", "grade": "55.7", "completion_date": "22-Feb-2019" } }); 1 2 3 4 5 6 7 8 9 // update the html content with required fields content = ejs . render ( content , { student : { "name" : "Reddy Sai" , "couse_name" : "Software Engineering Training" , "grade" : "55.7" , "completion_date" : "22-Feb-2019" } } ) ;

Convert HTML To PDF Using Node.js

Now we have updated HTML content with dynamic values, with this content we can able to generate the pdf using the html-pdf npm package.

pdf.create(content, {format: 'Letter', orientation: 'landscape'}).toStream(function(err, stream){ stream.pipe(fs.createWriteStream('certificate.pdf')); }); 1 2 3 pdf . create ( content , { format : 'Letter' , orientation : 'landscape' } ) . toStream ( function ( err , stream ) { stream . pipe ( fs . createWriteStream ( 'certificate.pdf' ) ) ; } ) ;

Using certificate.ejs file, here we are generating the PDF with a complete example. Use the below source to do that.

{ "name": "Reddy Sai", "couse_name": "Software Engineering Training", "grade": "55.7", "completion_date": "22-Feb-2019" } 1 2 3 4 5 6 { "name" : "Reddy Sai" , "couse_name" : "Software Engineering Training" , "grade" : "55.7" , "completion_date" : "22-Feb-2019" }

From this example, the generated PDF will respond in fly mode.

To test this endpoint, we have to pass the request body content like,

{ "name": "Reddy Sai", "couse_name": "Software Engineering Training", "grade": "55.7", "completion_date": "22-Feb-2019" } 1 2 3 4 5 6 { "name" : "Reddy Sai" , "couse_name" : "Software Engineering Training" , "grade" : "55.7" , "completion_date" : "22-Feb-2019" }

I used a postman to test this endpoint.

Here is the result.

Install Custom Fonts In Ubuntu

By chance, If you have used custom fonts to generate PDF, then those fonts won’t render properly in server-side. To avoid this problem, you must install the custom fonts locally on production machine(server) or copy the font files into the /usr/share/fonts/ and /usr/local/share/fonts/ directories.

When the pdf is generated on the server then you may notice that the spacing between letter will get vary, to overcome this problem, you have to override this file /etc/fonts/conf.d/51-local.conf in your production machine with below content.

<?xml version='1.0'?> <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'> <fontconfig> <match target="font"> <edit mode="assign" name="rgba"> <const>rgb</const> </edit> </match> <match target="font"> <edit mode="assign" name="hinting"> <bool>true</bool> </edit> </match> <match target="font"> <edit mode="assign" name="hintstyle"> <const>hintslight</const> </edit> </match> <match target="font"> <edit mode="assign" name="antialias"> <bool>true</bool> </edit> </match> <match target="font"> <edit mode="assign" name="lcdfilter"> <const>lcddefault</const> </edit> </match> </fontconfig> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <? xml version = '1.0' ?> < ! DOCTYPE fontconfig SYSTEM 'fonts.dtd' > < fontconfig > < match target = "font" > < edit mode = "assign" name = "rgba" > < const > rgb < / const > < / edit > < / match > < match target = "font" > < edit mode = "assign" name = "hinting" > < bool > true < / bool > < / edit > < / match > < match target = "font" > < edit mode = "assign" name = "hintstyle" > < const > hintslight < / const > < / edit > < / match > < match target = "font" > < edit mode = "assign" name = "antialias" > < bool > true < / bool > < / edit > < / match > < match target = "font" > < edit mode = "assign" name = "lcdfilter" > < const > lcddefault < / const > < / edit > < / match > < / fontconfig >

Similarly, you can follow this below link if you want to install the custom font in Windows.

https://support.microsoft.com/en-in/help/314960/how-to-install-or-remove-a-font-in-windows

Hope this will help you to work as you expected from production with any font relevant issues.