PDFs im Browser erstellen, bearbeiten und anzeigen

PDF-Urkunde der Fat Valley University

Unsere Demo generiert ein PDF-Dokument im Browser. Es werden keine Daten an den Server gesendet.

Bei jeder Änderung des Textes oder durch Hinzufügen eines Bildes wird das PDF in ein canvas-Element gerendert und angezeigt. In einer echten Anwendung würden wir die Vorschau natürlich anders lösen und das PDF erst ganz am Ende erzeugen.

Wir möchten hier folgende Projekte vorstellen:

Da bei unseren Beispielen Dateien per fetch nachgeladen werden, müssen die Scripts in einem (lokalen) Webserver ausgeführt werden. Man kann dazu z.B. die Visual Studio Code Erweiterung Live-Server verwenden.

PDF-LIB

PDF-LIB ist eine JavaScript-Bibliothek für die Erstellung und Bearbeitung von PDF-Dokumenten in Browsern oder Node.js. Die umfangreiche API ermöglicht es, Texte, Bilder, Formulare und andere Inhalte hinzuzufügen oder zu entfernen. Außerdem können mit PDF-LIB mehrere PDF-Dateien zu einer einzigen Datei kombiniert werden.

In diesem Beispiel laden wir eine bestehende PDF-Datei und ergänzen sie mit Text und Bild.

async function addTextAndImageToPdf() {

  // Laden des PDF-Dokuments
  const existingPdfBytes = await fetch('./bestehendes_dokument.pdf').then(res => res.arrayBuffer());

  const pdfDoc = await PDFDocument.load(existingPdfBytes);

  // page = Die erste Seite des geladenen PDF's
  const page = pdfDoc.getPages()[0];

  // Hinzufügen von Text
  page.drawText('Hallo Welt!', { x: 10, y: 570, size: 20 });

  // Hinzufügen eines Bildes
  const imageBytes = await fetch('./monkey.jpg').then(res => res.arrayBuffer());
  const image = await pdfDoc.embedJpg(imageBytes);

  page.drawImage(image, { x: 10, y: 330, width: image.width / 2, height: image.height / 2, });

  // Uint8Array
  const pdfBytes = await pdfDoc.save();

  // Speichern des geänderten PDF-Dokuments
  const blob = new Blob([pdfBytes], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'pdf-mit-Makakenselfie.pdf';
  link.click();
}

addTextAndImageToPdf();

Diese Demo zeigt den obigen Code in einer Webseite. Nach dem Generieren wird die PDF-Datei heruntergeladen.

pdf.js

Mozilla entwickelt und betreut die JavaScript-Bibliothek pdf.js, um PDF-Dokumente direkt im Webbrowser anzeigen zu können. Die Rendering-Engine wird von Firefox standardmäßig genutzt, um PDFs ohne zusätzliche Plugins darzustellen - ist jedoch nicht auf diesen Browser beschränkt. pdf.js rendert PDFs in ein Canvas-Element.

Anstatt das PDF herunterzuladen, übergeben wir jetzt den von der PDF-Lib erzeugten Uint8Array an folgende Funktion:

async function renderPdf(pdfBytes) {

  // Das Canvas-Elements aus dem DOM
  const canvas = document.querySelector('canvas');

  // Task zum Laden des PDF-Dokuments aus dem übergebenen Uint8Array
  const loadingTask = pdfjsLib.getDocument(pdfBytes);

  // Warten auf das Laden des Dokuments und Zuweisen des Ergebnisses zur Variable 'pdf'
  const pdf = await loadingTask.promise;

  // Laden der ersten Seite des PDF-Dokuments
  const page = await pdf.getPage(1);

  // Erzeugen eines Viewports für die Seite mit einer Skalierung von 1
  const viewport = page.getViewport({ scale: 1 });

  // Setzen von Höhe und Breite des canvas-Elements entsprechend dem Viewport
  canvas.height = viewport.height;
  canvas.width = viewport.width;

  // Erzeugen eines Tasks zum Rendern der Seite auf dem Canvas
  const renderTask = page.render({
    canvasContext: canvas.getContext('2d'),
    viewport: viewport
  });

  // Warten auf das Rendern der Seite
  await renderTask.promise;
}

Siehe Demo. Jetzt sollte pdf.js unser PDF in das canvas-Element rendern. Wichtig ist, den Worker einzubinden (siehe Quelltext).

Abschließend erweitern wir unsere Seite um einen Button und diese Download-Funktion:

function downloadPdf() {

  // Ein Blob repräsentiert einen Binärdatenblock und kann für den Download verwendet werden.
  const blob = new Blob([pdfBytes], { type: 'application/pdf' });

  // Generiere eine temporäre Object URL, die auf den Blob verweist.
  const url = URL.createObjectURL(blob);

  // Erstelle ein neues HTML 'a' Element (Link) zur Auslösung des Downloads.
  const link = document.createElement('a');

  // Setze den URL-Verweis des Links auf die erstellten Object URL, damit sie auf den Blob zeigt.
  link.href = url;

  // Definiert den Dateinamen, der beim Download verwendet werden soll.
  link.download = 'pdf-mit-Makakenselfie.pdf';

  // Programmgesteuertes Klicken des Links löst den Download aus.
  // Da der Link nicht im DOM eingefügt wird, geschieht der Download ohne sichtbare UI-Interaktion.
  link.click();

  // Verwerfe die Object URL nach Gebrauch, um Speicher freizugeben.
  URL.revokeObjectURL(url);
}

Die fertige Demo.

So! Jetzt ist es an der Zeit, die hart verdiente Urkunde der "Fat-Valley-University" auszudrucken und im goldenen Rahmen über den Kamin zu hängen 🙂 !