diff --git a/.gitignore b/.gitignore
index abb965fa4..f66991985 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,5 +9,7 @@ doc
nbproject
package-lock.json
yarn.lock
+*pnpm-lock.yaml
+.vscode
.idea
/js
diff --git a/dev-playground/public/index.html b/dev-playground/public/index.html
index dbc529dee..5888b600a 100644
--- a/dev-playground/public/index.html
+++ b/dev-playground/public/index.html
@@ -58,10 +58,10 @@
Playground does not make too much sense when horizontal resolution is below
var editor = ace.edit('editor');
setupEditor(editor);
- var names = ['basics', 'styles1', 'styles2', 'styles3', 'columns', 'tables', 'lists', 'margin', 'images', 'svgs', 'attachments'];
+ var names = ['basics', 'styles1', 'styles2', 'styles3', 'columns', 'tables', 'lists', 'margin', 'images', 'svgs', 'attachments', 'acroforms'];
var i = 0;
- ['basics', 'named-styles', 'inline-styling', 'style-overrides', 'columns', 'tables', 'lists', 'margins', 'images', 'svgs', 'attachments'].forEach(function (example) {
+ ['basics', 'named-styles', 'inline-styling', 'style-overrides', 'columns', 'tables', 'lists', 'margins', 'images', 'svgs', 'attachments', 'acroforms'].forEach(function (example) {
$scope.examples.push({
name: names[i++],
activate: function () {
diff --git a/dev-playground/public/samples/acroforms b/dev-playground/public/samples/acroforms
new file mode 100644
index 000000000..49411e349
--- /dev/null
+++ b/dev-playground/public/samples/acroforms
@@ -0,0 +1,347 @@
+{
+ "subsetFonts": false,
+ "content": [
+ {
+ "text": "Acroforms",
+ "style": "header"
+ },
+ {
+ "text": [
+ "It is recommended that you test your PDF form ",
+ "documents across all platforms and viewers that you wish to ",
+ "support. Refer to ",
+ "https://pdfkit.org/docs/forms or the PDF ",
+ "reference for form options and advanced form field use.\n\n"
+ ],
+ "style": "description"
+ },
+ {
+ "text": "Components\n",
+ "style": "subHeader"
+ },
+ {
+ "text": [
+ "Make sure you set the subsetFonts flag to false when using ",
+ "form fields with text.\n\n"
+ ],
+ "style": {
+ "bold": true
+ }
+ },
+ {
+ "text": "Text field",
+ "style": "formHeader"
+ },
+ {
+ "columns": [
+ [
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_placeholder",
+ "options": {
+ "value": "Placeholder ..."
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15,
+ "italics": true
+ },
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_date",
+ "options": {
+ "format": {
+ "type": "date"
+ },
+ "align": "center",
+ "value": "10/12"
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15
+ },
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_multi",
+ "options": {
+ "multiline": true,
+ "value": "multiline text form "
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 50
+ }
+ ],
+ [
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_alignment",
+ "options": {
+ "align": "right",
+ "value": "right alignment"
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15
+ },
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_color",
+ "options": {
+ "align": "center",
+ "required": true,
+ "value": "Ω©®℅¥123"
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15
+ }
+ ],
+ [
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_currency",
+ "options": {
+ "align": "right",
+ "format": {
+ "type": "number",
+ "nDec": 2,
+ "sepComma": true,
+ "negStyle": "ParensRed",
+ "currency": "$",
+ "currencyPrepend": true
+ },
+ "value": "$123,346.99"
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15
+ },
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_backgroundcolor",
+ "options": {
+ "backgroundColor": "yellow",
+ "borderColor": "green",
+ "align": "center",
+ "value": "background color"
+ }
+ },
+ "style": "textFieldStyle",
+ "height": 15
+ }
+ ]
+ ]
+ },
+ {
+ "columns": [
+ [
+ {
+ "text": "\nList",
+ "style": "formHeader"
+ },
+ {
+ "acroform": {
+ "type": "list",
+ "id": "list1",
+ "options": {
+ "select": [
+ "",
+ "A",
+ "B",
+ "C"
+ ]
+ }
+ },
+ "width": 100,
+ "height": 60
+ }
+ ],
+ [
+ {
+ "text": "\nCombobox",
+ "style": "formHeader"
+ },
+ {
+ "acroform": {
+ "type": "combo",
+ "id": "combo1",
+ "options": {
+ "select": [
+ "",
+ "A",
+ "B",
+ "C"
+ ],
+ "defaultValue": ""
+ }
+ },
+ "width": 100,
+ "height": 20
+ }
+ ],
+ [
+ {
+ "text": "\nCheckbox form",
+ "style": "formHeader"
+ },
+ {
+ "acroform": {
+ "type": "checkbox",
+ "id": "checkbox1",
+ "options": {
+ "selected": false
+ }
+ },
+ "width": 20,
+ "height": 20
+ }
+ ]
+ ]
+ },
+ {
+ "text": "\nYou can also use forms inline with text\n\n",
+ "style": "subHeader"
+ },
+ {
+ "text": [
+ "Check this box! ",
+ {
+ "acroform": {
+ "type": "checkbox",
+ "id": "checkbox2",
+ "options": {
+ "selected": false
+ }
+ },
+ "width": 15,
+ "height": 15
+ },
+ "\n\n"
+ ],
+ "alignment": "center"
+ },
+ {
+ "text": [
+ "The weather was very ",
+ {
+ "acroform": {
+ "type": "combo",
+ "id": "combo_story1",
+ "options": {
+ "select": [
+ "",
+ "nice",
+ "bad"
+ ],
+ "defaultValue": ""
+ }
+ },
+ "width": 50,
+ "height": 9.5
+ },
+ " and the skies were ",
+ {
+ "acroform": {
+ "type": "combo",
+ "id": "combo_story2",
+ "options": {
+ "select": [
+ "",
+ "clear",
+ "cloudy"
+ ],
+ "defaultValue": ""
+ }
+ },
+ "width": 50,
+ "height": 9.5
+ },
+ ". A fox named ",
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_story1"
+ },
+ "width": 50,
+ "height": 9.5
+ },
+ " and friends were playing a game at the park, when suddenly",
+ "... ",
+ {
+ "text": "finish the story",
+ "style": {
+ "italics": true,
+ "bold": true
+ }
+ }
+ ]
+ },
+ {
+ "acroform": {
+ "type": "text",
+ "id": "text_story2",
+ "options": {
+ "multiline": true
+ }
+ },
+ "style": "textFieldStyle",
+ "width": "*",
+ "height": 100
+ }
+ ],
+ "styles": {
+ "header": {
+ "fontSize": 18,
+ "bold": true,
+ "margin": [
+ 0,
+ 0,
+ 0,
+ 10
+ ],
+ "lineHeight": 0.3
+ },
+ "description": {
+ "fontSize": 13,
+ "margin": [
+ 0,
+ 10,
+ 0,
+ 5
+ ]
+ },
+ "subHeader": {
+ "bold": true,
+ "fontSize": 13
+ },
+ "formHeader": {
+ "fontSize": 12,
+ "color": "black"
+ },
+ "tableCell": {
+ "margin": [
+ 0,
+ 5,
+ 0,
+ 5
+ ]
+ },
+ "textFieldStyle": {
+ "font": "Helvetica",
+ "margin": [
+ 0,
+ 0,
+ 5,
+ 5
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/dev-playground/server.js b/dev-playground/server.js
index 0a3dbea6b..4bbb392ba 100644
--- a/dev-playground/server.js
+++ b/dev-playground/server.js
@@ -19,7 +19,13 @@ function createPdfBinary(docDefinition) {
bold: path.join(__dirname, '..', 'examples', '/fonts/Roboto-Medium.ttf'),
italics: path.join(__dirname, '..', 'examples', '/fonts/Roboto-Italic.ttf'),
bolditalics: path.join(__dirname, '..', 'examples', '/fonts/Roboto-MediumItalic.ttf')
- }
+ },
+ Helvetica: {
+ normal: 'Helvetica',
+ bold: 'Helvetica-Bold',
+ italics: 'Helvetica-Oblique',
+ bolditalics: 'Helvetica-BoldOblique'
+ },
};
pdfmake.setFonts(fonts);
@@ -35,6 +41,7 @@ app.post('/pdf', function (req, res) {
res.contentType('application/pdf');
res.send(binary);
}, function (error) {
+ console.log(error); //print in console
res.send('ERROR:' + error);
});
diff --git a/package.json b/package.json
index ef1164235..1e6027304 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"file-saver": "^2.0.5",
"globals": "^15.14.0",
"mocha": "^11.0.1",
+ "nodemon": "^3.1.9",
"npm-run-all": "^4.1.5",
"process": "^0.11.10",
"rewire": "^7.0.0",
@@ -62,7 +63,8 @@
"build:fonts": "shx mkdir -p build/fonts && shx mkdir -p build/fonts/Roboto && shx cp -r fonts/Roboto/*.* build/fonts/Roboto && brfs \"./src/browser-extensions/fonts/Roboto.js\" > build/fonts/Roboto.js",
"lint": "eslint \"./src/**/*.js\" \"./tests/**/*.js\" \"./examples/**/*.js\" \"./standard-fonts/**/*.js\" \"./fonts/**/*.js\"",
"mocha": "mocha --reporter spec \"./tests/**/*.spec.js\"",
- "playground": "node dev-playground/server.js"
+ "playground": "node dev-playground/server.js",
+ "playground:watch": "nodemon dev-playground/server.js"
},
"repository": {
"type": "git",
diff --git a/src/DocMeasure.js b/src/DocMeasure.js
index 79eeebbcf..c184b8b59 100644
--- a/src/DocMeasure.js
+++ b/src/DocMeasure.js
@@ -38,7 +38,6 @@ class DocMeasure {
return this.styleStack.auto(node, () => {
// TODO: refactor + rethink whether this is the proper way to handle margins
node._margin = getNodeMargin(node, this.styleStack);
-
if (node.columns) {
return extendMargins(this.measureColumns(node));
} else if (node.stack) {
@@ -63,6 +62,8 @@ class DocMeasure {
return extendMargins(this.measureQr(node));
} else if (node.attachment) {
return extendMargins(this.measureAttachment(node));
+ } else if (node.acroform) {
+ return extendMargins(this.measureAcroForm(node));
} else {
throw new Error(`Unrecognized document structure: ${stringifyNode(node)}`);
}
@@ -708,6 +709,23 @@ class DocMeasure {
return node;
}
+
+ measureAcroForm(node) {
+ node._minWidth = 10;
+ node._minHeight = 10;
+
+ let font = StyleContextStack.getStyleProperty(node, this.styleStack, 'font', 'Roboto');
+ let bold = StyleContextStack.getStyleProperty(node, this.styleStack, 'bold', false);
+ let italics = StyleContextStack.getStyleProperty(node, this.styleStack, 'italics', false);
+
+ node.font = font;
+ node.bold = bold;
+ node.italics = italics;
+
+ node.alignment = StyleContextStack.getStyleProperty(node, this.styleStack, 'alignment', 'left');
+
+ return node;
+ }
}
export default DocMeasure;
diff --git a/src/DocPreprocessor.js b/src/DocPreprocessor.js
index 6002555b3..bb44bf534 100644
--- a/src/DocPreprocessor.js
+++ b/src/DocPreprocessor.js
@@ -59,11 +59,17 @@ class DocPreprocessor {
return this.preprocessAttachment(node);
} else if (node.pageReference || node.textReference) {
return this.preprocessText(node);
+ } else if (node.acroform) {
+ return this.preprocessAcroForm(node);
} else {
throw new Error(`Unrecognized document structure: ${stringifyNode(node)}`);
}
}
+ preprocessAcroForm(node) {
+ return node;
+ }
+
preprocessColumns(node) {
let columns = node.columns;
diff --git a/src/ElementWriter.js b/src/ElementWriter.js
index fdf7d6ed1..b3bb92038 100644
--- a/src/ElementWriter.js
+++ b/src/ElementWriter.js
@@ -203,6 +203,33 @@ class ElementWriter extends EventEmitter {
return position;
}
+ addAcroForm(node, index) {
+ let context = this.context();
+ let page = context.getCurrentPage();
+ let position = this.getCurrentPositionOnPage();
+
+ if (!page) {
+ return false;
+ }
+
+ if (node._x === undefined) {
+ node._x = node.x || 0;
+ }
+
+ addPageItem(page, {
+ type: 'acroform',
+ item: node
+ }, index);
+
+ node.x = context.x + node._x;
+ node.y = context.y;
+
+
+ context.moveDown(node.height || node._minHeight);
+
+ return position;
+ }
+
addAttachment(attachment, index) {
let context = this.context();
let page = context.getCurrentPage();
diff --git a/src/LayoutBuilder.js b/src/LayoutBuilder.js
index 1dc884a28..7ef979b83 100644
--- a/src/LayoutBuilder.js
+++ b/src/LayoutBuilder.js
@@ -7,7 +7,7 @@ import TableProcessor from './TableProcessor';
import Line from './Line';
import { isString, isValue, isNumber } from './helpers/variableType';
import { stringifyNode, getNodeId } from './helpers/node';
-import { pack, offsetVector } from './helpers/tools';
+import { offsetVector } from './helpers/tools';
import TextInlines from './TextInlines';
import StyleContextStack from './StyleContextStack';
@@ -36,7 +36,7 @@ class LayoutBuilder {
}
registerTableLayouts(tableLayouts) {
- this.tableLayouts = pack(this.tableLayouts, tableLayouts);
+ this.tableLayouts = { ...this.tableLayouts, ...tableLayouts };// pack(this.tableLayouts, tableLayouts);
}
/**
@@ -78,7 +78,7 @@ class LayoutBuilder {
let nodeInfo = {};
[
'id', 'text', 'ul', 'ol', 'table', 'image', 'qr', 'canvas', 'svg', 'columns',
- 'headlineLevel', 'style', 'pageBreak', 'pageOrientation',
+ 'headlineLevel', 'style', 'pageBreak', 'pageOrientation', 'acroForm', 'type', 'options',
'width', 'height'
].forEach(key => {
if (node[key] !== undefined) {
@@ -475,6 +475,8 @@ class LayoutBuilder {
this.processQr(node);
} else if (node.attachment) {
this.processAttachment(node);
+ } else if (node.acroform) {
+ this.processAcroForm(node);
} else if (!node._span) {
throw new Error(`Unrecognized document structure: ${stringifyNode(node)}`);
}
@@ -954,7 +956,7 @@ class LayoutBuilder {
}
}
- // leafs (texts)
+ // leafs (texts, acroform))
processLeaf(node) {
let line = this.buildNextLine(node);
if (line && (node.tocItem || node.id)) {
@@ -1033,7 +1035,7 @@ class LayoutBuilder {
let inline = textNode._inlines.shift();
isForceContinue = false;
- if (!inline.noWrap && inline.text.length > 1 && inline.width > line.getAvailableWidth()) {
+ if (!inline.noWrap && inline.text && inline.text.length > 1 && inline.width > line.getAvailableWidth()) {
let widthPerChar = inline.width / inline.text.length;
let maxChars = Math.floor(line.getAvailableWidth() / widthPerChar);
if (maxChars < 1) {
@@ -1084,6 +1086,13 @@ class LayoutBuilder {
node.positions.push(position);
}
+ processAcroForm (node) {
+ let availableWidth = this.writer.context().availableWidth;
+ let position = this.writer.addAcroForm(node);
+ node.positions.push(position);
+ node.availableWidth = availableWidth;
+ }
+
processAttachment(node) {
let position = this.writer.addAttachment(node);
node.positions.push(position);
diff --git a/src/Line.js b/src/Line.js
index 7ff24511f..293dc28b1 100644
--- a/src/Line.js
+++ b/src/Line.js
@@ -33,13 +33,7 @@ class Line {
* @returns {number}
*/
getHeight() {
- let max = 0;
-
- this.inlines.forEach(item => {
- max = Math.max(max, item.height || 0);
- });
-
- return max;
+ return Math.max(...this.inlines.map(item => item.height || 0));
}
/**
@@ -49,7 +43,7 @@ class Line {
let y = 0;
this.inlines.forEach(inline => {
- y = Math.max(y, inline.font.ascender / 1000 * inline.fontSize);
+ y = Math.max(y, inline.acroform ? inline.height : inline.font.ascender / 1000 * inline.fontSize);
});
return y;
diff --git a/src/PDFDocument.js b/src/PDFDocument.js
index 90781199d..0c873d542 100644
--- a/src/PDFDocument.js
+++ b/src/PDFDocument.js
@@ -13,7 +13,7 @@ const typeName = (bold, italics) => {
};
class PDFDocument extends PDFKit {
- constructor(fonts = {}, images = {}, patterns = {}, attachments = {}, options = {}, virtualfs = null) {
+ constructor(fonts = {}, images = {}, patterns = {}, attachments = {}, options = {}, virtualfs = null, subsetFonts = true) {
super(options);
this.fonts = {};
@@ -43,6 +43,7 @@ class PDFDocument extends PDFKit {
this.images = images;
this.attachments = attachments;
this.virtualfs = virtualfs;
+ this.subsetFonts = subsetFonts; //TODO maybe automatically set this flag
}
getFontType(bold, italics) {
@@ -76,7 +77,9 @@ class PDFDocument extends PDFKit {
def[0] = this.virtualfs.readFileSync(def[0]);
}
+
this.fontCache[familyName][type] = this.font(...def)._font;
+
}
return this.fontCache[familyName][type];
@@ -171,4 +174,5 @@ class PDFDocument extends PDFKit {
}
}
+
export default PDFDocument;
diff --git a/src/PageElementWriter.js b/src/PageElementWriter.js
index 97fc2047c..af331e788 100644
--- a/src/PageElementWriter.js
+++ b/src/PageElementWriter.js
@@ -45,6 +45,10 @@ class PageElementWriter extends ElementWriter {
return this._fitOnPage(() => super.addAttachment(attachment, index));
}
+ addAcroForm(node, index) {
+ return this._fitOnPage(() => super.addAcroForm(node, index));
+ }
+
addVector(vector, ignoreContextX, ignoreContextY, index, forcePage) {
return super.addVector(vector, ignoreContextX, ignoreContextY, index, forcePage);
}
diff --git a/src/Printer.js b/src/Printer.js
index ca3798960..2a3192d90 100644
--- a/src/Printer.js
+++ b/src/Printer.js
@@ -85,7 +85,7 @@ class PdfPrinter {
font: null
};
- this.pdfKitDoc = new PDFDocument(this.fontDescriptors, docDefinition.images, docDefinition.patterns, docDefinition.attachments, pdfOptions, this.virtualfs);
+ this.pdfKitDoc = new PDFDocument(this.fontDescriptors, docDefinition.images, docDefinition.patterns, docDefinition.attachments, pdfOptions, this.virtualfs, docDefinition.subsetFonts);
embedFiles(docDefinition, this.pdfKitDoc);
const builder = new LayoutBuilder(pageSize, normalizePageMargin(docDefinition.pageMargins), new SVGMeasure());
diff --git a/src/Renderer.js b/src/Renderer.js
index 9c1f323c7..d3b00c1c7 100644
--- a/src/Renderer.js
+++ b/src/Renderer.js
@@ -41,6 +41,7 @@ class Renderer {
constructor(pdfDocument, progressCallback) {
this.pdfDocument = pdfDocument;
this.progressCallback = progressCallback;
+ this.hasFormInit = false;
}
renderPages(pages) {
@@ -74,6 +75,9 @@ class Renderer {
case 'svg':
this.renderSVG(item.item);
break;
+ case 'acroform':
+ this.renderAcroForm(item.item);
+ break;
case 'attachment':
this.renderAttachment(item.item);
break;
@@ -143,43 +147,52 @@ class Renderer {
let inline = line.inlines[i];
let shiftToBaseline = lineHeight - ((inline.font.ascender / 1000) * inline.fontSize) - descent;
- if (inline._pageNodeRef) {
- preparePageNodeRefLine(inline._pageNodeRef, inline);
- }
+ if (inline.acroform) {
+ //TODO positioning issue
+ let shiftedY = y + (lineHeight - ((inline.font.ascender / 1000) * inline.height) - descent);
+ inline.y = shiftedY;
+ inline.x = x + inline.x;
- let options = {
- lineBreak: false,
- textWidth: inline.width,
- characterSpacing: inline.characterSpacing,
- wordCount: 1,
- link: inline.link
- };
+ this.renderAcroForm(inline);
+ } else {
+ if (inline._pageNodeRef) {
+ preparePageNodeRefLine(inline._pageNodeRef, inline);
+ }
- if (inline.linkToDestination) {
- options.goTo = inline.linkToDestination;
- }
+ let options = {
+ lineBreak: false,
+ textWidth: inline.width,
+ characterSpacing: inline.characterSpacing,
+ wordCount: 1,
+ link: inline.link
+ };
- if (line.id && i === 0) {
- options.destination = line.id;
- }
+ if (inline.linkToDestination) {
+ options.goTo = inline.linkToDestination;
+ }
- if (inline.fontFeatures) {
- options.features = inline.fontFeatures;
- }
+ if (line.id && i === 0) {
+ options.destination = line.id;
+ }
+
+ if (inline.fontFeatures) {
+ options.features = inline.fontFeatures;
+ }
- let opacity = isNumber(inline.opacity) ? inline.opacity : 1;
- this.pdfDocument.opacity(opacity);
- this.pdfDocument.fill(inline.color || 'black');
+ let opacity = isNumber(inline.opacity) ? inline.opacity : 1;
+ this.pdfDocument.opacity(opacity);
+ this.pdfDocument.fill(inline.color || 'black');
- this.pdfDocument._font = inline.font;
- this.pdfDocument.fontSize(inline.fontSize);
+ this.pdfDocument._font = inline.font;
+ this.pdfDocument.fontSize(inline.fontSize);
- let shiftedY = offsetText(y + shiftToBaseline, inline);
- this.pdfDocument.text(inline.text, x + inline.x, shiftedY, options);
+ let shiftedY = offsetText(y + shiftToBaseline, inline);
+ this.pdfDocument.text(inline.text, x + inline.x, shiftedY, options);
- if (inline.linkToPage) {
- this.pdfDocument.ref({ Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0] }).end();
- this.pdfDocument.annotate(x + inline.x, shiftedY, inline.width, inline.height, { Subtype: 'Link', Dest: [inline.linkToPage - 1, 'XYZ', null, null, null] });
+ if (inline.linkToPage) {
+ this.pdfDocument.ref({ Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0] }).end();
+ this.pdfDocument.annotate(x + inline.x, shiftedY, inline.width, inline.height, { Subtype: 'Link', Dest: [inline.linkToPage - 1, 'XYZ', null, null, null] });
+ }
}
}
@@ -280,6 +293,81 @@ class Renderer {
}
}
+ renderAcroForm(node) {
+ const { font, bold, italics } = node;
+ let { type, options } = node.acroform;
+
+ if (options == null) {
+ options = {};
+ }
+
+ if (this.hasFormInit == false) {
+ this.pdfDocument.initForm();
+ this.hasFormInit = true;
+ }
+
+ const setFont = () => {
+ if (typeof font === "string") {
+ this.pdfDocument._font = this.pdfDocument.provideFont(font, bold, italics);
+ } else {
+ this.pdfDocument._font = font;
+ }
+ // if (this.hasFormInit) {
+ // this.pdfDocument.addFontToAcroFormDict();
+ // }
+ };
+
+ const id = node.acroform.id;
+
+ if (id == null) {
+ throw new Error(`Acroform field ${id} requires an ID`);
+ }
+
+ let width = node.width || node.availableWidth || (!isNaN(node._calcWidth) && node._calcWidth) || node._minWidth;
+ if (node.width == '*') {
+ width = node.availableWidth;
+ }
+
+ if (width == null) {
+ throw new Error(`Form ${type} width is undefined`);
+ }
+
+ let resolvedType;
+
+ setFont();
+ switch (type) {
+ case "text":
+ case "formText":
+ resolvedType = "formText";
+ break;
+ case "button":
+ case "formPushButton":
+ resolvedType = "formPushButton";
+ break;
+ case "list":
+ case "formList":
+ resolvedType = "formList";
+ break;
+ case "combo":
+ case "formCombo":
+ resolvedType = "formCombo";
+ break;
+ case "checkbox":
+ case "formCheckbox":
+ resolvedType = "formCheckbox";
+ break;
+ case "radio":
+ case "formRadio":
+ case "formRadioButton":
+ resolvedType = "formRadioButton";
+ break;
+ default:
+ throw new Error(`Unrecognized acroform type: ${type}`);
+ }
+
+ this.pdfDocument[resolvedType](id, node.x, node.y, width, node.height, options);
+ }
+
renderImage(image) {
let opacity = isNumber(image.opacity) ? image.opacity : 1;
this.pdfDocument.opacity(opacity);
diff --git a/src/TextBreaker.js b/src/TextBreaker.js
index 4e4aff3df..c901277be 100644
--- a/src/TextBreaker.js
+++ b/src/TextBreaker.js
@@ -104,16 +104,20 @@ class TextBreaker {
let noWrap = StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'noWrap', false);
if (isObject(item)) {
- if (item._textRef && item._textRef._textNodeRef.text) {
- item.text = item._textRef._textNodeRef.text;
+ if (item.text) {
+ if (item._textRef && item._textRef._textNodeRef.text) {
+ item.text = item._textRef._textNodeRef.text;
+ }
+ words = splitWords(item.text, noWrap);
+ } else if (item.acroform) {
+ words = [item];
}
- words = splitWords(item.text, noWrap);
style = StyleContextStack.copyStyle(item);
} else {
words = splitWords(item, noWrap);
}
- if (lastWord && words.length) {
+ if (lastWord && words.length && !lastWord.acroform) {
let firstWord = getFirstWord(words, noWrap);
let wrapWords = splitWords(lastWord + firstWord, false);
@@ -123,9 +127,14 @@ class TextBreaker {
}
for (let i2 = 0, l2 = words.length; i2 < l2; i2++) {
- let result = {
- text: words[i2].text
- };
+ let result = {};
+ if (words[0].acroform) {
+ result = words[0];
+ } else {
+ result = {
+ text: words[i2].text
+ };
+ }
if (words[i2].lineEnd) {
result.lineEnd = true;
@@ -138,7 +147,11 @@ class TextBreaker {
lastWord = null;
if (i + 1 < l) {
- lastWord = getLastWord(words, noWrap);
+ if (words[0].acroform) {
+ lastWord = words[0];
+ } else {
+ lastWord = getLastWord(words, noWrap);
+ }
}
}
diff --git a/src/TextInlines.js b/src/TextInlines.js
index 878db5a0a..713555e79 100644
--- a/src/TextInlines.js
+++ b/src/TextInlines.js
@@ -121,7 +121,7 @@ class TextInlines {
item.link = StyleContextStack.getStyleProperty(item, styleContextStack, 'link', null);
item.linkToPage = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToPage', null);
item.linkToDestination = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToDestination', null);
- item.noWrap = StyleContextStack.getStyleProperty(item, styleContextStack, 'noWrap', null);
+ item.noWrap = item.acroform ? true: StyleContextStack.getStyleProperty(item, styleContextStack, 'noWrap', null);
item.opacity = StyleContextStack.getStyleProperty(item, styleContextStack, 'opacity', 1);
item.sup = StyleContextStack.getStyleProperty(item, styleContextStack, 'sup', false);
item.sub = StyleContextStack.getStyleProperty(item, styleContextStack, 'sub', false);
@@ -133,28 +133,33 @@ class TextInlines {
let lineHeight = StyleContextStack.getStyleProperty(item, styleContextStack, 'lineHeight', 1);
- item.width = this.widthOfText(item.text, item);
- item.height = item.font.lineHeight(item.fontSize) * lineHeight;
+ if (item.acroform) {
+ item.width = item.width || 25;
+ item.height = item.height || 15;
+ } else {
+ item.width = this.widthOfText(item.text, item);
+ item.height = item.font.lineHeight(item.fontSize) * lineHeight;
- if (!item.leadingCut) {
- item.leadingCut = 0;
- }
+ if (!item.leadingCut) {
+ item.leadingCut = 0;
+ }
- let preserveLeadingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);
- if (!preserveLeadingSpaces) {
- let leadingSpaces = item.text.match(LEADING);
- if (leadingSpaces) {
- item.leadingCut += this.widthOfText(leadingSpaces[0], item);
+ let preserveLeadingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);
+ if (!preserveLeadingSpaces) {
+ let leadingSpaces = item.text.match(LEADING);
+ if (leadingSpaces) {
+ item.leadingCut += this.widthOfText(leadingSpaces[0], item);
+ }
}
- }
- item.trailingCut = 0;
+ item.trailingCut = 0;
- let preserveTrailingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false);
- if (!preserveTrailingSpaces) {
- let trailingSpaces = item.text.match(TRAILING);
- if (trailingSpaces) {
- item.trailingCut = this.widthOfText(trailingSpaces[0], item);
+ let preserveTrailingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false);
+ if (!preserveTrailingSpaces) {
+ let trailingSpaces = item.text.match(TRAILING);
+ if (trailingSpaces) {
+ item.trailingCut = this.widthOfText(trailingSpaces[0], item);
+ }
}
}
}, this);