surveyjs / survey-pdf

Supplementary component to the SurveyJS Form Library to download surveys as PDF files and generate editable PDF forms.
https://surveyjs.io/pdf-generator/examples/survey-pdf-export/
Other
58 stars 29 forks source link

Merge/Concatenate Multiple Forms into one PDF document #309

Open JaneSjs opened 3 months ago

JaneSjs commented 3 months ago
JaneSjs commented 3 months ago

In the meantime, it is possible to merge multiple PDF documents into a single document using third-party libraries. The following demo shows how to merge two surveys using the pdf-lib library: View Demo.

import React from "react";
import { SurveyPDF } from "survey-pdf";
import "survey-core/defaultV2.min.css";
import "./index.css";
import { json3, json4, data3, data4 } from "./json";
import { PDFDocument } from "pdf-lib";

async function mergePdfs(pdfsToMerges) {
  const mergedPdf = await PDFDocument.create();
  const actions = pdfsToMerges.map(async (pdfBuffer) => {
    const pdf = await PDFDocument.load(pdfBuffer);
    const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
    copiedPages.forEach((page) => {
      //page.setWidth(210);
      mergedPdf.addPage(page);
    });
  });
  await Promise.all(actions);
  const mergedPdfFile = await mergedPdf.save();

  // Convert ArrayBuffer to Blob
  const mergedPdfBlob = new Blob([mergedPdfFile], { type: "application/pdf" });

  // Create a URL for the Blob
  const mergedPdfUrl = URL.createObjectURL(mergedPdfBlob);

  // Create a download link
  const downloadLink = document.createElement("a");
  downloadLink.href = mergedPdfUrl;
  downloadLink.download = "merged.pdf";

  // Append the download link to the body and click it programmatically
  document.body.appendChild(downloadLink);
  downloadLink.click();

  // Clean up by removing the download link and revoking the URL
  document.body.removeChild(downloadLink);
  URL.revokeObjectURL(mergedPdfUrl);
}

async function createSurveyPdfModel(surveyJsons, responses) {
  let options = {
    fontSize: 14,
    margins: {
      left: 10,
      right: 10,
      top: 10,
      bot: 10,
    },
    format: [210, 297],
  };
  const surveyPDF1 = new SurveyPDF(surveyJsons[0], options);
  surveyPDF1.data = responses[0];
  const surveyPDF2 = new SurveyPDF(surveyJsons[1], options);
  surveyPDF2.data = responses[1];

  // Load PDF documents and wait for both to be loaded
  const [pdf1Content, pdf2Content] = await Promise.all([
    loadPDFContent(surveyPDF1),
    loadPDFContent(surveyPDF2),
  ]);

  if (pdf1Content && pdf2Content) {
    await mergePdfs([pdf1Content, pdf2Content]);
  } else {
    console.error("Error: One or both PDF buffers are empty.");
  }
}

async function loadPDFContent(surveyInstance) {
  try {
    const blob = await surveyInstance.raw("blob");
    const reader = new FileReader();
    reader.readAsArrayBuffer(blob);
    return await new Promise((resolve, reject) => {
      reader.onload = () => {
        resolve(reader.result);
      };
      reader.onerror = reject;
    });
  } catch (error) {
    console.error("Error loading PDF content:", error);
    return null;
  }
}

function SurveyPdfComponent() {
  return (
    <button
      onClick={() => createSurveyPdfModel([json3, json4], [data3, data4])}
    >
      Export Merged Surveys
    </button>
  );
}

export default SurveyPdfComponent;
//...
export const json3 = {
  title: "Sample Survey 1",
  mode: "display",
  pages: [
    {
      name: "page1",
      elements: [
        {
          type: "boolean",
          name: "question1",
        },
      ],
    },
  ],
};
export const json4 = {
  title: "Sample Survey 2",
  mode: "display",
  pages: [
    {
      name: "page1",
      elements: [
        {
          type: "boolean",
          name: "question2",
          title: "My Survey",
        },
      ],
    },
  ],
};
export const data3 = {
  question1: true,
};
export const data4 = {
  question2: false,
};