DEV Community 👩‍💻👨‍💻

Cover image for Client side PDF generator
Mallikarjun H T
Mallikarjun H T

Posted on • Updated on

Client side PDF generator

Have you ever wondered how client-side PDFs are produced?
Have you tried a few alternatives and realized that there is nothing substantial you can do? I've also used many libraries in various projects but have yet to find a better option. So, if you ever run into a problem in the future, keep in mind that each solution or package works differently, and you must pick what you require.

In this article, I'll discuss how I used 'html2Canvas and jsPdf,' as well as the challenges I encountered and what I discovered after a lengthy examination, as well as taking a few PDFs and comparing them to various alternatives available online.

My current problem statement begins with one of the environments in which my PDF was producing partial images. After a lot of digging, I assumed it was a issue with package versions, but it didn't work, so if you ever run into this problem, try * a fresh installation of node and/or npm * first.

When your pdf image appears stretched but your UI looks great as intended, you've got a serious problem.
As you might expect, I started by fitting to a specific dimension.

Did it work? No.

Please accept my apologies if I have not answered to you yet. Hold on a little longer, and you'll see what I'm talking about.

In this post, we'll look at how to use Html2Canvas and JsPdf in a React project. There are a few alternative options out there, such as integrating with HTML directly.

Hear are the list of solutions you can try as per your sutiation.

You may have came across the solutions given below, and if they did not work, scroll down to the bottom where I'll explain how you might reach a better, if not precise, result.

1. How to set image to fit to width of the page using jsPDF?

var doc = new jsPDF("p", "mm", "a4");
var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight();
Enter fullscreen mode Exit fullscreen mode

2. get width 100% of PDF file and auto height

html2canvas(input)
      .then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF({
          orientation: 'landscape',
        });
        const imgProps= pdf.getImageProperties(imgData);
        const pdfWidth = pdf.internal.pageSize.getWidth();
        const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
        pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
        pdf.save('download.pdf');
      });
Enter fullscreen mode Exit fullscreen mode

3. fit a web page into the pdf document, without losing the aspect ratio.

var divHeight = $('#div_id').height();
var divWidth = $('#div_id').width();
var ratio = divHeight / divWidth;
html2canvas(document.getElementById("div_id"), {
     height: divHeight,
     width: divWidth,
     onrendered: function(canvas) {
          var image = canvas.toDataURL("image/jpeg");
          var doc = new jsPDF(); // using defaults: orientation=portrait, unit=mm, size=A4
          var width = doc.internal.pageSize.getWidth();    
          var height = doc.internal.pageSize.getHeight();
          height = ratio * width;
          doc.addImage(image, 'JPEG', 0, 0, width-20, height-10);
          doc.save('myPage.pdf'); //Download the rendered PDF.
     }
});
Enter fullscreen mode Exit fullscreen mode

4. dynamic sized image

let width = doc.internal.pageSize.getWidth()
let height = doc.internal.pageSize.getHeight()
let widthRatio = width / canvas.width
let heightRatio = height / canvas.height
let ratio = widthRatio > heightRatio ? heightRatio : widthRatio
doc.addImage(
  canvas.toDataURL('image/jpeg', 1.0),
  'JPEG',
  0,
  0,
  canvas.width * ratio,
  canvas.height * ratio,
)
Enter fullscreen mode Exit fullscreen mode

5. Solution for all screen sizes and dynamic orientation:

 html2canvas(Component).then((canvas) => {
    const componentWidth = Component.offsetWidth
    const componentHeight = Component.offsetHeight

    const orientation = componentWidth >= componentHeight ? 'l' : 'p'

    const imgData = canvas.toDataURL('image/png')
    const pdf = new jsPDF({
    orientation,
    unit: 'px'
  })

    pdf.internal.pageSize.width = componentWidth
    pdf.internal.pageSize.height = componentHeight

    pdf.addImage(imgData, 'PNG', 0, 0, componentWidth, componentHeight)
    pdf.save('download.pdf')
  })
Enter fullscreen mode Exit fullscreen mode

6. doc width/height

var myCanvas = document.getElementById("exportToPDF");

    html2canvas(myCanvas, {
      onrendered: function(canvas) {
        var imgData = canvas.toDataURL(
          'image/jpeg', 1.0);
        //Get the original size of canvas/image
        var img_w = canvas.width;
        var img_h = canvas.height;

        //Convert to mm
        var doc_w = ExportModule.pxTomm(img_w);
        var doc_h = ExportModule.pxTomm(img_h);
        //Set doc size
        var doc = new jsPDF('l', 'mm', [doc_w, doc_h]);

        //set image height similar to doc size
        doc.addImage(imgData, 'JPG', 0, 0, doc_w, doc_h);
        var currentTime = new Date();
        doc.save('Dashboard_' + currentTime + '.pdf');

      }
    });
Enter fullscreen mode Exit fullscreen mode

7. calculate aspect ratio dynamicaly

So, if you've read thus far and still haven't found the best solution, don't despair; there is no better solution. Everyone has a different problem, and we all have different solutions. My solution is as follows:

const domElement = document.getElementById("divToPrint");
    const width = domElement.clientWidth;
    const height = domElement.clientHeight;
Enter fullscreen mode Exit fullscreen mode

will assist in the collection and generation of images specific to the client device, as well as the use of scall to produce a better image

html2canvas(domElement, 
      {
         scale: width / height 
     }).then(function (canvas) {
      const img = canvas.toDataURL("image/png", 2.0);
      const pdf = new jsPdf("l", "mm", [297, 210]);
      pdf.addImage(img, "png", 10, 10, 260, 160, "alias", "FAST"); 
      pdf.save(name);
    });
Enter fullscreen mode Exit fullscreen mode

If you'd like to add more information to the pdf, that's an added benefit. you can use opions as shown below.

pdf.setDisplayMode("fullpage");
      pdf.setProperties({ 
         title: name,  
         subject: "subject"
       });
      pdf.setDisplayMode("fullpage");
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this article we witnessed in this article we looked into how to set a width on an image. We also looked into how we can dynamically set the pdf orientation and a size as well. If you're looking forword to see different options that are available in the jspdf comment below and I'll make an article demonstrating all the options.

resources
JsPdf

Top comments (2)

Collapse
 
mallikarjunht profile image
Mallikarjun H T Author

I have not, will give it a Try once thanks for the suggestion.

Collapse
 
serhii_hrekov profile image
Bro Developer

have you tried pdfmake?

Update Your DEV Experience Level:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. 🛠