Search code examples
google-apps-scriptpdflibrariespdf.jspdf-lib.js

How to use a external Javascript library (PDF lib) in Apps script?


I need to modify a PDF on a Apps script application. To do that I want to use a JS library : PDF-LIB

my code :

eval(UrlFetchApp.fetch("https://unpkg.com/pdf-lib/dist/pdf-lib.js").getContentText());

function modifyPdf() {
  const url = 'https://pdf-lib.js.org/assets/with_update_sections.pdf'
  const existingPdfBytes = UrlFetchApp.fetch(url).getContentText();

  const pdfDoc = PDFDocument.load(existingPdfBytes)
  const helveticaFont = pdfDoc.embedFont(StandardFonts.Helvetica)

  const pages = pdfDoc.getPages()
  const firstPage = pages[0]
  const { width, height } = firstPage.getSize()
  firstPage.drawText('This text was added with JavaScript!', {
    x: 5,
    y: height / 2 + 300,
    size: 50,
    font: helveticaFont,
    color: rgb(0.95, 0.1, 0.1),
    rotate: degrees(-45),
  })

  const pdfBytes = pdfDoc.save()
}

When I execute the function modifyPDF I have :

Error
ReferenceError: PDFDocument is not defined modifyPdf @ modifie_pdf.gs:7

Do you know how I can import the js lib on my Apps script application ?


Solution

    • The evaluated global variable namespace is PDFLib. So, all variables like rgb, degrees, PDFDocument are keys of this object and should be referenced as such.

    • Most functions present in the library use promises, which, although is not supported by apps script functionally, it is supported syntactically. Therefore, async, await should be used, else you'll only get promise objects and not the actual document or font

    • The library uses setTimeout, which is not available in apps script. I used Utilities.sleep to simulate it's behavior.

    • getContentText() returns text and not binary content. Use getContent() to get byte[] instead and cast it to Uint8Array

    eval(UrlFetchApp.fetch("https://unpkg.com/pdf-lib/dist/pdf-lib.js").getContentText());
    /*+++simulate setTimeout*/setTimeout = (func, sleep) => (Utilities.sleep(sleep),func())
    
    async function modifyPdf() {
      const url = 'https://pdf-lib.js.org/assets/with_update_sections.pdf'
      const existingPdfBytes = new /*cast to uint8*/Uint8Array(/*returns byte[]*/UrlFetchApp.fetch(url).getContent/*---Text*/());
      /*+++ simulate import*/const { PDFDocument, StandardFonts, rgb, degrees} = PDFLib;
      const pdfDoc = /*+++*/await PDFDocument.load(existingPdfBytes)
      const helveticaFont = /*+++*/ await pdfDoc.embedFont(StandardFonts.Helvetica)
    
      const pages = pdfDoc.getPages()
      const firstPage = pages[0]
      const { width, height } = firstPage.getSize()
      firstPage.drawText(`This text was added with JavaScript\n\n${' '.repeat(10)}(Google Apps script)!`, {
        x: width/10 + 60,
        y: height/10 + 120,
        size: 40,
        font: helveticaFont,
        color: rgb(0.1, 0.1, 0.1),
        rotate: degrees(50),
        opacity: 0.5,
      })
    
      const pdfBytes = /*+++*/await pdfDoc.save();
      /*+++*/DriveApp.createFile(Utilities.newBlob(pdfBytes).setName('newpdf from apps script'))
    }