13

For a project I'm working on I need to be able to generate a PDF of the page the user is currently on, for which I'll use jspdf. Since I have a HTML I need to generate a PDF with, I'll need the addHTML() function. There are a lot of topic about this, saying

You'll either need to use html2canvas or rasterizehtml.

I've chosen to use html2canvas. This is what my code looks like at the moment:

import { Injectable, ElementRef, ViewChild } from '@angular/core';
import * as jsPDF from 'jspdf';
import * as d3 from 'd3';
import * as html2canvas from 'html2canvas';

@Injectable ()
export class pdfGeneratorService {

  @ViewChild('to-pdf') element: ElementRef;

  GeneratePDF () {
    html2canvas(this.element.nativeElement, <Html2Canvas.Html2CanvasOptions>{
      onrendered: function(canvas: HTMLCanvasElement) {
        var pdf = new jsPDF('p','pt','a4');

        pdf.addHTML(canvas, function() {
          pdf.save('web.pdf');
        });
      }
    });
  }
}

When this function is called, I get a console error:

EXCEPTION: Error in ./AppComponent class AppComponent - inline template:3:4 caused by: You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js

Why exactly is this? I give a canvas as parameter and it still says I need to use html2canvas.

FlorisdG
  • 754
  • 5
  • 11
  • 31

6 Answers6

22

What I found worked was adding:

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script>

to the index.html file (it could presumably be elsewhere).

I then used:

const elementToPrint = document.getElementById('foo'); //The html element to become a pdf
const pdf = new jsPDF('p', 'pt', 'a4');
pdf.addHTML(elementToPrint, () => {
    doc.save('web.pdf');
});

Which no longer uses html2canvas in the code.
You can then remove the following import:

import * as html2canvas from 'html2canvas';
Greg
  • 441
  • 3
  • 7
  • 1
    Would be nice if the import statement worked. But This should be selected as the answer for now. – Tim Schimandle Apr 19 '17 at 22:15
  • @Greg without importing the script in index.html. Can we able to do load html2canvas.js – Vignesh Nov 14 '17 at 06:30
  • 5
    where are you using html2canvas in your code apart from importing? I'm getting error You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js Error: You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js at Object.e.API.addHTML – Pratap A.K Nov 21 '17 at 08:06
  • Thanks, this solution worked for me in an Angular 5 project! Adding the script in index.html is crucial, if you only add it in angular.cli.json, it will not work somehow. The scipt needs to be in index.html.This is the newest version right now: 0.5.0-beta4 – balazs630 Jan 12 '18 at 10:40
  • I tried your suggestion it worked fine after updating the packages to latest version >"html2canvas:1.0.0-alpha.9", "jspdf": "^1.3.5", "jquery": "^3.3.1". Generating of pdf from HTML using jspdf is not working. – Vignesh Jan 29 '18 at 04:50
  • @Vignesh "npm i html2canvas", and add the file path ("node_modules/html2canvas/dist/html2canvas.js") in your angular.json scripts array. – akcasoy Mar 04 '20 at 14:40
9

In case someone prefer not to use cdn scripts & would like to use a more (angular) way, this worked for me in Angular 6:

Using this way will give you better support & autocomplete in the editor & will help you avoid depending on cdn scripts (if you wanna avoid them, like me)

Based on the excellent answer here & since it was hard for me to find that answer, I am re-sharing what was stated in it & helped me use jsPDF in Angular 6 (all credit goes to the original author of this answer)

You should run these cmds:

npm install jspdf --save

typings install dt~jspdf --global --save

npm install @types/jspdf --save

Add following in angular-cli.json:

"scripts": [ "../node_modules/jspdf/dist/jspdf.min.js" ]

html:

<button (click)="download()">download </button>

component ts:

import { Component, OnInit, Inject } from '@angular/core';
import * as jsPDF from 'jspdf'
@Component({
  ...
  providers: [
    { provide: 'Window',  useValue: window }
  ]
})
export class GenratePdfComponent implements OnInit {

