Skip to content Skip to footer

JavaScript and the Art of Printing PDFs

Ah, the digital age: where documents fly across the globe in seconds and ink and paper seem quaint. But sometimes, we gotta kick it old-school and print out a PDF from our web apps. As a full-stack dev who’s seen a fair share of print buttons, I’m gonna walk you through the ins and outs of printing PDFs with JavaScript. Whether you’re generating reports, invoices, or just want to offer a download for that super helpful user manual, I’ve got the code snippets to get you started.

Client-Side Printing with JavaScript

Let’s start with the basics. You’ve got a PDF URL and you want to pop open the print dialog in the user’s browser. Good news, it’s pretty straightforward:

function printPDF(url) {
  // This opens a new window with the PDF file
  const win = window.open(url, '_blank');
  win.focus();

  // Wait for the PDF to load and then print it
  win.onload = function() {
    win.print();
  };
}

This little snippet does the trick for most cases. But what if you’re dealing with more complex scenarios or want a more seamless experience? Buckle up, we’re going deeper.

Printing PDFs with PDF.js

When you need more control over how PDFs are handled in the browser, PDF.js is your go-to library. It’s a general-purpose, web standards-based platform for parsing and rendering PDFs, and it’s what powers the PDF viewer in Firefox.

Here’s how to use PDF.js to print a PDF:

import { getDocument } from 'pdfjs-dist/webpack';

function printPDFWithPDFjs(url) {
  const loadingTask = getDocument(url);

  loadingTask.promise.then(pdfDocument => {
    // Fetch the first page
    pdfDocument.getPage(1).then(page => {
      // You'll need to create a canvas element
      var viewport = page.getViewport({ scale: 1.0 });
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext('2d');
      canvas.height = viewport.height;
      canvas.width = viewport.width;

      // Render the page on the canvas
      var renderContext = {
        canvasContext: ctx,
        viewport: viewport,
      };
      page.render(renderContext).promise.then(() => {
        // Convert canvas to an image blob
        canvas.toBlob(blob => {
          // Create a new object URL for the blob
          var newUrl = URL.createObjectURL(blob);

          // Use the previous technique to print the blob
          const win = window.open(newUrl, '_blank');
          win.onload = function() {
            win.print();
          };
        });
      });
    });
  }).catch(function(reason) {
    console.error('Error: ' + reason);
  });
}

With PDF.js, you’re no longer limited to just printing the first page or relying on the browser’s built-in viewer. You can render individual pages to canvas elements, manipulate them, and then trigger the print dialog.

Generating and Printing PDFs with jsPDF

Sometimes, you need to generate a PDF on the fly and then print it. That’s where jsPDF comes into play. It’s a library that allows you to create PDF documents using JavaScript.

Here’s a quick example of generating a simple PDF and then printing it:

import { jsPDF } from "jspdf";

function generateAndPrintPDF() {
  // Create a new instance of jsPDF
  const doc = new jsPDF();

  // Add some content
  doc.text("Hello world!", 10, 10);

  // Output the PDF as a data URI
  const dataUri = doc.output('datauristring');

  // Open the data URI in a new window
  var win = window.open();
  win.document.write('<iframe src="' + dataUri + '" frameborder="0" style="width:100%;height:100%;"></iframe>');

  // Wait for the iframe to load and then print it
  const iframe = win.document.querySelector('iframe');
  iframe.onload = function() {
    win.focus();
    win.print();
  };
}

With jsPDF, you’re in complete control of the PDF generation. You can add text, images, shapes, and more. Then, you can either offer it as a downloadable file or print it directly from the browser.

That wraps up the first half of our journey into printing PDFs with JavaScript. We’ve covered client-side printing, using PDF.js for more control, and generating PDFs on the fly with jsPDF. Stay tuned for the second half, where we’ll dive into server-side PDF generation and more advanced client-side options. Happy printing!

Server-Side PDF Generation with Node.js

While client-side PDF generation is great for many applications, sometimes you need the power and control of server-side processing. Whether it’s for performance, privacy, or just because the client’s device isn’t up to the task, Node.js has got you covered.

