wojtekmaj / react-pdf

Display PDFs in your React app as easily as if they were images.
https://projects.wojtekmaj.pl/react-pdf
MIT License
9.34k stars 882 forks source link

It will be very helpful if this plugin has feature to render editable pdf #1776

Open salildts opened 5 months ago

salildts commented 5 months ago

Before you start - checklist

Description

I'm using the react-pdf plugin to render a editable pdf by which I can fill the form of the given pdf and then can download it with the given inputs in the pdf. But I could not get any scope to make the things ready for us. So, my request is to add this feature and this plug in will be more helpful for us.

Proposed solution

No response

Alternatives

No response

Additional information

No response

Code-X-Rahul commented 5 months ago

Did you find any solution. i want to implement same feature as your. tried using pdfjs-dist in next 14 but getting a shit ton of errors which i could not resolve.

mikejar commented 4 months ago

have you tried setting renderForm={true} on the Page component?

nothingrealhappen commented 3 months ago

Like @mikejar said you can use renderForm to render annotations, and if you want to download the modified pdf you can use:

const pdfRef = React.useRef<DocumentCallback>(null);

const onDocumentLoadSuccess = (pdf) => {
  pdfRef.current = pdf;
};

const downloadPdf = async () => {
  const data = await pdfRef.current?.saveDocument();
  downloadManager.download(data, null, "result.pdf", null);
};
// downloadManager, only support web browser environment
import { createValidAbsoluteUrl, isPdfFile } from "pdfjs-dist";

function download(blobUrl, filename) {
  const a = document.createElement("a");
  if (!a.click) {
    throw new Error('DownloadManager: "a.click()" is not supported.');
  }
  a.href = blobUrl;
  a.target = "_parent";
  // Use a.download if available. This increases the likelihood that
  // the file is downloaded instead of opened by another PDF plugin.
  if ("download" in a) {
    a.download = filename;
  }
  // <a> must be in the document for recent Firefox versions,
  // otherwise .click() is ignored.
  (document.body || document.documentElement).append(a);
  a.click();
  a.remove();
}

/**
 * @implements {IDownloadManager}
 */
class DownloadManager {
  private openBlobUrls = new WeakMap();

  downloadUrl(url, filename, _options) {
    if (!createValidAbsoluteUrl(url, "http://example.com")) {
      console.error(`downloadUrl - not a valid URL: ${url}`);
      return; // restricted/invalid URL
    }
    download(url + "#pdfjs.action=download", filename);
  }

  downloadData(data, filename, contentType) {
    const blobUrl = URL.createObjectURL(
      new Blob([data], { type: contentType })
    );
    download(blobUrl, filename);
  }

  /**
   * @returns {boolean} Indicating if the data was opened.
   */
  openOrDownloadData(data, filename, dest = null) {
    const isPdfData = isPdfFile(filename);
    const contentType = isPdfData ? "application/pdf" : "";

    if (isPdfData) {
      let blobUrl = this.openBlobUrls.get(data);
      if (!blobUrl) {
        blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
        this.openBlobUrls.set(data, blobUrl);
      }
      let viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename);
      if (dest) {
        viewerUrl += `#${escape(dest)}`;
      }

      try {
        window.open(viewerUrl);
        return true;
      } catch (ex) {
        console.error(`openOrDownloadData: ${ex}`);
        // Release the `blobUrl`, since opening it failed, and fallback to
        // downloading the PDF file.
        URL.revokeObjectURL(blobUrl);
        this.openBlobUrls.delete(data);
      }
    }

    this.downloadData(data, filename, contentType);
    return false;
  }

  download(data, url, filename, _options) {
    const blobUrl = URL.createObjectURL(
      new Blob([data], { type: "application/pdf" })
    );
    download(blobUrl, filename);
  }
}

export { DownloadManager };
zhanls commented 3 months ago

Like @mikejar said you can use renderForm to render annotations, and if you want to download the modified pdf you can use:

const pdfRef = React.useRef<DocumentCallback>(null);

const onDocumentLoadSuccess = (pdf) => {
  pdfRef.current = pdf;
};

const downloadPdf = async () => {
  const data = await pdfRef.current?.saveDocument();
  downloadManager.download(data, null, "result.pdf", null);
};
// downloadManager, only support web browser environment
import { createValidAbsoluteUrl, isPdfFile } from "pdfjs-dist";

function download(blobUrl, filename) {
  const a = document.createElement("a");
  if (!a.click) {
    throw new Error('DownloadManager: "a.click()" is not supported.');
  }
  a.href = blobUrl;
  a.target = "_parent";
  // Use a.download if available. This increases the likelihood that
  // the file is downloaded instead of opened by another PDF plugin.
  if ("download" in a) {
    a.download = filename;
  }
  // <a> must be in the document for recent Firefox versions,
  // otherwise .click() is ignored.
  (document.body || document.documentElement).append(a);
  a.click();
  a.remove();
}

/**
 * @implements {IDownloadManager}
 */
class DownloadManager {
  private openBlobUrls = new WeakMap();

  downloadUrl(url, filename, _options) {
    if (!createValidAbsoluteUrl(url, "http://example.com")) {
      console.error(`downloadUrl - not a valid URL: ${url}`);
      return; // restricted/invalid URL
    }
    download(url + "#pdfjs.action=download", filename);
  }

  downloadData(data, filename, contentType) {
    const blobUrl = URL.createObjectURL(
      new Blob([data], { type: contentType })
    );
    download(blobUrl, filename);
  }

  /**
   * @returns {boolean} Indicating if the data was opened.
   */
  openOrDownloadData(data, filename, dest = null) {
    const isPdfData = isPdfFile(filename);
    const contentType = isPdfData ? "application/pdf" : "";

    if (isPdfData) {
      let blobUrl = this.openBlobUrls.get(data);
      if (!blobUrl) {
        blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
        this.openBlobUrls.set(data, blobUrl);
      }
      let viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename);
      if (dest) {
        viewerUrl += `#${escape(dest)}`;
      }

      try {
        window.open(viewerUrl);
        return true;
      } catch (ex) {
        console.error(`openOrDownloadData: ${ex}`);
        // Release the `blobUrl`, since opening it failed, and fallback to
        // downloading the PDF file.
        URL.revokeObjectURL(blobUrl);
        this.openBlobUrls.delete(data);
      }
    }

    this.downloadData(data, filename, contentType);
    return false;
  }

  download(data, url, filename, _options) {
    const blobUrl = URL.createObjectURL(
      new Blob([data], { type: "application/pdf" })
    );
    download(blobUrl, filename);
  }
}

export { DownloadManager };

Much credits for the DownloadManager solution. Really helps a lot. But does the solution come from https://github.com/mozilla/pdf.js/blob/master/web/download_manager.js originally?