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.
To open PDF when clicking on a link with React, we can import the PDF file as a module and set that as the value of the href prop. We set the href prop of the a element to pdf which we imported with import . Then we set the target prop to '_blank' to open the PDF in a new window.
React-pdf provides a React component API that allows to open PDF files and render them using PDF.js. Although this is a simple library specialized for PDF viewing, it has some amazing features like: Easy to use — Insert the Document component and give it a file prop. React-pdf will sort it out whether it’s a URL, a file, or base64.
So, in this article, I will evaluate 5 PDF Viewer Libraries for React with feature comparisons to help you choose the best one for your requirement. 1. React-pdf/renderer — Specialized in rendering and creating PDFs. React-pdf/renderer is a widely used library for creating PDF files on the browser and server.
With react-pdf, we can render dynamic text using the render prop of the Text component like so: Here, the render prop has two arguments: pageNumber (the current index of the page), and totalPages (the total number of pages that this document contains). We are displaying both of their values to the client.
While going through the documentation when I was trying to pick the appropriate library for my use-case there were some features of React-pdf that convinced me to use it, I will briefly talk about them: React-Pdf uses React-Primitives spec to create custom components that you can use to create and structure your PDF documents.
Adding these lines seems to fix the code for me:
const bytes = new Uint8Array( pdfBytes );
const blob = new Blob( [ bytes ], { type: "application/pdf" } );
const docUrl = URL.createObjectURL( blob );
setPdfInfo( docUrl );
Or use it directly:
return <iframe src={docUrl} type="application/pdf" />
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" />}</>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With