Mastodon hachyterm.io

As software developers, we often come across situations where we need to provide users with the option to download HTML content as a PDF document. This capability can be especially valuable when we want to enable users to save web pages, reports, or other dynamically generated content for offline use or easy sharing. In this article, we will explore how to accomplish this using jsPDF, a widely used JavaScript library for generating PDF files, along with SVG.

Example in Angular

Let’s consider a practical code example in Angular that demonstrates how to download an HTML element as a PDF with the help of jsPDF and svg rendering.

However, the code can be used in other web frameworks like React.js, Svelte or vanilla JavaScript.

import { elementToSVG } from 'dom-to-svg'
import { Canvg } from 'canvg'
import { jsPDF } from 'jspdf'

// Angular component code
@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  styles: [
    `
      .save-as-pdf {
        margin: 0;
        padding: 0;
        background-color: lightblue;
      }
    `,
  ],
  template: `
    <button (click)="onSaveAsPdf()">Save as PDF</button>
    <div class="save-as-pdf">
      <h1>Hello from {{ name }}!</h1>
      <a target="_blank" href="https://angular.io/start">
        <p>Learn more about Angular</p>
      </a>
      <p>Save HTML with jsPDF</p>
    </div>
  `,
})
export class App {
  name = 'Angular'

  async onSaveAsPdf() {
    // Find the HTML element to convert to PDF
    const element = <HTMLElement>document.querySelector('.save-as-pdf')

    const width = element.clientWidth
    const height = element.clientHeight

    // Create SVG
    const svgDoc = elementToSVG(element)
    const svgString = new XMLSerializer().serializeToString(svgDoc)

    // Create a canvas
    const canvas = document.createElement('canvas')
    canvas.height = height
    canvas.width = width
    const ctx = canvas.getContext('2d')

    if (!ctx) {
      throw new Error('Error creating the HTML canvas with 2D context')
    }

    // Render the SVG onto the canvas
    const canvg = await Canvg.from(ctx, svgString)
    await canvg.render()

    // Determine PDF orientation and create a PDF document
    const isLandscape = width > height
    const orientation = isLandscape ? 'landscape' : 'portrait'
    const doc = new jsPDF(orientation, 'px', [width, height])

    // Add the rendered canvas as a JPEG image to the PDF and save
    doc.addImage(canvas, 'JPEG', 0, 0, width, height)
    doc.save('Hello from Angular.pdf')
  }
}

To begin, we have an Angular component that includes a button labeled “Save as PDF” and an HTML element designated with the CSS class .save-as-pdf. When users click the button, it triggers the onSaveAsPdf() method.

Inside the onSaveAsPdf() method, the following steps are performed to download the HTML element as a PDF:

  1. The HTML element is identified using document.querySelector('.save-as-pdf'). This allows us to target the specific element we want to convert to a PDF.

  2. We calculate the width and height of the element to determine the dimensions of the canvas and the resulting PDF.

  3. The HTML element is transformed into an SVG document using the elementToSVG() function. This step is essential.

  4. The SVG document is serialized into a string using XMLSerializer(). This conversion prepares the SVG for rendering onto a canvas.

  5. We create a canvas element with the calculated dimensions and obtain its 2D context. The canvas will serve as the rendering surface for the SVG.

  6. Using the Canvg library, we render the SVG onto the canvas. This process ensures that the visual representation of the HTML element is accurately captured.

  7. Based on the dimensions of the element, we determine the orientation of the resulting PDF (landscape or portrait). Then, using jsPDF, we create a new PDF document with the appropriate orientation.

  8. The rendered canvas is added to the PDF as a JPEG image using the doc.addImage() method. This step embeds the visual representation of the HTML element into the PDF.

  9. Finally, we save the PDF with a specified filename using the doc.save() method.

Summary

You have seen a practical approach to enable users to download HTML content as a PDF document using jsPDF in conjunction with SVG rendering. The provided code example in Angular illustrates the step-by-step process of converting an HTML element into a PDF.

By following the outlined steps, you can easily capture and save dynamic web content.

Thanks go to Manuel Navarro for the original implementation using similar libraries.

If you want to see a live example of the article, you can check this Stackblitz.