Madcap
Madcap

Reputation: 117

pdf-lib merge pdfs on frontend

I'm trying to merge two pdf files on frontend using javascript and pdf-lib library. I found this snippet pdf-lib in github repository:

async function mergePdfs(pdfsToMerge: string[]) {
  const mergedPdf = await PDFDocument.create();
  for (const pdfCopyDoc of pdfsToMerge) {
    const pdfBytes = fs.readFileSync(pdfCopyDoc);
    const pdf = await PDFDocument.load(pdfBytes);
    const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
    copiedPages.forEach((page) => {
      mergedPdf.addPage(page);
    });
  }
  const mergedPdfFile = await mergedPdf.save();
  return mergedPdfFile;
}

But as I see this snipped is for nodejs (there's no fs.readfilesync in browser javascript). So I have 2 questions:

  1. what should I put in pdfsToMerge(string: [])? I have variables containing urls to pdf1 and pdf
  2. Also I have two variables containing base64 code of these pdfs. How can I use this snippet not using fs.readfilesync like in nodejs but on frontend?

Many thanks in advance!

Upvotes: 1

Views: 9009

Answers (2)

David D Fischer
David D Fischer

Reputation: 19

Your version number should be newest pdf-lib

THen sequence of events matters. Here is function i use must be in order of event I use is with data or emtpy to get filled or non filled pdf files

async  copyPages(sale: Sale, url1, urlArray, isWithData, isEmptyForm) {
this.pdfService.getIsEmpty().subscribe(data => { isEmptyForm = data; });
this.pdfService.getIsWithData().subscribe(data => { isWithData = data; });
console.log(urlArray);
let donorBytes = [];
let donorBytesFInal = [];
let donorPage = [];
let donorDoc = [];
/**
 * first page get bytes from url
 * then load data
 * then convert the data bytes to pdfDocument 
 * later in routine this firstDonorDoc pages are inserted not added
 */
let firstDonorPdfBytes = await fetch(url1).then(res => res.arrayBuffer());
await this.loadDataTodocument(firstDonorPdfBytes, sale, isWithData, 
isEmptyForm).then(data => {
  firstDonorPdfBytes = data;
});

/**
 * load first document
 */
const firstDonorPdfDoc = await PDFDocument.load(firstDonorPdfBytes);

/**
 * load url array convert to bytes, send bytes to populate textfields with 
data
 */
for (let i = 0; i < urlArray.length; ++i) {
  console.log(urlArray.length);
  donorBytes[i] =  await fetch(urlArray[i].url).then(res => 
res.arrayBuffer());
}

/* Insert data to donorBytes and create DonorBytesFinal array with data */
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < donorBytes.length; ++i) {
await  this.loadDataTodocument(donorBytes[i], sale, isWithData, 
isEmptyForm).then(data 
 => {
    donorBytesFInal.push(data);
  });
}
//  console.log(donorBytesFInal);
/*
convert donor bytes to PdfDocument after bytes include data re 
 donorBytesFInal
*/
for (let i = 0; i < donorBytesFInal.length; ++i) {
  donorDoc[i] = await PDFDocument.load(donorBytesFInal[i]);
}
/* create out put document **/
const pdfDoc = await PDFDocument.create();

/**
 * copay first page... not in array
 */
const [firstDonorPage] = await pdfDoc.copyPages(firstDonorPdfDoc, [0]);

/**
 * copy all array pages of singular docuemnts output pdfdoc. Notices these 
 are insertpages nto addpage
 */
for (let i = 0; i < donorBytes.length; ++i) {
  [donorPage[i]] = await pdfDoc.copyPages(donorDoc[i], [0]);
  pdfDoc.insertPage(0, donorPage[i]);
}

/** first page is an ADDpage not an insert */
pdfDoc.addPage(firstDonorPage);

/** create tyes for 64 and 8 and update globally */
const u8 = await pdfDoc.save();
const n64 = await pdfDoc.saveAsBase64();
this.pdfService.changeUint8ByteArray(u8);
this.pdfService.changeBase64Array(n64);
const pdfBytes = u8;
 /** redundant empty urlarray */
urlArray = [];

Upvotes: 0

Taylor Sturtz
Taylor Sturtz

Reputation: 33

The PDFDocument.load() method will accept base64 strings as the parameter so you don't need to do transform those at all.

As for your variables storing url paths to pdf documents, you can use fetch instead of node's file system. As described in the pdf-lib docs, you can store the ArrayBuffer and pass that into PDFDocument.load() like so:

const url = 'https://pdf-lib.js.org/assets/with_update_sections.pdf'
const arrayBuffer = await fetch(url).then(res => res.arrayBuffer())
const pdfDoc = await PDFDocument.load(arrayBuffer)

Upvotes: 2

Related Questions