  constructor(
    @Inject('Window') private window: Window,
    ) { }

  download() {

        var doc = new jsPDF();
        doc.text(20, 20, 'Hello world!');
        doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
        doc.addPage();
        doc.text(20, 20, 'Do you like that?');

        // Save the PDF
        doc.save('Test.pdf');
    }
}
Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85
7

Anyone still trying to convert an Html div to a pdf can opt to use html2pdf, with a couple of lines you can do everything with ease.

var element = document.getElementById('element-to-print');
html2pdf(element);
Sadiq Ali
  • 1,272
  • 2
  • 15
  • 22
  • Can you let me know the reason for the down vote? html2pdf uses jspdf internally and it makes things a lot easier. Someone might find it useful as this question is what most people stumble upon. – Sadiq Ali May 01 '18 at 06:13
2

Try it like this:

GeneratePDF () {
    html2canvas(this.element.nativeElement, <Html2Canvas.Html2CanvasOptions>{
      onrendered: function(canvas: HTMLCanvasElement) {
        var pdf = new jsPDF('p','pt','a4');    
        var img = canvas.toDataURL("image/png");
        pdf.addImage(img, 'PNG', 10, 10, 580, 300);
        pdf.save('web.pdf');
      }
    });
  }
ferralucho
  • 637
  • 7
  • 24
1

Use this way stackblitz example

import {jsPDF} from 'jspdf';

@ViewChild('content', {static: false}) content: ElementRef;


public downloadPDF() {
   const doc = new jsPDF();

   const specialElementHandlers = {
      '#editor': function (element, renderer) {
       return true;
       }
   };

   const content = this.content.nativeElement;

   doc.fromHTML(content.innerHTML, 15, 15, {
      width: 190,
     'elementHandlers': specialElementHandlers
   });

   doc.save('fileName.pdf');
}
dasunse
  • 2,839
  • 1
  • 14
  • 32
1

For the newcomers to this question, the hint is that you should pay attention to what version of jspdf you are using:

1.xx:

you need to install html2canvas first

   npm install html2canvas

then add it the scripts section in angular.json

//.angular.json  
 "scripts": [ 
               // make sure you have the correct path 
               "node_modules/html2canvas/dist/html2canvas.min.js"
            ]  
   // let data = this.htmlData.nativeElement; if you use it with @ViewChild('htmlData') 
    htmlData:ElementRef;
    let data = document.body;
    html2canvas(data).then(canvas => {
    // Few necessary setting options
    const imgWidth = 208;
    const pageHeight = 295;
    const imgHeight = canvas.height * imgWidth / canvas.width;
    const heightLeft = imgHeight;

    const contentDataURL = canvas.toDataURL('image/png')
    let pdf = new jspdf('p', 'mm', 'a4'); // A4 size page of PDF
    var position = 0;
    pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight)
    pdf.save('new-file.pdf'); // Generated PDF
    });

2.xx:

there are several breaking changes between 1.xx and 2.xx:

Removed APIs that were previously marked as deprecated. Namely: addHTML, fromHTML, html2pdf, addSvg, addButton, addTextField, addChoiceField, cellInitialize, setFontStyle, setFontType, clip_fixed.

so the previous code becomes:

 // let data = this.htmlData.nativeElement; if you use it with @ViewChild('htmlData') 
 htmlData:ElementRef;
 let data = document.body;
    let options : any = {
      orientation: 'p',
      unit: 'px',
      format: 'a0',
      };
    let doc = new jsPDF(options);
     doc.html(data.innerHTML, {
      callback: function (doc) {
            doc.save("angular-demo.pdf");
          },
      margin:15,
      x: 10,
      y: 10
    });
  }

demo

Note that in version 2.xx you don't need to install html2canvas via npm or even include the script (in angular.json or index.html) since this is done dynamically internally.

Benzara Tahar
  • 2,058
  • 1
  • 17
  • 21