8

I'm trying to solve such problem with jsPDF:

I have PDF file, which is stored on server. I'm generating another pdf with jsPDF and trying to append to already existed pdf file (as I mentioned above) as a another page.

I googled about it, but can't find any help. Also I found this question on stackoverflow, but it is different scenario - Append Existing Pdf to Jspdf

How can I make this to work? Or is any other plugin or something else to make this?

Bharata
  • 13,509
  • 6
  • 36
  • 50
Shako Tskhadadze
  • 149
  • 1
  • 2
  • 11

3 Answers3

9

Unforfortunately, with jsPDF today (2018) it is not supported.

Alternative solution

But you could edit server side with free PHP library like FPDI. With FPDI it is even possible to edit PDF documents, extract some pages and to add them to new PDF documents. How to do it see here.

You could send to your server a request using AJAX and the server do it and gives you a new PDF back.


Update

We are in July 2020 and it is not supported with jsPDF. But some user created pull request about adding (copying) from pages from the same PDF document. On this link before you can find the sample code how to use his function. But it can not add pages from another PDF's. The code from his function you can find here.

Alternative solution with JavaScript PDF-lib

You can do it with JavaScript "PDF-lib". The source code and other info you can find on GitHub page. A lot of demos from this library you can find on it's project page.

"PDF-lib" can create and modify PDF documents in any JavaScript environment. It is designed to work in any modern JavaScript runtime. Tested in Node.JS, Browser, Deno, and React Native environments.

API documentation is available on the project site at:
https://pdf-lib.js.org/docs/api/

Example "Create PDF with Embed PDF Pages"

const { PDFDocument } = PDFLib;

