简体   繁体   English

使用 PDF-LIB 在 React 中渲染 PDF

[英]Render PDF in React using PDF-LIB

I'm trying to use PDF-LIB in order to implement PDF functionality in my React application.我正在尝试使用PDF-LIB在我的 React 应用程序中实现 PDF 功能。 The intent is to render PDF versions of forms, and allow the user to edit fields, and then save their progress.目的是渲染 PDF 版本的 forms,并允许用户编辑字段,然后保存他们的进度。

For this reason I decided to use PDF-LIB instead of alternatives like react-pdf, because this seems the most robust.出于这个原因,我决定使用 PDF-LIB 而不是 react-pdf 之类的替代方案,因为这似乎是最强大的。

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我对使用 PDF 的过程的理解如下: 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.文档表明我应该能够在 iframe 中呈现 PDF。 I tried creating an iframe element and returning that out of the modifypdf function.我尝试创建一个 iframe 元素并将其从modifypdf function 中返回。 I also tried setting the modified PDF data to the pdfInfo in state.我还尝试将修改后的 PDF 数据设置为pdfInfo中的 pdfInfo。 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?考虑到我希望用户能够编辑文档并能够保存,在 iFrame 中呈现 PDF 对我来说是最佳选择吗? 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: 20 年 9 月 29 日更新:

I realized that I had the byte array with the PDF revisions that came as a result of const pdfBytes = await pdfDoc.save();我意识到我的字节数组带有 PDF 修订版,这是由于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.因此,我使用URL.createObjectURL将数据转换为 URL,当我渲染 iframe 时,我可以在源代码中使用它。 That part is no longer breaking, but the PDF still does not render in the iframe.该部分不再损坏,但 PDF 仍未在 iframe 中呈现。

I have included the edited code above.我已经包含了上面编辑过的代码。

What I did and worked: I added a reference to the iframe instance:我所做的和工作的:我添加了对 iframe 实例的引用:

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您所需要的只是将 pdfBytes 作为数组传递

 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.不加载 iframe 的原因是,Blob 生成“http”url 并且浏览器只允许在 Iframe 中有“Https”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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