UNPKG

survey-pdf

Version:

Renders JSON-driven SurveyJS forms and their responses as PDF documents in the browser or Node.js: fillable interactive PDF forms (AcroForm) or static printouts.

194 lines (185 loc) 7.42 kB
/*! * surveyjs - SurveyJS PDF library v3.0.2 * Copyright (c) 2015-2026 Devsoft Baltic OÜ - http://surveyjs.io/ * License: MIT (http://www.opensource.org/licenses/mit-license.php) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs')) : typeof define === 'function' && define.amd ? define(['exports', 'fs'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.PDFFormFiller = {}, global.fs)); })(this, (function (exports, fs) { 'use strict'; class FormsMap { constructor(map) { this.map = map; this.res = {}; } mapDataRecursive(data, map) { if (data === undefined || data === null) return; if (typeof (data) !== 'object') { if (Array.isArray(map)) { map.forEach((m) => { this.mapDataRecursive(data, m); }); return; } if (typeof (map) !== 'object') { this.res[map] = data; } else { this.res[map[data].field] = map[data].value; } return; } if (Array.isArray(data)) { data.forEach((d, i) => { this.mapDataRecursive(d, Array.isArray(map) ? map[i] : map); }); return; } Object.keys(data).forEach(key => { this.mapDataRecursive(data[key], map[key]); }); } mapData(data) { this.res = {}; this.mapDataRecursive(data, this.map); return this.res; } } /** * A base class for the `PDFFormFiller` plugin. * @since 2.0.9 */ class PDFFormFillerBase { constructor(options) { if (options) { this.data = options.data; this.fieldMap = options.fieldMap; this.pdfTemplate = options.pdfTemplate; this.pdfLibraryAdapter = options.pdfLibraryAdapter; } } async getPDFBytes() { var _a; const map = new FormsMap(this.fieldMap); const plainData = map.mapData(this.data); return await ((_a = this.pdfLibraryAdapter) === null || _a === void 0 ? void 0 : _a.fillForm(this.pdfTemplate, plainData)); } fromCharCode(array) { const strings = []; const chunkSize = 0xffff; for (let i = 0; i < array.length; i += chunkSize) { const chunk = Array.prototype.slice.call(array, i, i + chunkSize); strings.push(String.fromCharCode.apply(null, chunk)); } return strings.join(''); } /** * An asynchronous method that allows you to get PDF content in different formats. * @param type *(Optional)* One of `"blob"`, `"bloburl"`, `"dataurlstring"`. Do not specify this parameter if you want to get raw PDF content as a string value. * @since 2.0.9 */ async raw(type) { const pdfBytes = await this.getPDFBytes(); if (!type || !pdfBytes) return pdfBytes; if (type == 'dataurlstring') return 'data:application/pdf;base64,' + btoa(this.fromCharCode(pdfBytes)); const blob = new Blob([pdfBytes], { type: 'application/pdf' }); if (type == 'blob') return blob; if (type == 'bloburl') return URL.createObjectURL(blob); return pdfBytes; } /** * An asynchronous method that starts to download the filled PDF form in the web browser. * * [View pdf-lib Demo](https://surveyjs.io/pdf-generator/examples/map-survey-responses-to-pdf-fields-using-pdflib/ (linkStyle)) * * [View PDF.js Demo](https://surveyjs.io/pdf-generator/examples/fill-in-pdf-form-fields-with-dynamic-survey-data-using-pdfjs/ (linkStyle)) * @param fileName *(Optional)* A file name with the ".pdf" extension. Default value: `"FilledForm.pdf"`. * @since 2.0.9 */ async save(fileName = 'FilledForm.pdf') { const pdfBytes = await this.getPDFBytes(); if (!pdfBytes) return; await this.saveToFile(pdfBytes, fileName); } } class PDFFormFiller extends PDFFormFillerBase { async saveToFile(pdfBytes, fileName) { return new Promise((resolve, reject) => { fs.writeFile(fileName, pdfBytes, (err) => { if (err) reject(err); else resolve(); }); }); } } class PDFLibAdapter { constructor(pdfLibrary) { this.pdfLibrary = pdfLibrary; } async fillForm(template, data) { const { PDFDocument, PDFTextField, PDFCheckBox, PDFRadioGroup, PDFDropdown } = this.pdfLibrary; const pdfDoc = await PDFDocument.load(template); const form = pdfDoc.getForm(); const fields = form.getFields(); fields.forEach((field) => { const fieldName = field.getName(); const value = data[fieldName]; if (value === null || value === undefined) return; if (field instanceof PDFTextField) { field.setText(value); } else if (field instanceof PDFCheckBox) { if (value) field.check(); else field.uncheck(); } else if (field instanceof PDFRadioGroup || field instanceof PDFDropdown) { field.select(value.toString()); } }); return await pdfDoc.save(); } } class PDFJSAdapter { constructor(pdfLibrary) { this.pdfLibrary = pdfLibrary; } async fillForm(template, data) { const pdfjsLib = this.pdfLibrary; const doc = await pdfjsLib.getDocument(template).promise; const numPages = doc.numPages; // Process all pages for (let pageNum = 1; pageNum <= numPages; pageNum++) { const page = await doc.getPage(pageNum); const annotations = await page.getAnnotations(); annotations.forEach((field) => { if (field.fieldType == undefined) return; const value = data[field.fieldName]; if (value) { if (field.radioButton && field.buttonValue != value) { return; } doc.annotationStorage.setValue(field.id, { value }); } }); } return await doc.saveDocument(); } } exports.PDFFormFiller = PDFFormFiller; exports.PDFJSAdapter = PDFJSAdapter; exports.PDFLibAdapter = PDFLibAdapter; })); //# sourceMappingURL=pdf-form-filler.node.js.map