async function embedPdfPages()
{
    // Fetch American flag PDF
    const flagUrl = 'https://pdf-lib.js.org/assets/american_flag.pdf',
        // Fetch U.S. constitution PDF
        constitutionUrl = 'https://pdf-lib.js.org/assets/us_constitution.pdf',
        flagPdfBytes = await fetch(flagUrl).then((res) => res.arrayBuffer()),
        constitutionPdfBytes = await fetch(constitutionUrl).then((res) => res.arrayBuffer()),
        // Create a new PDFDocument
        pdfDoc = await PDFDocument.create();
    
    // Add a blank page to the document
    var page = pdfDoc.addPage();
    
    // Embed the first page of the American flag PDF
    const [americanFlag] = await pdfDoc.embedPdf(flagPdfBytes),
        // Load the constitution PDF into a PDFDocument
        usConstitutionPdf = await PDFDocument.load(constitutionPdfBytes),
        // Embed the first page of the constitution
        firstPageOfConstitution = await pdfDoc.embedPage(usConstitutionPdf.getPages()[0]);

    // Draw the American flag page
    page.drawPage(americanFlag);
    
    //add a blank new page to the document
    page = pdfDoc.addPage();
    // Draw the first page of the constitution
     page.drawPage(firstPageOfConstitution);
    
    // Serialize the PDFDocument to bytes (a Uint8Array)
    const pdfBytes = await pdfDoc.save();
    // Trigger the browser to download the PDF document
    download(pdfBytes, "pdf-lib_pdf_page_embedding_example.pdf", "application/pdf");
}
body {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

p {
  font-family: helvetica;
  font-size: 24px;
  text-align: center;
  margin: 25px;
}

.small {
  font-family: helvetica;
  font-size: 18px;
  text-align: center;
  margin: 25px;
}

button {
  background-color: #008CBA;
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  font-size: 16px;
}
<script src="https://unpkg.com/pdf-lib@1.4.0"></script>
<script src="https://unpkg.com/downloadjs@1.4.7"></script>
<p>Click the button to embed PDF pages with <code>pdf-lib</code></p>
<button onclick="embedPdfPages()">Create PDF</button>
<p class="small">(Your browser will download the resulting file)</p>

Example "Create PDF with JPEG and other PDF as attachments"

const { PDFDocument, rgb } = PDFLib

async function addAttachments()
{
    // Define attachment URLs
    const jpgUrl = 'https://pdf-lib.js.org/assets/cat_riding_unicorn.jpg',
        pdfUrl = 'https://pdf-lib.js.org/assets/us_constitution.pdf',
        // Fetch attachments
        jpgAttachmentBytes = await fetch(jpgUrl).then(res => res.arrayBuffer()),
        pdfAttachmentBytes = await fetch(pdfUrl).then(res => res.arrayBuffer()),

        pdfDoc = await PDFDocument.create();

    // Add the JPG attachment
    await pdfDoc.attach(jpgAttachmentBytes, 'cat_riding_unicorn.jpg',
    {
        mimeType: 'image/jpeg',
        description: 'Cool cat riding a unicorn!',
        creationDate: new Date('2019/12/01'),
        modificationDate: new Date('2020/04/19')
    });
    // Add the PDF attachment
    await pdfDoc.attach(pdfAttachmentBytes, 'us_constitution.pdf',
    {
        mimeType: 'application/pdf',
        description: 'Constitution of the United States',
        creationDate: new Date('1787/09/17'),
        modificationDate: new Date('1992/05/07')
    });

    // Add a page with some text
    const page = pdfDoc.addPage();
    page.drawText('This PDF has two attachments. Note that only some appropriated PDF readers can view attachments. For example the Adobe Reader.', {x: 135, y: 415});

    // Serialize the PDFDocument to bytes (a Uint8Array)
    const pdfBytes = await pdfDoc.save();

    // Trigger the browser to download the PDF document
    download(pdfBytes, "pdf-lib_add_attachments.pdf", "application/pdf");
}
body {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

p {
  font-family: helvetica;
  font-size: 24px;
  text-align: center;
  margin: 25px;
}

.small {
  font-family: helvetica;
  font-size: 18px;
  text-align: center;
  margin: 25px;
}

button {
  background-color: #008CBA;
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  font-size: 16px;
}
blockquote
{
    background-color: rgba(255,229,100,.3);
    border-left: 8px solid #ffe564;
    padding: 15px 30px 15px 15px;
}
<script src="https://unpkg.com/pdf-lib@1.7.0"></script>
<script src="https://unpkg.com/downloadjs@1.4.7"></script>
<br><br><br>
<p>Click the button below to create a document and attach a JPEG image and PDF file with <code>pdf-lib</code></p>
<blockquote>Note that only some PDF readers can view attachments. This includes Adobe Reader, Foxit Reader, and Firefox.</blockquote>
<button onclick="addAttachments()">Create PDF</button>
<p class="small">(Your browser will download the resulting file)</p>

Useful links:

Bharata
  • 13,509
  • 6
  • 36
  • 50
  • Just note to read/open encrypted pdf's you would need to get the paid version of FPDI, which makes the free version pretty impractical to use when adding to existing pdf's. – Gavin Simpson Oct 27 '18 at 08:26
  • 1
    FPDI does not support importing of encrytped PDF documents. After all this makes no sense, because the resulting document is a completely new document which may be re-encrypted or not. Encrypting a resulting document is possible with the **[FPDI_Protection class](https://www.setasign.com/products/fpdi/downloads/#product-10103)**, which is an enhanced version of the free **[FPDF_Protection class](http://www.fpdf.org/en/script/script37.php)** (not FPDI_Protection class). In this class we could see how to encript PDF. – Bharata Oct 27 '18 at 08:58
2

jsPDF can't do this, but pdf-lib can. You can combine the two, or just use pdf-lib on its own. To load an existing pdf in pdf-lib, just do this:

async function loadPdf(){
  const response = await fetch('existing.pdf');
  const buffer = await response.arrayBuffer();
  const existingPdfDocBytes = new Uint8Array(buffer);
  const pdfDoc = PDFLib.PDFDocumentFactory.load(existingPdfDocBytes);
  return pdfDoc;
}
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
oligofren
  • 20,744
  • 16
  • 93
  • 180
-1

I dont have the code but I have an idea: https://www.npmjs.com/package/pdf-merger-js, pdf-merger-js merge blob pdf file , you can get the blob url of jspdf on doc.output('blob') and get the file from your server and convert it into blob too, then merge them.

borchvm
  • 3,533
  • 16
  • 44
  • 45