modules/acroform.js

  1. /* global jsPDF */
  2. /**
  3. * @license
  4. * Copyright (c) 2016 Alexander Weidt,
  5. * https://github.com/BiggA94
  6. *
  7. * Licensed under the MIT License. http://opensource.org/licenses/mit-license
  8. */
  9. /**
  10. * jsPDF AcroForm Plugin
  11. * @module AcroForm
  12. */
  13. import { jsPDF } from "../jspdf.js";
  14. var jsPDFAPI = jsPDF.API;
  15. var scaleFactor = 1;
  16. var pdfEscape = function(value) {
  17. return value
  18. .replace(/\\/g, "\\\\")
  19. .replace(/\(/g, "\\(")
  20. .replace(/\)/g, "\\)");
  21. };
  22. var pdfUnescape = function(value) {
  23. return value
  24. .replace(/\\\\/g, "\\")
  25. .replace(/\\\(/g, "(")
  26. .replace(/\\\)/g, ")");
  27. };
  28. var f2 = function(number) {
  29. return number.toFixed(2); // Ie, %.2f
  30. };
  31. var f5 = function(number) {
  32. return number.toFixed(5); // Ie, %.2f
  33. };
  34. jsPDFAPI.__acroform__ = {};
  35. var inherit = function(child, parent) {
  36. child.prototype = Object.create(parent.prototype);
  37. child.prototype.constructor = child;
  38. };
  39. var scale = function(x) {
  40. return x * scaleFactor;
  41. };
  42. var createFormXObject = function(formObject) {
  43. var xobj = new AcroFormXObject();
  44. var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
  45. var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
  46. xobj.BBox = [0, 0, Number(f2(width)), Number(f2(height))];
  47. return xobj;
  48. };
  49. /**
  50. * Bit-Operations
  51. */
  52. var setBit = (jsPDFAPI.__acroform__.setBit = function(number, bitPosition) {
  53. number = number || 0;
  54. bitPosition = bitPosition || 0;
  55. if (isNaN(number) || isNaN(bitPosition)) {
  56. throw new Error(
  57. "Invalid arguments passed to jsPDF.API.__acroform__.setBit"
  58. );
  59. }
  60. var bitMask = 1 << bitPosition;
  61. number |= bitMask;
  62. return number;
  63. });
  64. var clearBit = (jsPDFAPI.__acroform__.clearBit = function(number, bitPosition) {
  65. number = number || 0;
  66. bitPosition = bitPosition || 0;
  67. if (isNaN(number) || isNaN(bitPosition)) {
  68. throw new Error(
  69. "Invalid arguments passed to jsPDF.API.__acroform__.clearBit"
  70. );
  71. }
  72. var bitMask = 1 << bitPosition;
  73. number &= ~bitMask;
  74. return number;
  75. });
  76. var getBit = (jsPDFAPI.__acroform__.getBit = function(number, bitPosition) {
  77. if (isNaN(number) || isNaN(bitPosition)) {
  78. throw new Error(
  79. "Invalid arguments passed to jsPDF.API.__acroform__.getBit"
  80. );
  81. }
  82. return (number & (1 << bitPosition)) === 0 ? 0 : 1;
  83. });
  84. /*
  85. * Ff starts counting the bit position at 1 and not like javascript at 0
  86. */
  87. var getBitForPdf = (jsPDFAPI.__acroform__.getBitForPdf = function(
  88. number,
  89. bitPosition
  90. ) {
  91. if (isNaN(number) || isNaN(bitPosition)) {
  92. throw new Error(
  93. "Invalid arguments passed to jsPDF.API.__acroform__.getBitForPdf"
  94. );
  95. }
  96. return getBit(number, bitPosition - 1);
  97. });
  98. var setBitForPdf = (jsPDFAPI.__acroform__.setBitForPdf = function(
  99. number,
  100. bitPosition
  101. ) {
  102. if (isNaN(number) || isNaN(bitPosition)) {
  103. throw new Error(
  104. "Invalid arguments passed to jsPDF.API.__acroform__.setBitForPdf"
  105. );
  106. }
  107. return setBit(number, bitPosition - 1);
  108. });
  109. var clearBitForPdf = (jsPDFAPI.__acroform__.clearBitForPdf = function(
  110. number,
  111. bitPosition
  112. ) {
  113. if (isNaN(number) || isNaN(bitPosition)) {
  114. throw new Error(
  115. "Invalid arguments passed to jsPDF.API.__acroform__.clearBitForPdf"
  116. );
  117. }
  118. return clearBit(number, bitPosition - 1);
  119. });
  120. var calculateCoordinates = (jsPDFAPI.__acroform__.calculateCoordinates = function(
  121. args,
  122. scope
  123. ) {
  124. var getHorizontalCoordinate = scope.internal.getHorizontalCoordinate;
  125. var getVerticalCoordinate = scope.internal.getVerticalCoordinate;
  126. var x = args[0];
  127. var y = args[1];
  128. var w = args[2];
  129. var h = args[3];
  130. var coordinates = {};
  131. coordinates.lowerLeft_X = getHorizontalCoordinate(x) || 0;
  132. coordinates.lowerLeft_Y = getVerticalCoordinate(y + h) || 0;
  133. coordinates.upperRight_X = getHorizontalCoordinate(x + w) || 0;
  134. coordinates.upperRight_Y = getVerticalCoordinate(y) || 0;
  135. return [
  136. Number(f2(coordinates.lowerLeft_X)),
  137. Number(f2(coordinates.lowerLeft_Y)),
  138. Number(f2(coordinates.upperRight_X)),
  139. Number(f2(coordinates.upperRight_Y))
  140. ];
  141. });
  142. var calculateAppearanceStream = function(formObject) {
  143. if (formObject.appearanceStreamContent) {
  144. return formObject.appearanceStreamContent;
  145. }
  146. if (!formObject.V && !formObject.DV) {
  147. return;
  148. }
  149. // else calculate it
  150. var stream = [];
  151. var text = formObject._V || formObject.DV;
  152. var calcRes = calculateX(formObject, text);
  153. var fontKey = formObject.scope.internal.getFont(
  154. formObject.fontName,
  155. formObject.fontStyle
  156. ).id;
  157. //PDF 32000-1:2008, page 444
  158. stream.push("/Tx BMC");
  159. stream.push("q");
  160. stream.push("BT"); // Begin Text
  161. stream.push(formObject.scope.__private__.encodeColorString(formObject.color));
  162. stream.push("/" + fontKey + " " + f2(calcRes.fontSize) + " Tf");
  163. stream.push("1 0 0 1 0 0 Tm"); // Transformation Matrix
  164. stream.push(calcRes.text);
  165. stream.push("ET"); // End Text
  166. stream.push("Q");
  167. stream.push("EMC");
  168. var appearanceStreamContent = createFormXObject(formObject);
  169. appearanceStreamContent.scope = formObject.scope;
  170. appearanceStreamContent.stream = stream.join("\n");
  171. return appearanceStreamContent;
  172. };
  173. var calculateX = function(formObject, text) {
  174. var maxFontSize =
  175. formObject.fontSize === 0 ? formObject.maxFontSize : formObject.fontSize;
  176. var returnValue = {
  177. text: "",
  178. fontSize: ""
  179. };
  180. // Remove Brackets
  181. text = text.substr(0, 1) == "(" ? text.substr(1) : text;
  182. text =
  183. text.substr(text.length - 1) == ")"
  184. ? text.substr(0, text.length - 1)
  185. : text;
  186. // split into array of words
  187. var textSplit = text.split(" ");
  188. if (formObject.multiline) {
  189. textSplit = textSplit.map(word => word.split("\n"));
  190. } else {
  191. textSplit = textSplit.map(word => [word]);
  192. }
  193. var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
  194. var lineSpacing = 2;
  195. var borderPadding = 2;
  196. var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
  197. height = height < 0 ? -height : height;
  198. var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
  199. width = width < 0 ? -width : width;
  200. var isSmallerThanWidth = function(i, lastLine, fontSize) {
  201. if (i + 1 < textSplit.length) {
  202. var tmp = lastLine + " " + textSplit[i + 1][0];
  203. var TextWidth = calculateFontSpace(tmp, formObject, fontSize).width;
  204. var FieldWidth = width - 2 * borderPadding;
  205. return TextWidth <= FieldWidth;
  206. } else {
  207. return false;
  208. }
  209. };
  210. fontSize++;
  211. FontSize: while (fontSize > 0) {
  212. text = "";
  213. fontSize--;
  214. var textHeight = calculateFontSpace("3", formObject, fontSize).height;
  215. var startY = formObject.multiline
  216. ? height - fontSize
  217. : (height - textHeight) / 2;
  218. startY += lineSpacing;
  219. var startX;
  220. var lastY = startY;
  221. var firstWordInLine = 0,
  222. lastWordInLine = 0;
  223. var lastLength;
  224. var currWord = 0;
  225. if (fontSize <= 0) {
  226. // In case, the Text doesn't fit at all
  227. fontSize = 12;
  228. text = "(...) Tj\n";
  229. text +=
  230. "% Width of Text: " +
  231. calculateFontSpace(text, formObject, fontSize).width +
  232. ", FieldWidth:" +
  233. width +
  234. "\n";
  235. break;
  236. }
  237. var lastLine = "";
  238. var lineCount = 0;
  239. Line: for (var i = 0; i < textSplit.length; i++) {
  240. if (textSplit.hasOwnProperty(i)) {
  241. let isWithNewLine = false;
  242. if (textSplit[i].length !== 1 && currWord !== textSplit[i].length - 1) {
  243. if (
  244. (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing >
  245. height
  246. ) {
  247. continue FontSize;
  248. }
  249. lastLine += textSplit[i][currWord];
  250. isWithNewLine = true;
  251. lastWordInLine = i;
  252. i--;
  253. } else {
  254. lastLine += textSplit[i][currWord] + " ";
  255. lastLine =
  256. lastLine.substr(lastLine.length - 1) == " "
  257. ? lastLine.substr(0, lastLine.length - 1)
  258. : lastLine;
  259. var key = parseInt(i);
  260. var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
  261. var isLastWord = i >= textSplit.length - 1;
  262. if (nextLineIsSmaller && !isLastWord) {
  263. lastLine += " ";
  264. currWord = 0;
  265. continue; // Line
  266. } else if (!nextLineIsSmaller && !isLastWord) {
  267. if (!formObject.multiline) {
  268. continue FontSize;
  269. } else {
  270. if (
  271. (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing >
  272. height
  273. ) {
  274. // If the Text is higher than the
  275. // FieldObject
  276. continue FontSize;
  277. }
  278. lastWordInLine = key;
  279. // go on
  280. }
  281. } else if (isLastWord) {
  282. lastWordInLine = key;
  283. } else {
  284. if (
  285. formObject.multiline &&
  286. (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing >
  287. height
  288. ) {
  289. // If the Text is higher than the FieldObject
  290. continue FontSize;
  291. }
  292. }
  293. }
  294. // Remove last blank
  295. var line = "";
  296. for (var x = firstWordInLine; x <= lastWordInLine; x++) {
  297. var currLine = textSplit[x];
  298. if (formObject.multiline) {
  299. if (x === lastWordInLine) {
  300. line += currLine[currWord] + " ";
  301. currWord = (currWord + 1) % currLine.length;
  302. continue;
  303. }
  304. if (x === firstWordInLine) {
  305. line += currLine[currLine.length - 1] + " ";
  306. continue;
  307. }
  308. }
  309. line += currLine[0] + " ";
  310. }
  311. // Remove last blank
  312. line =
  313. line.substr(line.length - 1) == " "
  314. ? line.substr(0, line.length - 1)
  315. : line;
  316. // lastLength -= blankSpace.width;
  317. lastLength = calculateFontSpace(line, formObject, fontSize).width;
  318. // Calculate startX
  319. switch (formObject.textAlign) {
  320. case "right":
  321. startX = width - lastLength - borderPadding;
  322. break;
  323. case "center":
  324. startX = (width - lastLength) / 2;
  325. break;
  326. case "left":
  327. default:
  328. startX = borderPadding;
  329. break;
  330. }
  331. text += f2(startX) + " " + f2(lastY) + " Td\n";
  332. text += "(" + pdfEscape(line) + ") Tj\n";
  333. // reset X in PDF
  334. text += -f2(startX) + " 0 Td\n";
  335. // After a Line, adjust y position
  336. lastY = -(fontSize + lineSpacing);
  337. // Reset for next iteration step
  338. lastLength = 0;
  339. firstWordInLine = isWithNewLine ? lastWordInLine : lastWordInLine + 1;
  340. lineCount++;
  341. lastLine = "";
  342. continue Line;
  343. }
  344. }
  345. break;
  346. }
  347. returnValue.text = text;
  348. returnValue.fontSize = fontSize;
  349. return returnValue;
  350. };
  351. /**
  352. * Small workaround for calculating the TextMetric approximately.
  353. *
  354. * @param text
  355. * @param fontsize
  356. * @returns {TextMetrics} (Has Height and Width)
  357. */
  358. var calculateFontSpace = function(text, formObject, fontSize) {
  359. var font = formObject.scope.internal.getFont(
  360. formObject.fontName,
  361. formObject.fontStyle
  362. );
  363. var width =
  364. formObject.scope.getStringUnitWidth(text, {
  365. font: font,
  366. fontSize: parseFloat(fontSize),
  367. charSpace: 0
  368. }) * parseFloat(fontSize);
  369. var height =
  370. formObject.scope.getStringUnitWidth("3", {
  371. font: font,
  372. fontSize: parseFloat(fontSize),
  373. charSpace: 0
  374. }) *
  375. parseFloat(fontSize) *
  376. 1.5;
  377. return { height: height, width: width };
  378. };
  379. var acroformPluginTemplate = {
  380. fields: [],
  381. xForms: [],
  382. /**
  383. * acroFormDictionaryRoot contains information about the AcroForm
  384. * Dictionary 0: The Event-Token, the AcroFormDictionaryCallback has
  385. * 1: The Object ID of the Root
  386. */
  387. acroFormDictionaryRoot: null,
  388. /**
  389. * After the PDF gets evaluated, the reference to the root has to be
  390. * reset, this indicates, whether the root has already been printed
  391. * out
  392. */
  393. printedOut: false,
  394. internal: null,
  395. isInitialized: false
  396. };
  397. var annotReferenceCallback = function(scope) {
  398. //set objId to undefined and force it to get a new objId on buildDocument
  399. scope.internal.acroformPlugin.acroFormDictionaryRoot.objId = undefined;
  400. var fields = scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields;
  401. for (var i in fields) {
  402. if (fields.hasOwnProperty(i)) {
  403. var formObject = fields[i];
  404. //set objId to undefined and force it to get a new objId on buildDocument
  405. formObject.objId = undefined;
  406. // add Annot Reference!
  407. if (formObject.hasAnnotation) {
  408. // If theres an Annotation Widget in the Form Object, put the
  409. // Reference in the /Annot array
  410. createAnnotationReference(formObject, scope);
  411. }
  412. }
  413. }
  414. };
  415. var putForm = function(formObject) {
  416. if (formObject.scope.internal.acroformPlugin.printedOut) {
  417. formObject.scope.internal.acroformPlugin.printedOut = false;
  418. formObject.scope.internal.acroformPlugin.acroFormDictionaryRoot = null;
  419. }
  420. formObject.scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields.push(
  421. formObject
  422. );
  423. };
  424. /**
  425. * Create the Reference to the widgetAnnotation, so that it gets referenced
  426. * in the Annot[] int the+ (Requires the Annotation Plugin)
  427. */
  428. var createAnnotationReference = function(object, scope) {
  429. var options = {
  430. type: "reference",
  431. object: object
  432. };
  433. var findEntry = function(entry) {
  434. return entry.type === options.type && entry.object === options.object;
  435. };
  436. if (
  437. scope.internal
  438. .getPageInfo(object.page)
  439. .pageContext.annotations.find(findEntry) === undefined
  440. ) {
  441. scope.internal
  442. .getPageInfo(object.page)
  443. .pageContext.annotations.push(options);
  444. }
  445. };
  446. // Callbacks
  447. var putCatalogCallback = function(scope) {
  448. // Put reference to AcroForm to DocumentCatalog
  449. if (
  450. typeof scope.internal.acroformPlugin.acroFormDictionaryRoot !== "undefined"
  451. ) {
  452. // for safety, shouldn't normally be the case
  453. scope.internal.write(
  454. "/AcroForm " +
  455. scope.internal.acroformPlugin.acroFormDictionaryRoot.objId +
  456. " " +
  457. 0 +
  458. " R"
  459. );
  460. } else {
  461. throw new Error("putCatalogCallback: Root missing.");
  462. }
  463. };
  464. /**
  465. * Adds /Acroform X 0 R to Document Catalog, and creates the AcroForm
  466. * Dictionary
  467. */
  468. var AcroFormDictionaryCallback = function(scope) {
  469. // Remove event
  470. scope.internal.events.unsubscribe(
  471. scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID
  472. );
  473. delete scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID;
  474. scope.internal.acroformPlugin.printedOut = true;
  475. };
  476. /**
  477. * Creates the single Fields and writes them into the Document
  478. *
  479. * If fieldArray is set, use the fields that are inside it instead of the
  480. * fields from the AcroRoot (for the FormXObjects...)
  481. */
  482. var createFieldCallback = function(fieldArray, scope) {
  483. var standardFields = !fieldArray;
  484. if (!fieldArray) {
  485. // in case there is no fieldArray specified, we want to print out
  486. // the Fields of the AcroForm
  487. // Print out Root
  488. scope.internal.newObjectDeferredBegin(
  489. scope.internal.acroformPlugin.acroFormDictionaryRoot.objId,
  490. true
  491. );
  492. scope.internal.acroformPlugin.acroFormDictionaryRoot.putStream();
  493. }
  494. fieldArray =
  495. fieldArray || scope.internal.acroformPlugin.acroFormDictionaryRoot.Kids;
  496. for (var i in fieldArray) {
  497. if (fieldArray.hasOwnProperty(i)) {
  498. var fieldObject = fieldArray[i];
  499. var keyValueList = [];
  500. var oldRect = fieldObject.Rect;
  501. if (fieldObject.Rect) {
  502. fieldObject.Rect = calculateCoordinates(fieldObject.Rect, scope);
  503. }
  504. // Start Writing the Object
  505. scope.internal.newObjectDeferredBegin(fieldObject.objId, true);
  506. fieldObject.DA = AcroFormAppearance.createDefaultAppearanceStream(
  507. fieldObject
  508. );
  509. if (
  510. typeof fieldObject === "object" &&
  511. typeof fieldObject.getKeyValueListForStream === "function"
  512. ) {
  513. keyValueList = fieldObject.getKeyValueListForStream();
  514. }
  515. fieldObject.Rect = oldRect;
  516. if (
  517. fieldObject.hasAppearanceStream &&
  518. !fieldObject.appearanceStreamContent
  519. ) {
  520. // Calculate Appearance
  521. var appearance = calculateAppearanceStream(fieldObject);
  522. keyValueList.push({ key: "AP", value: "<</N " + appearance + ">>" });
  523. scope.internal.acroformPlugin.xForms.push(appearance);
  524. }
  525. // Assume AppearanceStreamContent is a Array with N,R,D (at least
  526. // one of them!)
  527. if (fieldObject.appearanceStreamContent) {
  528. var appearanceStreamString = "";
  529. // Iterate over N,R and D
  530. for (var k in fieldObject.appearanceStreamContent) {
  531. if (fieldObject.appearanceStreamContent.hasOwnProperty(k)) {
  532. var value = fieldObject.appearanceStreamContent[k];
  533. appearanceStreamString += "/" + k + " ";
  534. appearanceStreamString += "<<";
  535. if (Object.keys(value).length >= 1 || Array.isArray(value)) {
  536. // appearanceStream is an Array or Object!
  537. for (var i in value) {
  538. if (value.hasOwnProperty(i)) {
  539. var obj = value[i];
  540. if (typeof obj === "function") {
  541. // if Function is referenced, call it in order
  542. // to get the FormXObject
  543. obj = obj.call(scope, fieldObject);
  544. }
  545. appearanceStreamString += "/" + i + " " + obj + " ";
  546. // In case the XForm is already used, e.g. OffState
  547. // of CheckBoxes, don't add it
  548. if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0))
  549. scope.internal.acroformPlugin.xForms.push(obj);
  550. }
  551. }
  552. } else {
  553. obj = value;
  554. if (typeof obj === "function") {
  555. // if Function is referenced, call it in order to
  556. // get the FormXObject
  557. obj = obj.call(scope, fieldObject);
  558. }
  559. appearanceStreamString += "/" + i + " " + obj;
  560. if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0))
  561. scope.internal.acroformPlugin.xForms.push(obj);
  562. }
  563. appearanceStreamString += ">>";
  564. }
  565. }
  566. // appearance stream is a normal Object..
  567. keyValueList.push({
  568. key: "AP",
  569. value: "<<\n" + appearanceStreamString + ">>"
  570. });
  571. }
  572. scope.internal.putStream({
  573. additionalKeyValues: keyValueList,
  574. objectId: fieldObject.objId
  575. });
  576. scope.internal.out("endobj");
  577. }
  578. }
  579. if (standardFields) {
  580. createXFormObjectCallback(scope.internal.acroformPlugin.xForms, scope);
  581. }
  582. };
  583. var createXFormObjectCallback = function(fieldArray, scope) {
  584. for (var i in fieldArray) {
  585. if (fieldArray.hasOwnProperty(i)) {
  586. var key = i;
  587. var fieldObject = fieldArray[i];
  588. // Start Writing the Object
  589. scope.internal.newObjectDeferredBegin(fieldObject.objId, true);
  590. if (
  591. typeof fieldObject === "object" &&
  592. typeof fieldObject.putStream === "function"
  593. ) {
  594. fieldObject.putStream();
  595. }
  596. delete fieldArray[key];
  597. }
  598. }
  599. };
  600. var initializeAcroForm = function(scope, formObject) {
  601. formObject.scope = scope;
  602. if (
  603. scope.internal !== undefined &&
  604. (scope.internal.acroformPlugin === undefined ||
  605. scope.internal.acroformPlugin.isInitialized === false)
  606. ) {
  607. AcroFormField.FieldNum = 0;
  608. scope.internal.acroformPlugin = JSON.parse(
  609. JSON.stringify(acroformPluginTemplate)
  610. );
  611. if (scope.internal.acroformPlugin.acroFormDictionaryRoot) {
  612. throw new Error("Exception while creating AcroformDictionary");
  613. }
  614. scaleFactor = scope.internal.scaleFactor;
  615. // The Object Number of the AcroForm Dictionary
  616. scope.internal.acroformPlugin.acroFormDictionaryRoot = new AcroFormDictionary();
  617. scope.internal.acroformPlugin.acroFormDictionaryRoot.scope = scope;
  618. // add Callback for creating the AcroForm Dictionary
  619. scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID = scope.internal.events.subscribe(
  620. "postPutResources",
  621. function() {
  622. AcroFormDictionaryCallback(scope);
  623. }
  624. );
  625. scope.internal.events.subscribe("buildDocument", function() {
  626. annotReferenceCallback(scope);
  627. }); // buildDocument
  628. // Register event, that is triggered when the DocumentCatalog is
  629. // written, in order to add /AcroForm
  630. scope.internal.events.subscribe("putCatalog", function() {
  631. putCatalogCallback(scope);
  632. });
  633. // Register event, that creates all Fields
  634. scope.internal.events.subscribe("postPutPages", function(fieldArray) {
  635. createFieldCallback(fieldArray, scope);
  636. });
  637. scope.internal.acroformPlugin.isInitialized = true;
  638. }
  639. };
  640. //PDF 32000-1:2008, page 26, 7.3.6
  641. var arrayToPdfArray = (jsPDFAPI.__acroform__.arrayToPdfArray = function(
  642. array,
  643. objId,
  644. scope
  645. ) {
  646. var encryptor = function(data) {
  647. return data;
  648. };
  649. if (Array.isArray(array)) {
  650. var content = "[";
  651. for (var i = 0; i < array.length; i++) {
  652. if (i !== 0) {
  653. content += " ";
  654. }
  655. switch (typeof array[i]) {
  656. case "boolean":
  657. case "number":
  658. case "object":
  659. content += array[i].toString();
  660. break;
  661. case "string":
  662. if (array[i].substr(0, 1) !== "/") {
  663. if (typeof objId !== "undefined" && scope)
  664. encryptor = scope.internal.getEncryptor(objId);
  665. content += "(" + pdfEscape(encryptor(array[i].toString())) + ")";
  666. } else {
  667. content += array[i].toString();
  668. }
  669. break;
  670. }
  671. }
  672. content += "]";
  673. return content;
  674. }
  675. throw new Error(
  676. "Invalid argument passed to jsPDF.__acroform__.arrayToPdfArray"
  677. );
  678. });
  679. function getMatches(string, regex, index) {
  680. index || (index = 1); // default to the first capturing group
  681. var matches = [];
  682. var match;
  683. while ((match = regex.exec(string))) {
  684. matches.push(match[index]);
  685. }
  686. return matches;
  687. }
  688. var pdfArrayToStringArray = function(array) {
  689. var result = [];
  690. if (typeof array === "string") {
  691. result = getMatches(array, /\((.*?)\)/g);
  692. }
  693. return result;
  694. };
  695. var toPdfString = function(string, objId, scope) {
  696. var encryptor = function(data) {
  697. return data;
  698. };
  699. if (typeof objId !== "undefined" && scope)
  700. encryptor = scope.internal.getEncryptor(objId);
  701. string = string || "";
  702. string.toString();
  703. string = "(" + pdfEscape(encryptor(string)) + ")";
  704. return string;
  705. };
  706. // ##########################
  707. // Classes
  708. // ##########################
  709. /**
  710. * @class AcroFormPDFObject
  711. * @classdesc A AcroFormPDFObject
  712. */
  713. var AcroFormPDFObject = function() {
  714. this._objId = undefined;
  715. this._scope = undefined;
  716. /**
  717. * @name AcroFormPDFObject#objId
  718. * @type {any}
  719. */
  720. Object.defineProperty(this, "objId", {
  721. get: function() {
  722. if (typeof this._objId === "undefined") {
  723. if (typeof this.scope === "undefined") {
  724. return undefined;
  725. }
  726. this._objId = this.scope.internal.newObjectDeferred();
  727. }
  728. return this._objId;
  729. },
  730. set: function(value) {
  731. this._objId = value;
  732. }
  733. });
  734. Object.defineProperty(this, "scope", {
  735. value: this._scope,
  736. writable: true
  737. });
  738. };
  739. /**
  740. * @function AcroFormPDFObject.toString
  741. */
  742. AcroFormPDFObject.prototype.toString = function() {
  743. return this.objId + " 0 R";
  744. };
  745. AcroFormPDFObject.prototype.putStream = function() {
  746. var keyValueList = this.getKeyValueListForStream();
  747. this.scope.internal.putStream({
  748. data: this.stream,
  749. additionalKeyValues: keyValueList,
  750. objectId: this.objId
  751. });
  752. this.scope.internal.out("endobj");
  753. };
  754. /**
  755. * Returns an key-value-List of all non-configurable Variables from the Object
  756. *
  757. * @name getKeyValueListForStream
  758. * @returns {string}
  759. */
  760. AcroFormPDFObject.prototype.getKeyValueListForStream = function() {
  761. var keyValueList = [];
  762. var keys = Object.getOwnPropertyNames(this).filter(function(key) {
  763. return (
  764. key != "content" &&
  765. key != "appearanceStreamContent" &&
  766. key != "scope" &&
  767. key != "objId" &&
  768. key.substring(0, 1) != "_"
  769. );
  770. });
  771. for (var i in keys) {
  772. if (Object.getOwnPropertyDescriptor(this, keys[i]).configurable === false) {
  773. var key = keys[i];
  774. var value = this[key];
  775. if (value) {
  776. if (Array.isArray(value)) {
  777. keyValueList.push({
  778. key: key,
  779. value: arrayToPdfArray(value, this.objId, this.scope)
  780. });
  781. } else if (value instanceof AcroFormPDFObject) {
  782. // In case it is a reference to another PDFObject,
  783. // take the reference number
  784. value.scope = this.scope;
  785. keyValueList.push({ key: key, value: value.objId + " 0 R" });
  786. } else if (typeof value !== "function") {
  787. keyValueList.push({ key: key, value: value });
  788. }
  789. }
  790. }
  791. }
  792. return keyValueList;
  793. };
  794. var AcroFormXObject = function() {
  795. AcroFormPDFObject.call(this);
  796. Object.defineProperty(this, "Type", {
  797. value: "/XObject",
  798. configurable: false,
  799. writable: true
  800. });
  801. Object.defineProperty(this, "Subtype", {
  802. value: "/Form",
  803. configurable: false,
  804. writable: true
  805. });
  806. Object.defineProperty(this, "FormType", {
  807. value: 1,
  808. configurable: false,
  809. writable: true
  810. });
  811. var _BBox = [];
  812. Object.defineProperty(this, "BBox", {
  813. configurable: false,
  814. get: function() {
  815. return _BBox;
  816. },
  817. set: function(value) {
  818. _BBox = value;
  819. }
  820. });
  821. Object.defineProperty(this, "Resources", {
  822. value: "2 0 R",
  823. configurable: false,
  824. writable: true
  825. });
  826. var _stream;
  827. Object.defineProperty(this, "stream", {
  828. enumerable: false,
  829. configurable: true,
  830. set: function(value) {
  831. _stream = value.trim();
  832. },
  833. get: function() {
  834. if (_stream) {
  835. return _stream;
  836. } else {
  837. return null;
  838. }
  839. }
  840. });
  841. };
  842. inherit(AcroFormXObject, AcroFormPDFObject);
  843. var AcroFormDictionary = function() {
  844. AcroFormPDFObject.call(this);
  845. var _Kids = [];
  846. Object.defineProperty(this, "Kids", {
  847. enumerable: false,
  848. configurable: true,
  849. get: function() {
  850. if (_Kids.length > 0) {
  851. return _Kids;
  852. } else {
  853. return undefined;
  854. }
  855. }
  856. });
  857. Object.defineProperty(this, "Fields", {
  858. enumerable: false,
  859. configurable: false,
  860. get: function() {
  861. return _Kids;
  862. }
  863. });
  864. // Default Appearance
  865. var _DA;
  866. Object.defineProperty(this, "DA", {
  867. enumerable: false,
  868. configurable: false,
  869. get: function() {
  870. if (!_DA) {
  871. return undefined;
  872. }
  873. var encryptor = function(data) {
  874. return data;
  875. };
  876. if (this.scope) encryptor = this.scope.internal.getEncryptor(this.objId);
  877. return "(" + pdfEscape(encryptor(_DA)) + ")";
  878. },
  879. set: function(value) {
  880. _DA = value;
  881. }
  882. });
  883. };
  884. inherit(AcroFormDictionary, AcroFormPDFObject);
  885. /**
  886. * The Field Object contains the Variables, that every Field needs
  887. *
  888. * @class AcroFormField
  889. * @classdesc An AcroForm FieldObject
  890. */
  891. var AcroFormField = function() {
  892. AcroFormPDFObject.call(this);
  893. //Annotation-Flag See Table 165
  894. var _F = 4;
  895. Object.defineProperty(this, "F", {
  896. enumerable: false,
  897. configurable: false,
  898. get: function() {
  899. return _F;
  900. },
  901. set: function(value) {
  902. if (!isNaN(value)) {
  903. _F = value;
  904. } else {
  905. throw new Error(
  906. 'Invalid value "' + value + '" for attribute F supplied.'
  907. );
  908. }
  909. }
  910. });
  911. /**
  912. * (PDF 1.2) If set, print the annotation when the page is printed. If clear, never print the annotation, regardless of wether is is displayed on the screen.
  913. * NOTE 2 This can be useful for annotations representing interactive pushbuttons, which would serve no meaningful purpose on the printed page.
  914. *
  915. * @name AcroFormField#showWhenPrinted
  916. * @default true
  917. * @type {boolean}
  918. */
  919. Object.defineProperty(this, "showWhenPrinted", {
  920. enumerable: true,
  921. configurable: true,
  922. get: function() {
  923. return Boolean(getBitForPdf(_F, 3));
  924. },
  925. set: function(value) {
  926. if (Boolean(value) === true) {
  927. this.F = setBitForPdf(_F, 3);
  928. } else {
  929. this.F = clearBitForPdf(_F, 3);
  930. }
  931. }
  932. });
  933. var _Ff = 0;
  934. Object.defineProperty(this, "Ff", {
  935. enumerable: false,
  936. configurable: false,
  937. get: function() {
  938. return _Ff;
  939. },
  940. set: function(value) {
  941. if (!isNaN(value)) {
  942. _Ff = value;
  943. } else {
  944. throw new Error(
  945. 'Invalid value "' + value + '" for attribute Ff supplied.'
  946. );
  947. }
  948. }
  949. });
  950. var _Rect = [];
  951. Object.defineProperty(this, "Rect", {
  952. enumerable: false,
  953. configurable: false,
  954. get: function() {
  955. if (_Rect.length === 0) {
  956. return undefined;
  957. }
  958. return _Rect;
  959. },
  960. set: function(value) {
  961. if (typeof value !== "undefined") {
  962. _Rect = value;
  963. } else {
  964. _Rect = [];
  965. }
  966. }
  967. });
  968. /**
  969. * The x-position of the field.
  970. *
  971. * @name AcroFormField#x
  972. * @default null
  973. * @type {number}
  974. */
  975. Object.defineProperty(this, "x", {
  976. enumerable: true,
  977. configurable: true,
  978. get: function() {
  979. if (!_Rect || isNaN(_Rect[0])) {
  980. return 0;
  981. }
  982. return _Rect[0];
  983. },
  984. set: function(value) {
  985. _Rect[0] = value;
  986. }
  987. });
  988. /**
  989. * The y-position of the field.
  990. *
  991. * @name AcroFormField#y
  992. * @default null
  993. * @type {number}
  994. */
  995. Object.defineProperty(this, "y", {
  996. enumerable: true,
  997. configurable: true,
  998. get: function() {
  999. if (!_Rect || isNaN(_Rect[1])) {
  1000. return 0;
  1001. }
  1002. return _Rect[1];
  1003. },
  1004. set: function(value) {
  1005. _Rect[1] = value;
  1006. }
  1007. });
  1008. /**
  1009. * The width of the field.
  1010. *
  1011. * @name AcroFormField#width
  1012. * @default null
  1013. * @type {number}
  1014. */
  1015. Object.defineProperty(this, "width", {
  1016. enumerable: true,
  1017. configurable: true,
  1018. get: function() {
  1019. if (!_Rect || isNaN(_Rect[2])) {
  1020. return 0;
  1021. }
  1022. return _Rect[2];
  1023. },
  1024. set: function(value) {
  1025. _Rect[2] = value;
  1026. }
  1027. });
  1028. /**
  1029. * The height of the field.
  1030. *
  1031. * @name AcroFormField#height
  1032. * @default null
  1033. * @type {number}
  1034. */
  1035. Object.defineProperty(this, "height", {
  1036. enumerable: true,
  1037. configurable: true,
  1038. get: function() {
  1039. if (!_Rect || isNaN(_Rect[3])) {
  1040. return 0;
  1041. }
  1042. return _Rect[3];
  1043. },
  1044. set: function(value) {
  1045. _Rect[3] = value;
  1046. }
  1047. });
  1048. var _FT = "";
  1049. Object.defineProperty(this, "FT", {
  1050. enumerable: true,
  1051. configurable: false,
  1052. get: function() {
  1053. return _FT;
  1054. },
  1055. set: function(value) {
  1056. switch (value) {
  1057. case "/Btn":
  1058. case "/Tx":
  1059. case "/Ch":
  1060. case "/Sig":
  1061. _FT = value;
  1062. break;
  1063. default:
  1064. throw new Error(
  1065. 'Invalid value "' + value + '" for attribute FT supplied.'
  1066. );
  1067. }
  1068. }
  1069. });
  1070. var _T = null;
  1071. Object.defineProperty(this, "T", {
  1072. enumerable: true,
  1073. configurable: false,
  1074. get: function() {
  1075. if (!_T || _T.length < 1) {
  1076. // In case of a Child from a Radio´Group, you don't need a FieldName
  1077. if (this instanceof AcroFormChildClass) {
  1078. return undefined;
  1079. }
  1080. _T = "FieldObject" + AcroFormField.FieldNum++;
  1081. }
  1082. var encryptor = function(data) {
  1083. return data;
  1084. };
  1085. if (this.scope) encryptor = this.scope.internal.getEncryptor(this.objId);
  1086. return "(" + pdfEscape(encryptor(_T)) + ")";
  1087. },
  1088. set: function(value) {
  1089. _T = value.toString();
  1090. }
  1091. });
  1092. /**
  1093. * (Optional) The partial field name (see 12.7.3.2, “Field Names”).
  1094. *
  1095. * @name AcroFormField#fieldName
  1096. * @default null
  1097. * @type {string}
  1098. */
  1099. Object.defineProperty(this, "fieldName", {
  1100. configurable: true,
  1101. enumerable: true,
  1102. get: function() {
  1103. return _T;
  1104. },
  1105. set: function(value) {
  1106. _T = value;
  1107. }
  1108. });
  1109. var _fontName = "helvetica";
  1110. /**
  1111. * The fontName of the font to be used.
  1112. *
  1113. * @name AcroFormField#fontName
  1114. * @default 'helvetica'
  1115. * @type {string}
  1116. */
  1117. Object.defineProperty(this, "fontName", {
  1118. enumerable: true,
  1119. configurable: true,
  1120. get: function() {
  1121. return _fontName;
  1122. },
  1123. set: function(value) {
  1124. _fontName = value;
  1125. }
  1126. });
  1127. var _fontStyle = "normal";
  1128. /**
  1129. * The fontStyle of the font to be used.
  1130. *
  1131. * @name AcroFormField#fontStyle
  1132. * @default 'normal'
  1133. * @type {string}
  1134. */
  1135. Object.defineProperty(this, "fontStyle", {
  1136. enumerable: true,
  1137. configurable: true,
  1138. get: function() {
  1139. return _fontStyle;
  1140. },
  1141. set: function(value) {
  1142. _fontStyle = value;
  1143. }
  1144. });
  1145. var _fontSize = 0;
  1146. /**
  1147. * The fontSize of the font to be used.
  1148. *
  1149. * @name AcroFormField#fontSize
  1150. * @default 0 (for auto)
  1151. * @type {number}
  1152. */
  1153. Object.defineProperty(this, "fontSize", {
  1154. enumerable: true,
  1155. configurable: true,
  1156. get: function() {
  1157. return _fontSize;
  1158. },
  1159. set: function(value) {
  1160. _fontSize = value;
  1161. }
  1162. });
  1163. var _maxFontSize = undefined;
  1164. /**
  1165. * The maximum fontSize of the font to be used.
  1166. *
  1167. * @name AcroFormField#maxFontSize
  1168. * @default 0 (for auto)
  1169. * @type {number}
  1170. */
  1171. Object.defineProperty(this, "maxFontSize", {
  1172. enumerable: true,
  1173. configurable: true,
  1174. get: function() {
  1175. if (_maxFontSize === undefined) {
  1176. // use the old default value here - the value is some kind of random as it depends on the scaleFactor (user unit)
  1177. // ("50" is transformed to the "user space" but then used in "pdf space")
  1178. return 50 / scaleFactor;
  1179. } else {
  1180. return _maxFontSize;
  1181. }
  1182. },
  1183. set: function(value) {
  1184. _maxFontSize = value;
  1185. }
  1186. });
  1187. var _color = "black";
  1188. /**
  1189. * The color of the text
  1190. *
  1191. * @name AcroFormField#color
  1192. * @default 'black'
  1193. * @type {string|rgba}
  1194. */
  1195. Object.defineProperty(this, "color", {
  1196. enumerable: true,
  1197. configurable: true,
  1198. get: function() {
  1199. return _color;
  1200. },
  1201. set: function(value) {
  1202. _color = value;
  1203. }
  1204. });
  1205. var _DA = "/F1 0 Tf 0 g";
  1206. // Defines the default appearance (Needed for variable Text)
  1207. Object.defineProperty(this, "DA", {
  1208. enumerable: true,
  1209. configurable: false,
  1210. get: function() {
  1211. if (
  1212. !_DA ||
  1213. this instanceof AcroFormChildClass ||
  1214. this instanceof AcroFormTextField
  1215. ) {
  1216. return undefined;
  1217. }
  1218. return toPdfString(_DA, this.objId, this.scope);
  1219. },
  1220. set: function(value) {
  1221. value = value.toString();
  1222. _DA = value;
  1223. }
  1224. });
  1225. var _DV = null;
  1226. Object.defineProperty(this, "DV", {
  1227. enumerable: false,
  1228. configurable: false,
  1229. get: function() {
  1230. if (!_DV) {
  1231. return undefined;
  1232. }
  1233. if (this instanceof AcroFormButton === false) {
  1234. return toPdfString(_DV, this.objId, this.scope);
  1235. }
  1236. return _DV;
  1237. },
  1238. set: function(value) {
  1239. value = value.toString();
  1240. if (this instanceof AcroFormButton === false) {
  1241. if (value.substr(0, 1) === "(") {
  1242. _DV = pdfUnescape(value.substr(1, value.length - 2));
  1243. } else {
  1244. _DV = pdfUnescape(value);
  1245. }
  1246. } else {
  1247. _DV = value;
  1248. }
  1249. }
  1250. });
  1251. /**
  1252. * (Optional; inheritable) The default value to which the field reverts when a reset-form action is executed (see 12.7.5.3, “Reset-Form Action”). The format of this value is the same as that of value.
  1253. *
  1254. * @name AcroFormField#defaultValue
  1255. * @default null
  1256. * @type {any}
  1257. */
  1258. Object.defineProperty(this, "defaultValue", {
  1259. enumerable: true,
  1260. configurable: true,
  1261. get: function() {
  1262. if (this instanceof AcroFormButton === true) {
  1263. return pdfUnescape(_DV.substr(1, _DV.length - 1));
  1264. } else {
  1265. return _DV;
  1266. }
  1267. },
  1268. set: function(value) {
  1269. value = value.toString();
  1270. if (this instanceof AcroFormButton === true) {
  1271. _DV = "/" + value;
  1272. } else {
  1273. _DV = value;
  1274. }
  1275. }
  1276. });
  1277. var _V = null;
  1278. Object.defineProperty(this, "_V", {
  1279. enumerable: false,
  1280. configurable: false,
  1281. get: function() {
  1282. if (!_V) {
  1283. return undefined;
  1284. }
  1285. return _V;
  1286. },
  1287. set: function(value) {
  1288. this.V = value;
  1289. }
  1290. });
  1291. Object.defineProperty(this, "V", {
  1292. enumerable: false,
  1293. configurable: false,
  1294. get: function() {
  1295. if (!_V) {
  1296. return undefined;
  1297. }
  1298. if (this instanceof AcroFormButton === false) {
  1299. return toPdfString(_V, this.objId, this.scope);
  1300. }
  1301. return _V;
  1302. },
  1303. set: function(value) {
  1304. value = value.toString();
  1305. if (this instanceof AcroFormButton === false) {
  1306. if (value.substr(0, 1) === "(") {
  1307. _V = pdfUnescape(value.substr(1, value.length - 2));
  1308. } else {
  1309. _V = pdfUnescape(value);
  1310. }
  1311. } else {
  1312. _V = value;
  1313. }
  1314. }
  1315. });
  1316. /**
  1317. * (Optional; inheritable) The field’s value, whose format varies depending on the field type. See the descriptions of individual field types for further information.
  1318. *
  1319. * @name AcroFormField#value
  1320. * @default null
  1321. * @type {any}
  1322. */
  1323. Object.defineProperty(this, "value", {
  1324. enumerable: true,
  1325. configurable: true,
  1326. get: function() {
  1327. if (this instanceof AcroFormButton === true) {
  1328. return pdfUnescape(_V.substr(1, _V.length - 1));
  1329. } else {
  1330. return _V;
  1331. }
  1332. },
  1333. set: function(value) {
  1334. value = value.toString();
  1335. if (this instanceof AcroFormButton === true) {
  1336. _V = "/" + value;
  1337. } else {
  1338. _V = value;
  1339. }
  1340. }
  1341. });
  1342. /**
  1343. * Check if field has annotations
  1344. *
  1345. * @name AcroFormField#hasAnnotation
  1346. * @readonly
  1347. * @type {boolean}
  1348. */
  1349. Object.defineProperty(this, "hasAnnotation", {
  1350. enumerable: true,
  1351. configurable: true,
  1352. get: function() {
  1353. return this.Rect;
  1354. }
  1355. });
  1356. Object.defineProperty(this, "Type", {
  1357. enumerable: true,
  1358. configurable: false,
  1359. get: function() {
  1360. return this.hasAnnotation ? "/Annot" : null;
  1361. }
  1362. });
  1363. Object.defineProperty(this, "Subtype", {
  1364. enumerable: true,
  1365. configurable: false,
  1366. get: function() {
  1367. return this.hasAnnotation ? "/Widget" : null;
  1368. }
  1369. });
  1370. var _hasAppearanceStream = false;
  1371. /**
  1372. * true if field has an appearanceStream
  1373. *
  1374. * @name AcroFormField#hasAppearanceStream
  1375. * @readonly
  1376. * @type {boolean}
  1377. */
  1378. Object.defineProperty(this, "hasAppearanceStream", {
  1379. enumerable: true,
  1380. configurable: true,
  1381. get: function() {
  1382. return _hasAppearanceStream;
  1383. },
  1384. set: function(value) {
  1385. value = Boolean(value);
  1386. _hasAppearanceStream = value;
  1387. }
  1388. });
  1389. /**
  1390. * The page on which the AcroFormField is placed
  1391. *
  1392. * @name AcroFormField#page
  1393. * @type {number}
  1394. */
  1395. var _page;
  1396. Object.defineProperty(this, "page", {
  1397. enumerable: true,
  1398. configurable: true,
  1399. get: function() {
  1400. if (!_page) {
  1401. return undefined;
  1402. }
  1403. return _page;
  1404. },
  1405. set: function(value) {
  1406. _page = value;
  1407. }
  1408. });
  1409. /**
  1410. * If set, the user may not change the value of the field. Any associated widget annotations will not interact with the user; that is, they will not respond to mouse clicks or change their appearance in response to mouse motions. This flag is useful for fields whose values are computed or imported from a database.
  1411. *
  1412. * @name AcroFormField#readOnly
  1413. * @default false
  1414. * @type {boolean}
  1415. */
  1416. Object.defineProperty(this, "readOnly", {
  1417. enumerable: true,
  1418. configurable: true,
  1419. get: function() {
  1420. return Boolean(getBitForPdf(this.Ff, 1));
  1421. },
  1422. set: function(value) {
  1423. if (Boolean(value) === true) {
  1424. this.Ff = setBitForPdf(this.Ff, 1);
  1425. } else {
  1426. this.Ff = clearBitForPdf(this.Ff, 1);
  1427. }
  1428. }
  1429. });
  1430. /**
  1431. * If set, the field shall have a value at the time it is exported by a submitform action (see 12.7.5.2, “Submit-Form Action”).
  1432. *
  1433. * @name AcroFormField#required
  1434. * @default false
  1435. * @type {boolean}
  1436. */
  1437. Object.defineProperty(this, "required", {
  1438. enumerable: true,
  1439. configurable: true,
  1440. get: function() {
  1441. return Boolean(getBitForPdf(this.Ff, 2));
  1442. },
  1443. set: function(value) {
  1444. if (Boolean(value) === true) {
  1445. this.Ff = setBitForPdf(this.Ff, 2);
  1446. } else {
  1447. this.Ff = clearBitForPdf(this.Ff, 2);
  1448. }
  1449. }
  1450. });
  1451. /**
  1452. * If set, the field shall not be exported by a submit-form action (see 12.7.5.2, “Submit-Form Action”)
  1453. *
  1454. * @name AcroFormField#noExport
  1455. * @default false
  1456. * @type {boolean}
  1457. */
  1458. Object.defineProperty(this, "noExport", {
  1459. enumerable: true,
  1460. configurable: true,
  1461. get: function() {
  1462. return Boolean(getBitForPdf(this.Ff, 3));
  1463. },
  1464. set: function(value) {
  1465. if (Boolean(value) === true) {
  1466. this.Ff = setBitForPdf(this.Ff, 3);
  1467. } else {
  1468. this.Ff = clearBitForPdf(this.Ff, 3);
  1469. }
  1470. }
  1471. });
  1472. var _Q = null;
  1473. Object.defineProperty(this, "Q", {
  1474. enumerable: true,
  1475. configurable: false,
  1476. get: function() {
  1477. if (_Q === null) {
  1478. return undefined;
  1479. }
  1480. return _Q;
  1481. },
  1482. set: function(value) {
  1483. if ([0, 1, 2].indexOf(value) !== -1) {
  1484. _Q = value;
  1485. } else {
  1486. throw new Error(
  1487. 'Invalid value "' + value + '" for attribute Q supplied.'
  1488. );
  1489. }
  1490. }
  1491. });
  1492. /**
  1493. * (Optional; inheritable) A code specifying the form of quadding (justification) that shall be used in displaying the text:
  1494. * 'left', 'center', 'right'
  1495. *
  1496. * @name AcroFormField#textAlign
  1497. * @default 'left'
  1498. * @type {string}
  1499. */
  1500. Object.defineProperty(this, "textAlign", {
  1501. get: function() {
  1502. var result;
  1503. switch (_Q) {
  1504. case 0:
  1505. default:
  1506. result = "left";
  1507. break;
  1508. case 1:
  1509. result = "center";
  1510. break;
  1511. case 2:
  1512. result = "right";
  1513. break;
  1514. }
  1515. return result;
  1516. },
  1517. configurable: true,
  1518. enumerable: true,
  1519. set: function(value) {
  1520. switch (value) {
  1521. case "right":
  1522. case 2:
  1523. _Q = 2;
  1524. break;
  1525. case "center":
  1526. case 1:
  1527. _Q = 1;
  1528. break;
  1529. case "left":
  1530. case 0:
  1531. default:
  1532. _Q = 0;
  1533. }
  1534. }
  1535. });
  1536. };
  1537. inherit(AcroFormField, AcroFormPDFObject);
  1538. /**
  1539. * @class AcroFormChoiceField
  1540. * @extends AcroFormField
  1541. */
  1542. var AcroFormChoiceField = function() {
  1543. AcroFormField.call(this);
  1544. // Field Type = Choice Field
  1545. this.FT = "/Ch";
  1546. // options
  1547. this.V = "()";
  1548. this.fontName = "zapfdingbats";
  1549. // Top Index
  1550. var _TI = 0;
  1551. Object.defineProperty(this, "TI", {
  1552. enumerable: true,
  1553. configurable: false,
  1554. get: function() {
  1555. return _TI;
  1556. },
  1557. set: function(value) {
  1558. _TI = value;
  1559. }
  1560. });
  1561. /**
  1562. * (Optional) For scrollable list boxes, the top index (the index in the Opt array of the first option visible in the list). Default value: 0.
  1563. *
  1564. * @name AcroFormChoiceField#topIndex
  1565. * @default 0
  1566. * @type {number}
  1567. */
  1568. Object.defineProperty(this, "topIndex", {
  1569. enumerable: true,
  1570. configurable: true,
  1571. get: function() {
  1572. return _TI;
  1573. },
  1574. set: function(value) {
  1575. _TI = value;
  1576. }
  1577. });
  1578. var _Opt = [];
  1579. Object.defineProperty(this, "Opt", {
  1580. enumerable: true,
  1581. configurable: false,
  1582. get: function() {
  1583. return arrayToPdfArray(_Opt, this.objId, this.scope);
  1584. },
  1585. set: function(value) {
  1586. _Opt = pdfArrayToStringArray(value);
  1587. }
  1588. });
  1589. /**
  1590. * @memberof AcroFormChoiceField
  1591. * @name getOptions
  1592. * @function
  1593. * @instance
  1594. * @returns {array} array of Options
  1595. */
  1596. this.getOptions = function() {
  1597. return _Opt;
  1598. };
  1599. /**
  1600. * @memberof AcroFormChoiceField
  1601. * @name setOptions
  1602. * @function
  1603. * @instance
  1604. * @param {array} value
  1605. */
  1606. this.setOptions = function(value) {
  1607. _Opt = value;
  1608. if (this.sort) {
  1609. _Opt.sort();
  1610. }
  1611. };
  1612. /**
  1613. * @memberof AcroFormChoiceField
  1614. * @name addOption
  1615. * @function
  1616. * @instance
  1617. * @param {string} value
  1618. */
  1619. this.addOption = function(value) {
  1620. value = value || "";
  1621. value = value.toString();
  1622. _Opt.push(value);
  1623. if (this.sort) {
  1624. _Opt.sort();
  1625. }
  1626. };
  1627. /**
  1628. * @memberof AcroFormChoiceField
  1629. * @name removeOption
  1630. * @function
  1631. * @instance
  1632. * @param {string} value
  1633. * @param {boolean} allEntries (default: false)
  1634. */
  1635. this.removeOption = function(value, allEntries) {
  1636. allEntries = allEntries || false;
  1637. value = value || "";
  1638. value = value.toString();
  1639. while (_Opt.indexOf(value) !== -1) {
  1640. _Opt.splice(_Opt.indexOf(value), 1);
  1641. if (allEntries === false) {
  1642. break;
  1643. }
  1644. }
  1645. };
  1646. /**
  1647. * If set, the field is a combo box; if clear, the field is a list box.
  1648. *
  1649. * @name AcroFormChoiceField#combo
  1650. * @default false
  1651. * @type {boolean}
  1652. */
  1653. Object.defineProperty(this, "combo", {
  1654. enumerable: true,
  1655. configurable: true,
  1656. get: function() {
  1657. return Boolean(getBitForPdf(this.Ff, 18));
  1658. },
  1659. set: function(value) {
  1660. if (Boolean(value) === true) {
  1661. this.Ff = setBitForPdf(this.Ff, 18);
  1662. } else {
  1663. this.Ff = clearBitForPdf(this.Ff, 18);
  1664. }
  1665. }
  1666. });
  1667. /**
  1668. * If set, the combo box shall include an editable text box as well as a drop-down list; if clear, it shall include only a drop-down list. This flag shall be used only if the Combo flag is set.
  1669. *
  1670. * @name AcroFormChoiceField#edit
  1671. * @default false
  1672. * @type {boolean}
  1673. */
  1674. Object.defineProperty(this, "edit", {
  1675. enumerable: true,
  1676. configurable: true,
  1677. get: function() {
  1678. return Boolean(getBitForPdf(this.Ff, 19));
  1679. },
  1680. set: function(value) {
  1681. //PDF 32000-1:2008, page 444
  1682. if (this.combo === true) {
  1683. if (Boolean(value) === true) {
  1684. this.Ff = setBitForPdf(this.Ff, 19);
  1685. } else {
  1686. this.Ff = clearBitForPdf(this.Ff, 19);
  1687. }
  1688. }
  1689. }
  1690. });
  1691. /**
  1692. * If set, the field’s option items shall be sorted alphabetically. This flag is intended for use by writers, not by readers. Conforming readers shall display the options in the order in which they occur in the Opt array (see Table 231).
  1693. *
  1694. * @name AcroFormChoiceField#sort
  1695. * @default false
  1696. * @type {boolean}
  1697. */
  1698. Object.defineProperty(this, "sort", {
  1699. enumerable: true,
  1700. configurable: true,
  1701. get: function() {
  1702. return Boolean(getBitForPdf(this.Ff, 20));
  1703. },
  1704. set: function(value) {
  1705. if (Boolean(value) === true) {
  1706. this.Ff = setBitForPdf(this.Ff, 20);
  1707. _Opt.sort();
  1708. } else {
  1709. this.Ff = clearBitForPdf(this.Ff, 20);
  1710. }
  1711. }
  1712. });
  1713. /**
  1714. * (PDF 1.4) If set, more than one of the field’s option items may be selected simultaneously; if clear, at most one item shall be selected
  1715. *
  1716. * @name AcroFormChoiceField#multiSelect
  1717. * @default false
  1718. * @type {boolean}
  1719. */
  1720. Object.defineProperty(this, "multiSelect", {
  1721. enumerable: true,
  1722. configurable: true,
  1723. get: function() {
  1724. return Boolean(getBitForPdf(this.Ff, 22));
  1725. },
  1726. set: function(value) {
  1727. if (Boolean(value) === true) {
  1728. this.Ff = setBitForPdf(this.Ff, 22);
  1729. } else {
  1730. this.Ff = clearBitForPdf(this.Ff, 22);
  1731. }
  1732. }
  1733. });
  1734. /**
  1735. * (PDF 1.4) If set, text entered in the field shall not be spellchecked. This flag shall not be used unless the Combo and Edit flags are both set.
  1736. *
  1737. * @name AcroFormChoiceField#doNotSpellCheck
  1738. * @default false
  1739. * @type {boolean}
  1740. */
  1741. Object.defineProperty(this, "doNotSpellCheck", {
  1742. enumerable: true,
  1743. configurable: true,
  1744. get: function() {
  1745. return Boolean(getBitForPdf(this.Ff, 23));
  1746. },
  1747. set: function(value) {
  1748. if (Boolean(value) === true) {
  1749. this.Ff = setBitForPdf(this.Ff, 23);
  1750. } else {
  1751. this.Ff = clearBitForPdf(this.Ff, 23);
  1752. }
  1753. }
  1754. });
  1755. /**
  1756. * (PDF 1.5) If set, the new value shall be committed as soon as a selection is made (commonly with the pointing device). In this case, supplying a value for a field involves three actions: selecting the field for fill-in, selecting a choice for the fill-in value, and leaving that field, which finalizes or “commits” the data choice and triggers any actions associated with the entry or changing of this data. If this flag is on, then processing does not wait for leaving the field action to occur, but immediately proceeds to the third step.
  1757. * This option enables applications to perform an action once a selection is made, without requiring the user to exit the field. If clear, the new value is not committed until the user exits the field.
  1758. *
  1759. * @name AcroFormChoiceField#commitOnSelChange
  1760. * @default false
  1761. * @type {boolean}
  1762. */
  1763. Object.defineProperty(this, "commitOnSelChange", {
  1764. enumerable: true,
  1765. configurable: true,
  1766. get: function() {
  1767. return Boolean(getBitForPdf(this.Ff, 27));
  1768. },
  1769. set: function(value) {
  1770. if (Boolean(value) === true) {
  1771. this.Ff = setBitForPdf(this.Ff, 27);
  1772. } else {
  1773. this.Ff = clearBitForPdf(this.Ff, 27);
  1774. }
  1775. }
  1776. });
  1777. this.hasAppearanceStream = false;
  1778. };
  1779. inherit(AcroFormChoiceField, AcroFormField);
  1780. /**
  1781. * @class AcroFormListBox
  1782. * @extends AcroFormChoiceField
  1783. * @extends AcroFormField
  1784. */
  1785. var AcroFormListBox = function() {
  1786. AcroFormChoiceField.call(this);
  1787. this.fontName = "helvetica";
  1788. //PDF 32000-1:2008, page 444
  1789. this.combo = false;
  1790. };
  1791. inherit(AcroFormListBox, AcroFormChoiceField);
  1792. /**
  1793. * @class AcroFormComboBox
  1794. * @extends AcroFormListBox
  1795. * @extends AcroFormChoiceField
  1796. * @extends AcroFormField
  1797. */
  1798. var AcroFormComboBox = function() {
  1799. AcroFormListBox.call(this);
  1800. this.combo = true;
  1801. };
  1802. inherit(AcroFormComboBox, AcroFormListBox);
  1803. /**
  1804. * @class AcroFormEditBox
  1805. * @extends AcroFormComboBox
  1806. * @extends AcroFormListBox
  1807. * @extends AcroFormChoiceField
  1808. * @extends AcroFormField
  1809. */
  1810. var AcroFormEditBox = function() {
  1811. AcroFormComboBox.call(this);
  1812. this.edit = true;
  1813. };
  1814. inherit(AcroFormEditBox, AcroFormComboBox);
  1815. /**
  1816. * @class AcroFormButton
  1817. * @extends AcroFormField
  1818. */
  1819. var AcroFormButton = function() {
  1820. AcroFormField.call(this);
  1821. this.FT = "/Btn";
  1822. /**
  1823. * (Radio buttons only) If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect. If clear, clicking the selected button deselects it, leaving no button selected.
  1824. *
  1825. * @name AcroFormButton#noToggleToOff
  1826. * @type {boolean}
  1827. */
  1828. Object.defineProperty(this, "noToggleToOff", {
  1829. enumerable: true,
  1830. configurable: true,
  1831. get: function() {
  1832. return Boolean(getBitForPdf(this.Ff, 15));
  1833. },
  1834. set: function(value) {
  1835. if (Boolean(value) === true) {
  1836. this.Ff = setBitForPdf(this.Ff, 15);
  1837. } else {
  1838. this.Ff = clearBitForPdf(this.Ff, 15);
  1839. }
  1840. }
  1841. });
  1842. /**
  1843. * If set, the field is a set of radio buttons; if clear, the field is a checkbox. This flag may be set only if the Pushbutton flag is clear.
  1844. *
  1845. * @name AcroFormButton#radio
  1846. * @type {boolean}
  1847. */
  1848. Object.defineProperty(this, "radio", {
  1849. enumerable: true,
  1850. configurable: true,
  1851. get: function() {
  1852. return Boolean(getBitForPdf(this.Ff, 16));
  1853. },
  1854. set: function(value) {
  1855. if (Boolean(value) === true) {
  1856. this.Ff = setBitForPdf(this.Ff, 16);
  1857. } else {
  1858. this.Ff = clearBitForPdf(this.Ff, 16);
  1859. }
  1860. }
  1861. });
  1862. /**
  1863. * If set, the field is a pushbutton that does not retain a permanent value.
  1864. *
  1865. * @name AcroFormButton#pushButton
  1866. * @type {boolean}
  1867. */
  1868. Object.defineProperty(this, "pushButton", {
  1869. enumerable: true,
  1870. configurable: true,
  1871. get: function() {
  1872. return Boolean(getBitForPdf(this.Ff, 17));
  1873. },
  1874. set: function(value) {
  1875. if (Boolean(value) === true) {
  1876. this.Ff = setBitForPdf(this.Ff, 17);
  1877. } else {
  1878. this.Ff = clearBitForPdf(this.Ff, 17);
  1879. }
  1880. }
  1881. });
  1882. /**
  1883. * (PDF 1.5) If set, a group of radio buttons within a radio button field that use the same value for the on state will turn on and off in unison; that is if one is checked, they are all checked. If clear, the buttons are mutually exclusive (the same behavior as HTML radio buttons).
  1884. *
  1885. * @name AcroFormButton#radioIsUnison
  1886. * @type {boolean}
  1887. */
  1888. Object.defineProperty(this, "radioIsUnison", {
  1889. enumerable: true,
  1890. configurable: true,
  1891. get: function() {
  1892. return Boolean(getBitForPdf(this.Ff, 26));
  1893. },
  1894. set: function(value) {
  1895. if (Boolean(value) === true) {
  1896. this.Ff = setBitForPdf(this.Ff, 26);
  1897. } else {
  1898. this.Ff = clearBitForPdf(this.Ff, 26);
  1899. }
  1900. }
  1901. });
  1902. var _MK = {};
  1903. Object.defineProperty(this, "MK", {
  1904. enumerable: false,
  1905. configurable: false,
  1906. get: function() {
  1907. var encryptor = function(data) {
  1908. return data;
  1909. };
  1910. if (this.scope) encryptor = this.scope.internal.getEncryptor(this.objId);
  1911. if (Object.keys(_MK).length !== 0) {
  1912. var result = [];
  1913. result.push("<<");
  1914. var key;
  1915. for (key in _MK) {
  1916. result.push("/" + key + " (" + pdfEscape(encryptor(_MK[key])) + ")");
  1917. }
  1918. result.push(">>");
  1919. return result.join("\n");
  1920. }
  1921. return undefined;
  1922. },
  1923. set: function(value) {
  1924. if (typeof value === "object") {
  1925. _MK = value;
  1926. }
  1927. }
  1928. });
  1929. /**
  1930. * From the PDF reference:
  1931. * (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
  1932. * Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
  1933. *
  1934. * - '8' = Cross,
  1935. * - 'l' = Circle,
  1936. * - '' = nothing
  1937. * @name AcroFormButton#caption
  1938. * @type {string}
  1939. */
  1940. Object.defineProperty(this, "caption", {
  1941. enumerable: true,
  1942. configurable: true,
  1943. get: function() {
  1944. return _MK.CA || "";
  1945. },
  1946. set: function(value) {
  1947. if (typeof value === "string") {
  1948. _MK.CA = value;
  1949. }
  1950. }
  1951. });
  1952. var _AS;
  1953. Object.defineProperty(this, "AS", {
  1954. enumerable: false,
  1955. configurable: false,
  1956. get: function() {
  1957. return _AS;
  1958. },
  1959. set: function(value) {
  1960. _AS = value;
  1961. }
  1962. });
  1963. /**
  1964. * (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
  1965. *
  1966. * @name AcroFormButton#appearanceState
  1967. * @type {any}
  1968. */
  1969. Object.defineProperty(this, "appearanceState", {
  1970. enumerable: true,
  1971. configurable: true,
  1972. get: function() {
  1973. return _AS.substr(1, _AS.length - 1);
  1974. },
  1975. set: function(value) {
  1976. _AS = "/" + value;
  1977. }
  1978. });
  1979. };
  1980. inherit(AcroFormButton, AcroFormField);
  1981. /**
  1982. * @class AcroFormPushButton
  1983. * @extends AcroFormButton
  1984. * @extends AcroFormField
  1985. */
  1986. var AcroFormPushButton = function() {
  1987. AcroFormButton.call(this);
  1988. this.pushButton = true;
  1989. };
  1990. inherit(AcroFormPushButton, AcroFormButton);
  1991. /**
  1992. * @class AcroFormRadioButton
  1993. * @extends AcroFormButton
  1994. * @extends AcroFormField
  1995. */
  1996. var AcroFormRadioButton = function() {
  1997. AcroFormButton.call(this);
  1998. this.radio = true;
  1999. this.pushButton = false;
  2000. var _Kids = [];
  2001. Object.defineProperty(this, "Kids", {
  2002. enumerable: true,
  2003. configurable: false,
  2004. get: function() {
  2005. return _Kids;
  2006. },
  2007. set: function(value) {
  2008. if (typeof value !== "undefined") {
  2009. _Kids = value;
  2010. } else {
  2011. _Kids = [];
  2012. }
  2013. }
  2014. });
  2015. };
  2016. inherit(AcroFormRadioButton, AcroFormButton);
  2017. /**
  2018. * The Child class of a RadioButton (the radioGroup) -> The single Buttons
  2019. *
  2020. * @class AcroFormChildClass
  2021. * @extends AcroFormField
  2022. * @ignore
  2023. */
  2024. var AcroFormChildClass = function() {
  2025. AcroFormField.call(this);
  2026. var _parent;
  2027. Object.defineProperty(this, "Parent", {
  2028. enumerable: false,
  2029. configurable: false,
  2030. get: function() {
  2031. return _parent;
  2032. },
  2033. set: function(value) {
  2034. _parent = value;
  2035. }
  2036. });
  2037. var _optionName;
  2038. Object.defineProperty(this, "optionName", {
  2039. enumerable: false,
  2040. configurable: true,
  2041. get: function() {
  2042. return _optionName;
  2043. },
  2044. set: function(value) {
  2045. _optionName = value;
  2046. }
  2047. });
  2048. var _MK = {};
  2049. Object.defineProperty(this, "MK", {
  2050. enumerable: false,
  2051. configurable: false,
  2052. get: function() {
  2053. var encryptor = function(data) {
  2054. return data;
  2055. };
  2056. if (this.scope) encryptor = this.scope.internal.getEncryptor(this.objId);
  2057. var result = [];
  2058. result.push("<<");
  2059. var key;
  2060. for (key in _MK) {
  2061. result.push("/" + key + " (" + pdfEscape(encryptor(_MK[key])) + ")");
  2062. }
  2063. result.push(">>");
  2064. return result.join("\n");
  2065. },
  2066. set: function(value) {
  2067. if (typeof value === "object") {
  2068. _MK = value;
  2069. }
  2070. }
  2071. });
  2072. /**
  2073. * From the PDF reference:
  2074. * (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
  2075. * Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
  2076. *
  2077. * - '8' = Cross,
  2078. * - 'l' = Circle,
  2079. * - '' = nothing
  2080. * @name AcroFormButton#caption
  2081. * @type {string}
  2082. */
  2083. Object.defineProperty(this, "caption", {
  2084. enumerable: true,
  2085. configurable: true,
  2086. get: function() {
  2087. return _MK.CA || "";
  2088. },
  2089. set: function(value) {
  2090. if (typeof value === "string") {
  2091. _MK.CA = value;
  2092. }
  2093. }
  2094. });
  2095. var _AS;
  2096. Object.defineProperty(this, "AS", {
  2097. enumerable: false,
  2098. configurable: false,
  2099. get: function() {
  2100. return _AS;
  2101. },
  2102. set: function(value) {
  2103. _AS = value;
  2104. }
  2105. });
  2106. /**
  2107. * (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
  2108. *
  2109. * @name AcroFormButton#appearanceState
  2110. * @type {any}
  2111. */
  2112. Object.defineProperty(this, "appearanceState", {
  2113. enumerable: true,
  2114. configurable: true,
  2115. get: function() {
  2116. return _AS.substr(1, _AS.length - 1);
  2117. },
  2118. set: function(value) {
  2119. _AS = "/" + value;
  2120. }
  2121. });
  2122. this.caption = "l";
  2123. this.appearanceState = "Off";
  2124. // todo: set AppearanceType as variable that can be set from the
  2125. // outside...
  2126. this._AppearanceType = AcroFormAppearance.RadioButton.Circle;
  2127. // The Default appearanceType is the Circle
  2128. this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(
  2129. this.optionName
  2130. );
  2131. };
  2132. inherit(AcroFormChildClass, AcroFormField);
  2133. AcroFormRadioButton.prototype.setAppearance = function(appearance) {
  2134. if (!("createAppearanceStream" in appearance && "getCA" in appearance)) {
  2135. throw new Error(
  2136. "Couldn't assign Appearance to RadioButton. Appearance was Invalid!"
  2137. );
  2138. }
  2139. for (var objId in this.Kids) {
  2140. if (this.Kids.hasOwnProperty(objId)) {
  2141. var child = this.Kids[objId];
  2142. child.appearanceStreamContent = appearance.createAppearanceStream(
  2143. child.optionName
  2144. );
  2145. child.caption = appearance.getCA();
  2146. }
  2147. }
  2148. };
  2149. AcroFormRadioButton.prototype.createOption = function(name) {
  2150. // Create new Child for RadioGroup
  2151. var child = new AcroFormChildClass();
  2152. child.Parent = this;
  2153. child.optionName = name;
  2154. // Add to Parent
  2155. this.Kids.push(child);
  2156. addField.call(this.scope, child);
  2157. return child;
  2158. };
  2159. /**
  2160. * @class AcroFormCheckBox
  2161. * @extends AcroFormButton
  2162. * @extends AcroFormField
  2163. */
  2164. var AcroFormCheckBox = function() {
  2165. AcroFormButton.call(this);
  2166. this.fontName = "zapfdingbats";
  2167. this.caption = "3";
  2168. this.appearanceState = "On";
  2169. this.value = "On";
  2170. this.textAlign = "center";
  2171. this.appearanceStreamContent = AcroFormAppearance.CheckBox.createAppearanceStream();
  2172. };
  2173. inherit(AcroFormCheckBox, AcroFormButton);
  2174. /**
  2175. * @class AcroFormTextField
  2176. * @extends AcroFormField
  2177. */
  2178. var AcroFormTextField = function() {
  2179. AcroFormField.call(this);
  2180. this.FT = "/Tx";
  2181. /**
  2182. * If set, the field may contain multiple lines of text; if clear, the field’s text shall be restricted to a single line.
  2183. *
  2184. * @name AcroFormTextField#multiline
  2185. * @type {boolean}
  2186. */
  2187. Object.defineProperty(this, "multiline", {
  2188. enumerable: true,
  2189. configurable: true,
  2190. get: function() {
  2191. return Boolean(getBitForPdf(this.Ff, 13));
  2192. },
  2193. set: function(value) {
  2194. if (Boolean(value) === true) {
  2195. this.Ff = setBitForPdf(this.Ff, 13);
  2196. } else {
  2197. this.Ff = clearBitForPdf(this.Ff, 13);
  2198. }
  2199. }
  2200. });
  2201. /**
  2202. * (PDF 1.4) If set, the text entered in the field represents the pathname of a file whose contents shall be submitted as the value of the field.
  2203. *
  2204. * @name AcroFormTextField#fileSelect
  2205. * @type {boolean}
  2206. */
  2207. Object.defineProperty(this, "fileSelect", {
  2208. enumerable: true,
  2209. configurable: true,
  2210. get: function() {
  2211. return Boolean(getBitForPdf(this.Ff, 21));
  2212. },
  2213. set: function(value) {
  2214. if (Boolean(value) === true) {
  2215. this.Ff = setBitForPdf(this.Ff, 21);
  2216. } else {
  2217. this.Ff = clearBitForPdf(this.Ff, 21);
  2218. }
  2219. }
  2220. });
  2221. /**
  2222. * (PDF 1.4) If set, text entered in the field shall not be spell-checked.
  2223. *
  2224. * @name AcroFormTextField#doNotSpellCheck
  2225. * @type {boolean}
  2226. */
  2227. Object.defineProperty(this, "doNotSpellCheck", {
  2228. enumerable: true,
  2229. configurable: true,
  2230. get: function() {
  2231. return Boolean(getBitForPdf(this.Ff, 23));
  2232. },
  2233. set: function(value) {
  2234. if (Boolean(value) === true) {
  2235. this.Ff = setBitForPdf(this.Ff, 23);
  2236. } else {
  2237. this.Ff = clearBitForPdf(this.Ff, 23);
  2238. }
  2239. }
  2240. });
  2241. /**
  2242. * (PDF 1.4) If set, the field shall not scroll (horizontally for single-line fields, vertically for multiple-line fields) to accommodate more text than fits within its annotation rectangle. Once the field is full, no further text shall be accepted for interactive form filling; for noninteractive form filling, the filler should take care not to add more character than will visibly fit in the defined area.
  2243. *
  2244. * @name AcroFormTextField#doNotScroll
  2245. * @type {boolean}
  2246. */
  2247. Object.defineProperty(this, "doNotScroll", {
  2248. enumerable: true,
  2249. configurable: true,
  2250. get: function() {
  2251. return Boolean(getBitForPdf(this.Ff, 24));
  2252. },
  2253. set: function(value) {
  2254. if (Boolean(value) === true) {
  2255. this.Ff = setBitForPdf(this.Ff, 24);
  2256. } else {
  2257. this.Ff = clearBitForPdf(this.Ff, 24);
  2258. }
  2259. }
  2260. });
  2261. /**
  2262. * (PDF 1.5) May be set only if the MaxLen entry is present in the text field dictionary (see Table 229) and if the Multiline, Password, and FileSelect flags are clear. If set, the field shall be automatically divided into as many equally spaced positions, or combs, as the value of MaxLen, and the text is laid out into those combs.
  2263. *
  2264. * @name AcroFormTextField#comb
  2265. * @type {boolean}
  2266. */
  2267. Object.defineProperty(this, "comb", {
  2268. enumerable: true,
  2269. configurable: true,
  2270. get: function() {
  2271. return Boolean(getBitForPdf(this.Ff, 25));
  2272. },
  2273. set: function(value) {
  2274. if (Boolean(value) === true) {
  2275. this.Ff = setBitForPdf(this.Ff, 25);
  2276. } else {
  2277. this.Ff = clearBitForPdf(this.Ff, 25);
  2278. }
  2279. }
  2280. });
  2281. /**
  2282. * (PDF 1.5) If set, the value of this field shall be a rich text string (see 12.7.3.4, “Rich Text Strings”). If the field has a value, the RV entry of the field dictionary (Table 222) shall specify the rich text string.
  2283. *
  2284. * @name AcroFormTextField#richText
  2285. * @type {boolean}
  2286. */
  2287. Object.defineProperty(this, "richText", {
  2288. enumerable: true,
  2289. configurable: true,
  2290. get: function() {
  2291. return Boolean(getBitForPdf(this.Ff, 26));
  2292. },
  2293. set: function(value) {
  2294. if (Boolean(value) === true) {
  2295. this.Ff = setBitForPdf(this.Ff, 26);
  2296. } else {
  2297. this.Ff = clearBitForPdf(this.Ff, 26);
  2298. }
  2299. }
  2300. });
  2301. var _MaxLen = null;
  2302. Object.defineProperty(this, "MaxLen", {
  2303. enumerable: true,
  2304. configurable: false,
  2305. get: function() {
  2306. return _MaxLen;
  2307. },
  2308. set: function(value) {
  2309. _MaxLen = value;
  2310. }
  2311. });
  2312. /**
  2313. * (Optional; inheritable) The maximum length of the field’s text, in characters.
  2314. *
  2315. * @name AcroFormTextField#maxLength
  2316. * @type {number}
  2317. */
  2318. Object.defineProperty(this, "maxLength", {
  2319. enumerable: true,
  2320. configurable: true,
  2321. get: function() {
  2322. return _MaxLen;
  2323. },
  2324. set: function(value) {
  2325. if (Number.isInteger(value)) {
  2326. _MaxLen = value;
  2327. }
  2328. }
  2329. });
  2330. Object.defineProperty(this, "hasAppearanceStream", {
  2331. enumerable: true,
  2332. configurable: true,
  2333. get: function() {
  2334. return this.V || this.DV;
  2335. }
  2336. });
  2337. };
  2338. inherit(AcroFormTextField, AcroFormField);
  2339. /**
  2340. * @class AcroFormPasswordField
  2341. * @extends AcroFormTextField
  2342. * @extends AcroFormField
  2343. */
  2344. var AcroFormPasswordField = function() {
  2345. AcroFormTextField.call(this);
  2346. /**
  2347. * If set, the field is intended for entering a secure password that should not be echoed visibly to the screen. Characters typed from the keyboard shall instead be echoed in some unreadable form, such as asterisks or bullet characters.
  2348. * NOTE To protect password confidentiality, readers should never store the value of the text field in the PDF file if this flag is set.
  2349. *
  2350. * @name AcroFormTextField#password
  2351. * @type {boolean}
  2352. */
  2353. Object.defineProperty(this, "password", {
  2354. enumerable: true,
  2355. configurable: true,
  2356. get: function() {
  2357. return Boolean(getBitForPdf(this.Ff, 14));
  2358. },
  2359. set: function(value) {
  2360. if (Boolean(value) === true) {
  2361. this.Ff = setBitForPdf(this.Ff, 14);
  2362. } else {
  2363. this.Ff = clearBitForPdf(this.Ff, 14);
  2364. }
  2365. }
  2366. });
  2367. this.password = true;
  2368. };
  2369. inherit(AcroFormPasswordField, AcroFormTextField);
  2370. // Contains Methods for creating standard appearances
  2371. var AcroFormAppearance = {
  2372. CheckBox: {
  2373. createAppearanceStream: function() {
  2374. var appearance = {
  2375. N: {
  2376. On: AcroFormAppearance.CheckBox.YesNormal
  2377. },
  2378. D: {
  2379. On: AcroFormAppearance.CheckBox.YesPushDown,
  2380. Off: AcroFormAppearance.CheckBox.OffPushDown
  2381. }
  2382. };
  2383. return appearance;
  2384. },
  2385. /**
  2386. * Returns the standard On Appearance for a CheckBox
  2387. *
  2388. * @returns {AcroFormXObject}
  2389. */
  2390. YesPushDown: function(formObject) {
  2391. var xobj = createFormXObject(formObject);
  2392. xobj.scope = formObject.scope;
  2393. var stream = [];
  2394. var fontKey = formObject.scope.internal.getFont(
  2395. formObject.fontName,
  2396. formObject.fontStyle
  2397. ).id;
  2398. var encodedColor = formObject.scope.__private__.encodeColorString(
  2399. formObject.color
  2400. );
  2401. var calcRes = calculateX(formObject, formObject.caption);
  2402. stream.push("0.749023 g");
  2403. stream.push(
  2404. "0 0 " +
  2405. f2(AcroFormAppearance.internal.getWidth(formObject)) +
  2406. " " +
  2407. f2(AcroFormAppearance.internal.getHeight(formObject)) +
  2408. " re"
  2409. );
  2410. stream.push("f");
  2411. stream.push("BMC");
  2412. stream.push("q");
  2413. stream.push("0 0 1 rg");
  2414. stream.push(
  2415. "/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor
  2416. );
  2417. stream.push("BT");
  2418. stream.push(calcRes.text);
  2419. stream.push("ET");
  2420. stream.push("Q");
  2421. stream.push("EMC");
  2422. xobj.stream = stream.join("\n");
  2423. return xobj;
  2424. },
  2425. YesNormal: function(formObject) {
  2426. var xobj = createFormXObject(formObject);
  2427. xobj.scope = formObject.scope;
  2428. var fontKey = formObject.scope.internal.getFont(
  2429. formObject.fontName,
  2430. formObject.fontStyle
  2431. ).id;
  2432. var encodedColor = formObject.scope.__private__.encodeColorString(
  2433. formObject.color
  2434. );
  2435. var stream = [];
  2436. var height = AcroFormAppearance.internal.getHeight(formObject);
  2437. var width = AcroFormAppearance.internal.getWidth(formObject);
  2438. var calcRes = calculateX(formObject, formObject.caption);
  2439. stream.push("1 g");
  2440. stream.push("0 0 " + f2(width) + " " + f2(height) + " re");
  2441. stream.push("f");
  2442. stream.push("q");
  2443. stream.push("0 0 1 rg");
  2444. stream.push("0 0 " + f2(width - 1) + " " + f2(height - 1) + " re");
  2445. stream.push("W");
  2446. stream.push("n");
  2447. stream.push("0 g");
  2448. stream.push("BT");
  2449. stream.push(
  2450. "/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor
  2451. );
  2452. stream.push(calcRes.text);
  2453. stream.push("ET");
  2454. stream.push("Q");
  2455. xobj.stream = stream.join("\n");
  2456. return xobj;
  2457. },
  2458. /**
  2459. * Returns the standard Off Appearance for a CheckBox
  2460. *
  2461. * @returns {AcroFormXObject}
  2462. */
  2463. OffPushDown: function(formObject) {
  2464. var xobj = createFormXObject(formObject);
  2465. xobj.scope = formObject.scope;
  2466. var stream = [];
  2467. stream.push("0.749023 g");
  2468. stream.push(
  2469. "0 0 " +
  2470. f2(AcroFormAppearance.internal.getWidth(formObject)) +
  2471. " " +
  2472. f2(AcroFormAppearance.internal.getHeight(formObject)) +
  2473. " re"
  2474. );
  2475. stream.push("f");
  2476. xobj.stream = stream.join("\n");
  2477. return xobj;
  2478. }
  2479. },
  2480. RadioButton: {
  2481. Circle: {
  2482. createAppearanceStream: function(name) {
  2483. var appearanceStreamContent = {
  2484. D: {
  2485. Off: AcroFormAppearance.RadioButton.Circle.OffPushDown
  2486. },
  2487. N: {}
  2488. };
  2489. appearanceStreamContent.N[name] =
  2490. AcroFormAppearance.RadioButton.Circle.YesNormal;
  2491. appearanceStreamContent.D[name] =
  2492. AcroFormAppearance.RadioButton.Circle.YesPushDown;
  2493. return appearanceStreamContent;
  2494. },
  2495. getCA: function() {
  2496. return "l";
  2497. },
  2498. YesNormal: function(formObject) {
  2499. var xobj = createFormXObject(formObject);
  2500. xobj.scope = formObject.scope;
  2501. var stream = [];
  2502. // Make the Radius of the Circle relative to min(height, width) of formObject
  2503. var DotRadius =
  2504. AcroFormAppearance.internal.getWidth(formObject) <=
  2505. AcroFormAppearance.internal.getHeight(formObject)
  2506. ? AcroFormAppearance.internal.getWidth(formObject) / 4
  2507. : AcroFormAppearance.internal.getHeight(formObject) / 4;
  2508. // The Borderpadding...
  2509. DotRadius = Number((DotRadius * 0.9).toFixed(5));
  2510. var c = AcroFormAppearance.internal.Bezier_C;
  2511. var DotRadiusBezier = Number((DotRadius * c).toFixed(5));
  2512. /*
  2513. * The Following is a Circle created with Bezier-Curves.
  2514. */
  2515. stream.push("q");
  2516. stream.push(
  2517. "1 0 0 1 " +
  2518. f5(AcroFormAppearance.internal.getWidth(formObject) / 2) +
  2519. " " +
  2520. f5(AcroFormAppearance.internal.getHeight(formObject) / 2) +
  2521. " cm"
  2522. );
  2523. stream.push(DotRadius + " 0 m");
  2524. stream.push(
  2525. DotRadius +
  2526. " " +
  2527. DotRadiusBezier +
  2528. " " +
  2529. DotRadiusBezier +
  2530. " " +
  2531. DotRadius +
  2532. " 0 " +
  2533. DotRadius +
  2534. " c"
  2535. );
  2536. stream.push(
  2537. "-" +
  2538. DotRadiusBezier +
  2539. " " +
  2540. DotRadius +
  2541. " -" +
  2542. DotRadius +
  2543. " " +
  2544. DotRadiusBezier +
  2545. " -" +
  2546. DotRadius +
  2547. " 0 c"
  2548. );
  2549. stream.push(
  2550. "-" +
  2551. DotRadius +
  2552. " -" +
  2553. DotRadiusBezier +
  2554. " -" +
  2555. DotRadiusBezier +
  2556. " -" +
  2557. DotRadius +
  2558. " 0 -" +
  2559. DotRadius +
  2560. " c"
  2561. );
  2562. stream.push(
  2563. DotRadiusBezier +
  2564. " -" +
  2565. DotRadius +
  2566. " " +
  2567. DotRadius +
  2568. " -" +
  2569. DotRadiusBezier +
  2570. " " +
  2571. DotRadius +
  2572. " 0 c"
  2573. );
  2574. stream.push("f");
  2575. stream.push("Q");
  2576. xobj.stream = stream.join("\n");
  2577. return xobj;
  2578. },
  2579. YesPushDown: function(formObject) {
  2580. var xobj = createFormXObject(formObject);
  2581. xobj.scope = formObject.scope;
  2582. var stream = [];
  2583. var DotRadius =
  2584. AcroFormAppearance.internal.getWidth(formObject) <=
  2585. AcroFormAppearance.internal.getHeight(formObject)
  2586. ? AcroFormAppearance.internal.getWidth(formObject) / 4
  2587. : AcroFormAppearance.internal.getHeight(formObject) / 4;
  2588. // The Borderpadding...
  2589. DotRadius = Number((DotRadius * 0.9).toFixed(5));
  2590. // Save results for later use; no need to waste
  2591. // processor ticks on doing math
  2592. var k = Number((DotRadius * 2).toFixed(5));
  2593. var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
  2594. var dc = Number(
  2595. (DotRadius * AcroFormAppearance.internal.Bezier_C).toFixed(5)
  2596. );
  2597. stream.push("0.749023 g");
  2598. stream.push("q");
  2599. stream.push(
  2600. "1 0 0 1 " +
  2601. f5(AcroFormAppearance.internal.getWidth(formObject) / 2) +
  2602. " " +
  2603. f5(AcroFormAppearance.internal.getHeight(formObject) / 2) +
  2604. " cm"
  2605. );
  2606. stream.push(k + " 0 m");
  2607. stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
  2608. stream.push(
  2609. "-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c"
  2610. );
  2611. stream.push(
  2612. "-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c"
  2613. );
  2614. stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
  2615. stream.push("f");
  2616. stream.push("Q");
  2617. stream.push("0 g");
  2618. stream.push("q");
  2619. stream.push(
  2620. "1 0 0 1 " +
  2621. f5(AcroFormAppearance.internal.getWidth(formObject) / 2) +
  2622. " " +
  2623. f5(AcroFormAppearance.internal.getHeight(formObject) / 2) +
  2624. " cm"
  2625. );
  2626. stream.push(DotRadius + " 0 m");
  2627. stream.push(
  2628. "" +
  2629. DotRadius +
  2630. " " +
  2631. dc +
  2632. " " +
  2633. dc +
  2634. " " +
  2635. DotRadius +
  2636. " 0 " +
  2637. DotRadius +
  2638. " c"
  2639. );
  2640. stream.push(
  2641. "-" +
  2642. dc +
  2643. " " +
  2644. DotRadius +
  2645. " -" +
  2646. DotRadius +
  2647. " " +
  2648. dc +
  2649. " -" +
  2650. DotRadius +
  2651. " 0 c"
  2652. );
  2653. stream.push(
  2654. "-" +
  2655. DotRadius +
  2656. " -" +
  2657. dc +
  2658. " -" +
  2659. dc +
  2660. " -" +
  2661. DotRadius +
  2662. " 0 -" +
  2663. DotRadius +
  2664. " c"
  2665. );
  2666. stream.push(
  2667. dc +
  2668. " -" +
  2669. DotRadius +
  2670. " " +
  2671. DotRadius +
  2672. " -" +
  2673. dc +
  2674. " " +
  2675. DotRadius +
  2676. " 0 c"
  2677. );
  2678. stream.push("f");
  2679. stream.push("Q");
  2680. xobj.stream = stream.join("\n");
  2681. return xobj;
  2682. },
  2683. OffPushDown: function(formObject) {
  2684. var xobj = createFormXObject(formObject);
  2685. xobj.scope = formObject.scope;
  2686. var stream = [];
  2687. var DotRadius =
  2688. AcroFormAppearance.internal.getWidth(formObject) <=
  2689. AcroFormAppearance.internal.getHeight(formObject)
  2690. ? AcroFormAppearance.internal.getWidth(formObject) / 4
  2691. : AcroFormAppearance.internal.getHeight(formObject) / 4;
  2692. // The Borderpadding...
  2693. DotRadius = Number((DotRadius * 0.9).toFixed(5));
  2694. // Save results for later use; no need to waste
  2695. // processor ticks on doing math
  2696. var k = Number((DotRadius * 2).toFixed(5));
  2697. var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
  2698. stream.push("0.749023 g");
  2699. stream.push("q");
  2700. stream.push(
  2701. "1 0 0 1 " +
  2702. f5(AcroFormAppearance.internal.getWidth(formObject) / 2) +
  2703. " " +
  2704. f5(AcroFormAppearance.internal.getHeight(formObject) / 2) +
  2705. " cm"
  2706. );
  2707. stream.push(k + " 0 m");
  2708. stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
  2709. stream.push(
  2710. "-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c"
  2711. );
  2712. stream.push(
  2713. "-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c"
  2714. );
  2715. stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
  2716. stream.push("f");
  2717. stream.push("Q");
  2718. xobj.stream = stream.join("\n");
  2719. return xobj;
  2720. }
  2721. },
  2722. Cross: {
  2723. /**
  2724. * Creates the Actual AppearanceDictionary-References
  2725. *
  2726. * @param {string} name
  2727. * @returns {Object}
  2728. * @ignore
  2729. */
  2730. createAppearanceStream: function(name) {
  2731. var appearanceStreamContent = {
  2732. D: {
  2733. Off: AcroFormAppearance.RadioButton.Cross.OffPushDown
  2734. },
  2735. N: {}
  2736. };
  2737. appearanceStreamContent.N[name] =
  2738. AcroFormAppearance.RadioButton.Cross.YesNormal;
  2739. appearanceStreamContent.D[name] =
  2740. AcroFormAppearance.RadioButton.Cross.YesPushDown;
  2741. return appearanceStreamContent;
  2742. },
  2743. getCA: function() {
  2744. return "8";
  2745. },
  2746. YesNormal: function(formObject) {
  2747. var xobj = createFormXObject(formObject);
  2748. xobj.scope = formObject.scope;
  2749. var stream = [];
  2750. var cross = AcroFormAppearance.internal.calculateCross(formObject);
  2751. stream.push("q");
  2752. stream.push(
  2753. "1 1 " +
  2754. f2(AcroFormAppearance.internal.getWidth(formObject) - 2) +
  2755. " " +
  2756. f2(AcroFormAppearance.internal.getHeight(formObject) - 2) +
  2757. " re"
  2758. );
  2759. stream.push("W");
  2760. stream.push("n");
  2761. stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
  2762. stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
  2763. stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
  2764. stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
  2765. stream.push("s");
  2766. stream.push("Q");
  2767. xobj.stream = stream.join("\n");
  2768. return xobj;
  2769. },
  2770. YesPushDown: function(formObject) {
  2771. var xobj = createFormXObject(formObject);
  2772. xobj.scope = formObject.scope;
  2773. var cross = AcroFormAppearance.internal.calculateCross(formObject);
  2774. var stream = [];
  2775. stream.push("0.749023 g");
  2776. stream.push(
  2777. "0 0 " +
  2778. f2(AcroFormAppearance.internal.getWidth(formObject)) +
  2779. " " +
  2780. f2(AcroFormAppearance.internal.getHeight(formObject)) +
  2781. " re"
  2782. );
  2783. stream.push("f");
  2784. stream.push("q");
  2785. stream.push(
  2786. "1 1 " +
  2787. f2(AcroFormAppearance.internal.getWidth(formObject) - 2) +
  2788. " " +
  2789. f2(AcroFormAppearance.internal.getHeight(formObject) - 2) +
  2790. " re"
  2791. );
  2792. stream.push("W");
  2793. stream.push("n");
  2794. stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
  2795. stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
  2796. stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
  2797. stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
  2798. stream.push("s");
  2799. stream.push("Q");
  2800. xobj.stream = stream.join("\n");
  2801. return xobj;
  2802. },
  2803. OffPushDown: function(formObject) {
  2804. var xobj = createFormXObject(formObject);
  2805. xobj.scope = formObject.scope;
  2806. var stream = [];
  2807. stream.push("0.749023 g");
  2808. stream.push(
  2809. "0 0 " +
  2810. f2(AcroFormAppearance.internal.getWidth(formObject)) +
  2811. " " +
  2812. f2(AcroFormAppearance.internal.getHeight(formObject)) +
  2813. " re"
  2814. );
  2815. stream.push("f");
  2816. xobj.stream = stream.join("\n");
  2817. return xobj;
  2818. }
  2819. }
  2820. },
  2821. /**
  2822. * Returns the standard Appearance
  2823. *
  2824. * @returns {AcroFormXObject}
  2825. */
  2826. createDefaultAppearanceStream: function(formObject) {
  2827. // Set Helvetica to Standard Font (size: auto)
  2828. // Color: Black
  2829. var fontKey = formObject.scope.internal.getFont(
  2830. formObject.fontName,
  2831. formObject.fontStyle
  2832. ).id;
  2833. var encodedColor = formObject.scope.__private__.encodeColorString(
  2834. formObject.color
  2835. );
  2836. var fontSize = formObject.fontSize;
  2837. var result = "/" + fontKey + " " + fontSize + " Tf " + encodedColor;
  2838. return result;
  2839. }
  2840. };
  2841. AcroFormAppearance.internal = {
  2842. Bezier_C: 0.551915024494,
  2843. calculateCross: function(formObject) {
  2844. var width = AcroFormAppearance.internal.getWidth(formObject);
  2845. var height = AcroFormAppearance.internal.getHeight(formObject);
  2846. var a = Math.min(width, height);
  2847. var cross = {
  2848. x1: {
  2849. // upperLeft
  2850. x: (width - a) / 2,
  2851. y: (height - a) / 2 + a // height - borderPadding
  2852. },
  2853. x2: {
  2854. // lowerRight
  2855. x: (width - a) / 2 + a,
  2856. y: (height - a) / 2 // borderPadding
  2857. },
  2858. x3: {
  2859. // lowerLeft
  2860. x: (width - a) / 2,
  2861. y: (height - a) / 2 // borderPadding
  2862. },
  2863. x4: {
  2864. // upperRight
  2865. x: (width - a) / 2 + a,
  2866. y: (height - a) / 2 + a // height - borderPadding
  2867. }
  2868. };
  2869. return cross;
  2870. }
  2871. };
  2872. AcroFormAppearance.internal.getWidth = function(formObject) {
  2873. var result = 0;
  2874. if (typeof formObject === "object") {
  2875. result = scale(formObject.Rect[2]);
  2876. }
  2877. return result;
  2878. };
  2879. AcroFormAppearance.internal.getHeight = function(formObject) {
  2880. var result = 0;
  2881. if (typeof formObject === "object") {
  2882. result = scale(formObject.Rect[3]);
  2883. }
  2884. return result;
  2885. };
  2886. // Public:
  2887. /**
  2888. * Add an AcroForm-Field to the jsPDF-instance
  2889. *
  2890. * @name addField
  2891. * @function
  2892. * @instance
  2893. * @param {Object} fieldObject
  2894. * @returns {jsPDF}
  2895. */
  2896. var addField = (jsPDFAPI.addField = function(fieldObject) {
  2897. initializeAcroForm(this, fieldObject);
  2898. if (fieldObject instanceof AcroFormField) {
  2899. putForm(fieldObject);
  2900. } else {
  2901. throw new Error("Invalid argument passed to jsPDF.addField.");
  2902. }
  2903. fieldObject.page = fieldObject.scope.internal.getCurrentPageInfo().pageNumber;
  2904. return this;
  2905. });
  2906. jsPDFAPI.AcroFormChoiceField = AcroFormChoiceField;
  2907. jsPDFAPI.AcroFormListBox = AcroFormListBox;
  2908. jsPDFAPI.AcroFormComboBox = AcroFormComboBox;
  2909. jsPDFAPI.AcroFormEditBox = AcroFormEditBox;
  2910. jsPDFAPI.AcroFormButton = AcroFormButton;
  2911. jsPDFAPI.AcroFormPushButton = AcroFormPushButton;
  2912. jsPDFAPI.AcroFormRadioButton = AcroFormRadioButton;
  2913. jsPDFAPI.AcroFormCheckBox = AcroFormCheckBox;
  2914. jsPDFAPI.AcroFormTextField = AcroFormTextField;
  2915. jsPDFAPI.AcroFormPasswordField = AcroFormPasswordField;
  2916. jsPDFAPI.AcroFormAppearance = AcroFormAppearance;
  2917. jsPDFAPI.AcroForm = {
  2918. ChoiceField: AcroFormChoiceField,
  2919. ListBox: AcroFormListBox,
  2920. ComboBox: AcroFormComboBox,
  2921. EditBox: AcroFormEditBox,
  2922. Button: AcroFormButton,
  2923. PushButton: AcroFormPushButton,
  2924. RadioButton: AcroFormRadioButton,
  2925. CheckBox: AcroFormCheckBox,
  2926. TextField: AcroFormTextField,
  2927. PasswordField: AcroFormPasswordField,
  2928. Appearance: AcroFormAppearance
  2929. };
  2930. jsPDF.AcroForm = {
  2931. ChoiceField: AcroFormChoiceField,
  2932. ListBox: AcroFormListBox,
  2933. ComboBox: AcroFormComboBox,
  2934. EditBox: AcroFormEditBox,
  2935. Button: AcroFormButton,
  2936. PushButton: AcroFormPushButton,
  2937. RadioButton: AcroFormRadioButton,
  2938. CheckBox: AcroFormCheckBox,
  2939. TextField: AcroFormTextField,
  2940. PasswordField: AcroFormPasswordField,
  2941. Appearance: AcroFormAppearance
  2942. };
  2943. var AcroForm = jsPDF.AcroForm;
  2944. export {
  2945. AcroForm,
  2946. AcroFormChoiceField,
  2947. AcroFormListBox,
  2948. AcroFormComboBox,
  2949. AcroFormEditBox,
  2950. AcroFormButton,
  2951. AcroFormPushButton,
  2952. AcroFormRadioButton,
  2953. AcroFormCheckBox,
  2954. AcroFormTextField,
  2955. AcroFormPasswordField,
  2956. AcroFormAppearance
  2957. };