简体   繁体   中英

Render PDF in React using PDF-LIB

I'm trying to use PDF-LIB in order to implement PDF functionality in my React application. The intent is to render PDF versions of forms, and allow the user to edit fields, and then save their progress.

For this reason I decided to use PDF-LIB instead of alternatives like react-pdf, because this seems the most robust.

My understanding of the process of working with PDF's is the following: Fetch PDF & convert to byte array --> Load PDF data and make changes --> Save updated PDF as byte array

I'm trying to adapt the example found here

Here's my code:

const LoadPDF = () => {
  const [pdfInfo, setPdfInfo] = useState([]);

  useEffect(() => {
    modifyPdf();
  }, []);

  const modifyPdf = async () => {
    const existingPdfBytes = await fetch(
      "https://pdf-lib.js.org/assets/with_update_sections.pdf"
    ).then((res) => res.arrayBuffer());

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

    const pages = pdfDoc.getPages();
    const firstPage = pages[0];
    
    // Get the width and height of the first page
    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 = await pdfDoc.save();
    const docUrl = URL.createObjectURL(
      new Blob(pdfBytes, { type: "application/pdf" })
    );
    setPdfInfo(docUrl);
  };
  
  return (
    <>{<iframe title="test-frame" src={pdfInfo} type="application/pdf" />}</>
  );
};

export default LoadPDF;

The docs indicate that I should be able to render the PDF in an iframe. I tried creating an iframe element and returning that out of the modifypdf function. I also tried setting the modified PDF data to the pdfInfo in state. The third thing I tried was to create an image and then render that.

At this point I'm lost. Would rendering the PDF in an iFrame be the best option for me, given that I want the user to be able to edit the document and be able to save? I have a disconnect between getting the data in the format I need, and rendering it to the screen. I know I'll need to refactor this, but I'm trying to get an idea of how this library works, and then work on solving the other parts of my problem.

Update 9/29/20:

I realized that I had the byte array with the PDF revisions that came as a result of const pdfBytes = await pdfDoc.save(); So I've used URL.createObjectURL to turn the data into a URL that I can use in the source when I render the iframe. That part is no longer breaking, but the PDF still does not render in the iframe.

I have included the edited code above.

What I did and worked: I added a reference to the iframe instance:

import React, { useState, useEffect, useRef } from 'react';

const LoadPDF = () => {
...
const viewer = useRef(null);

const modifyPDF = async () => {
...
};

return (
        <>{<iframe title="test-frame" src={pdfInfo} ref={viewer} type="application/pdf" />}</>
      );
}

Adding these lines seems to fix the code for me:

var bytes = new Uint8Array(pdfBytes); 
var blob = new Blob([bytes], { type: "application/pdf" });
const docUrl = URL.createObjectURL(blob);
setPdfInfo(docUrl);

All you needed was to pass pdfBytes as an array

 const docUrl = URL.createObjectURL(new Blob([pdfBytes], {type: 'application/pdf'}))
setPdfInfo(docUrl);

Reason behind not loading iframe is, Blob generate "http" url and browser only allow to have "Https" in Iframe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM