Converting a Visualforce Page into a PDF

July 20, 2017 Appirio

By Kamal Sharma

Businesses often need webpage data to be converted into a PDF so they can see a snapshot of business critical pages. If you need to display a Visualforce page as a PDF, just put “Render As” equal to PDF, and it works.
If you want to send a Visualforce page as a PDF attachment, the same will work with four to five lines of code in the controller. This is because anything rendered through JavaScript won’t display on the PDF page. In reality, the Visualforce page to PDF conversion happens on the server side, and the stuff which is supposed to render on the client side will not appear in the converted PDF. If we want to convert only the chart, then we have a solution, we can use Google Chart. But keep in mind that these charts are deprecated ones. The latest Google Chart will be rendered at client side.
A no-excuse solution helps to resolve not only this PDF rendering issue but also lots of print-related issues too. What happens if we take a screenshot of the page and render that screenshot image as a PDF? This way, the PDF will have the same look and content as it shows on the screen to the end user.
There are numerous available JavaScript libraries that can convert a page into an image, and an image into a PDF. Once you have access to this, your implementation of the solution can vary as per the exact requirement.
I have put a sample working process here as an example — you can enhance or modify it based on your requirements:

Visualforce Page:

<apex:page docType="html-5.0" controller="SEM_BlogController" showHeader="false" sidebar="false" standardStylesheets="false">



       <!-- Libraries to take screenshot and image to pdf conversion-->

       <script src=""></script>

       <script src=""></script>

       <script src=""></script>

       <script src=""></script>

       <script src=""></script>

       <!-- Code to take screenshot and image to pdf conversion-->


           function render(targetElem) {

               var nodesToRecover = []

               var nodesToRemove = []

               var svgs = $(targetElem).find('svg');

               svgs.each(function(index, node) {

                   var parentNode = node.parentNode

                   var svg = parentNode.innerHTML

                   var canvas = document.createElement('canvas')

                   xml = (new XMLSerializer()).serializeToString(node)

                   xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '')

                   canvg(canvas, xml); // html to image


                       parent: parentNode,

                       child: node




                       parent: parentNode,

                       child: canvas





               html2canvas(targetElem, {

                   onrendered: function(canvas) {

              = 'hidden'



                       var doc = new jsPDF('p', 'pt', [canvas.height,canvas.width]); // create pdf file

                       doc.addHTML(canvas, {}, function() { // add image to pdf file










       <apex:form >

           <apex:actionFunction action="{!sendEmail}" name="sendEmail" rerender="" status="counterStatus" >

               <apex:param name="pdfContent" assignTo="{!pdfContent}" value="" />



           <div class="buttonAndMessageContainer">

               <apex:actionStatus startText="Sending Email...."

                                  stopText="Email Sent Successfully!" startStyle="display:block;" stopStyle="display:none;" id="counterStatus"/>


               <div class="buttonContainer" >

                   <apex:commandButton reRender="messageForSendMail" value="Send Result as Email Attachment" onclick="render(document.getElementById('resultForPdf'))"></apex:commandButton>




           <div id="resultForPdf">

               <apex:repeat value="{!questionMap}" var="question">


                       <span id="{!question}"></span>



                   <apex:chart renderTo="{!question}" data="{!questionMap[question].chartData}" height="300" width="300" background="#F5F5F5">

                       <apex:legend position="bottom"/>

                       <apex:pieSeries labelField="name" dataField="data" donut="50">

                           <apex:chartLabel display="none" orientation="vertical"

                                            font="bold 18px Helvetica"/>









public class SEM_BlogController {

   public Map<String,Question> questionMap {get;set;}

   public String message {get;set;}

   private String emailId;



   public SEM_BlogController(){

       questionMap = new Map<String,Question>();

       emailId = '';



   public void populateChartData() {

       Question que;

       List<chartDataWrapper> data;

       chartDataWrapper chartData;

       for(Integer i = 0 ; i < 5 ; i++){

           data = new List<chartDataWrapper>();

           for(Integer j = 0 ; j < 3 ; j++){

               chartData = new chartDataWrapper('ans' + j,  j + 8);



           que = new Question();

           que.question = 'Demo Question ' + i + '?';

           que.chartData = data;





    public void sendEmail(){


       String body = Apexpages.currentPage().getParameters().get('pdfContent');

       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

       String[] toAddresses = new String[]{emailId};



           mail.setSubject('Demo PDF');

           mail.setPlainTextBody('Hi, PFB the sample PDF file.');



           mail.saveAsActivity = false;

           body = body.replace('', '');

           // Add to attachment file list

           List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>();

           Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();





           //Send email


           Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

           message = 'Email has been send successfully!';



// Wrapper class

   public class chartDataWrapper {


       public String name { get; set; }

       public Integer data { get; set; }


       public chartDataWrapper(String name, Integer data) {

  = name;

  = data;



   public class Question{

       public String question {get;set;}

       public List<chartDataWrapper> chartData {get;set;}



You may have excuses, but you have a way as well to find out the solution.

Previous Article
Salesforce and Acquia Drupal Integrate
Salesforce and Acquia Drupal Integrate

By Pankaj Mehra Drupal is a free CMS platform. Acquia is a company which provides a mix of Drupal services....

Next Article
Enhancing the Meeting Experience with Jamboard
Enhancing the Meeting Experience with Jamboard

By Cynthia Lipkovitch As an Appirian, I can always count on experiencing the newest and most innovative pro...