Generating PDFs with Puppeteer

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It’s perfect for generating PDFs of content that’s rendered in the browser.

Here’s how to use Puppeteer to generate a PDF on the server:

const puppeteer = require('puppeteer');

async function printPDF(url) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto(url, { waitUntil: 'networkidle0' });
  const pdf = await page.pdf({ format: 'A4' });

  await browser.close();
  return pdf;
}

// Usage:
printPDF('http://example.com').then(pdf => {
  // Here you can write the PDF to a file, send it over the network, etc.
});

With Puppeteer, you can take a URL (either public or within your private network), render the page in a headless browser, and then output a PDF. It’s like having a print-to-PDF feature on the server.

Creating PDFs with pdfkit

Another great option for server-side PDF generation is pdfkit, a PDF generation library for Node that makes creating complex, multi-page, printable documents easy.

Here’s a basic example of generating a PDF with pdfkit:

const PDFDocument = require('pdfkit');
const fs = require('fs');

function createPDF() {
  // Create a document
  const doc = new PDFDocument();

  // Pipe its output somewhere, like to a file or HTTP response
  // See below for browser usage
  doc.pipe(fs.createWriteStream('output.pdf'));

  // Embed a font, set the font size, and render some text
  doc
    .font('fonts/PalatinoBold.ttf')
    .fontSize(25)
    .text('Some text with an embedded font!', 100, 100);

  // Add another page
  doc.addPage()
     .fontSize(25)
     .text('Here is some vector graphics...', 100, 100);

  // Draw a triangle
  doc.save()
     .moveTo(100, 150)
     .lineTo(100, 250)
     .lineTo(200, 250)
     .fill("#FF3300");

  // Finalize PDF file
  doc.end();
}

createPDF();

In this example, pdfkit is used to create a PDF with text and graphics. The output can be piped to a file, HTTP response, or any writable stream.

Advanced Client-Side Printing Techniques

Sometimes, you need a bit more than just printing a PDF. Maybe you want to print directly from the client-side without user interaction, or you need to print part of a page or a dynamically generated document.

Silent Printing with qz-tray

For silent, client-side printing, you can use qz-tray, a cross-browser, cross-platform plugin for sending documents and raw commands to a printer.

const qz = require('qz-tray');

// Connect to the qz-tray service
qz.websocket.connect().then(() => {
  return qz.printers.find(); // Pass the printer name
}).then(printer => {
  var config = qz.configs.create(printer);

  // Create a PDF blob
  var pdfBlob = new Blob([/* PDF data as array goes here */], { type: 'application/pdf' });

  // Send PDF to the printer
  return qz.print(config, [{ type: 'pdf', data: pdfBlob }]);
}).catch(e => {
  console.error(e);
});

Using qz-tray, you can bypass the standard print dialog and directly interface with the user’s printer. This is particularly useful for kiosk or POS applications where silent printing is essential.

Printing Part of a Web Page

Sometimes, you don’t want to print a whole PDF or even a whole web page — just part of it. Here’s how you can do that with plain JavaScript:

function printElement(elem) {
  const printWindow = window.open('', 'PRINT', 'height=600,width=800');

  printWindow.document.write('<html><head><title>' + document.title + '</title>');
  printWindow.document.write('</head><body>');
  printWindow.document.write(elem.outerHTML);
  printWindow.document.write('</body></html>');

  printWindow.document.close(); // necessary for IE >= 10
  printWindow.focus(); // necessary for IE >= 10

  printWindow.print();
  printWindow.close();
}

// Usage:
printElement(document.getElementById('printableArea'));

This function opens a new window, writes the HTML of the element you want to print to the new window, and triggers the print dialog.

And there you have it, folks — a deep dive into printing PDFs with JavaScript, from client-side quick prints to server-side PDF generation, and even silent printing and partial page printing. Whether you’re building a simple web app or a complex enterprise system, these tools and techniques should cover all your printable document needs. Keep in mind that printing can be a complex topic due to the variety of user environments and browsers, but with the right approach, you can create a smooth and user-friendly print experience. Happy coding and happy printing!