text: /**
   * jsPDF AcroForm Plugin Copyright (c) 2016 Alexander Weidt,
   * https://github.com/BiggA94
   * 
   * Licensed under the MIT License. http://opensource.org/licenses/mit-license
   */
  
  (function (jsPDFAPI, globalObj) {
    'use strict';
  
    var scope;
    var pageHeight;
    var scaleFactor = 1;
    var inherit = function (child, parent) {
        var ObjectCreate = Object.create || function (o) {
            var F = function () {
            };
            F.prototype = o;
            return new F();
          };
        child.prototype = Object.create(parent.prototype);
        child.prototype.constructor = child;
    };
    var scale = function (x) {
      return (x * (scaleFactor / 1));// 1 = (96 / 72)
    };
    var antiScale = function (x) {
      return ((1 / scaleFactor ) * x);
    };
  
    var createFormXObject = function (formObject) {
      var xobj = new AcroFormXObject;
      var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
      var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
      xobj.BBox = [0, 0, width.toFixed(2), height.toFixed(2)];
      return xobj;
    };
    
    var setBitPosition = function (variable, position, value) {
      variable = variable || 0;
      value = value || 1;
  
      var bitMask = 1;
      bitMask = bitMask << (position - 1);
  
      if (value == 1) {
        // Set the Bit to 1
        var variable = variable | bitMask;
      } else {
        // Set the Bit to 0
        var variable = variable & (~bitMask);
      }
  
      return variable;
    };
    
    var getBitPosition = function (variable, position) {
      variable = variable || 0;
      var bitMask = 1;
      bitMask = bitMask << (position - 1);
      return variable | bitMask;
    };
    
  
    
    /**
    * Calculating the Ff entry:
    * 
    * The Ff entry contains flags, that have to be set bitwise In the Following
    * the number in the Comment is the BitPosition
    */
    var calculateFlagsOnOptions = function (flags, opts, PDFVersion) {
      var PDFVersion = PDFVersion || 1.3;
      var flags = flags || 0;
      
      // 1, readOnly
      if (opts.readOnly == true) {
        flags = setBitPosition(flags, 1);
      }
  
      // 2, required
      if (opts.required == true) {
        flags = setBitPosition(flags, 2);
      }
  
      // 4, noExport
      if (opts.noExport == true) {
        flags = setBitPosition(flags, 3);
      }
  
      // 13, multiline
      if (opts.multiline == true) {
        flags = setBitPosition(flags, 13);
      }
  
      // 14, Password
      if (opts.password) {
        flags = setBitPosition(flags, 14);
      }
  
      // 15, NoToggleToOff (Radio buttons only
      if (opts.noToggleToOff) {
        flags = setBitPosition(flags, 15);
      }
  
      // 16, Radio
      if (opts.radio) {
        flags = setBitPosition(flags, 16);
      }
      
      // 17, Pushbutton
      if (opts.pushbutton) {
        flags = setBitPosition(flags, 17);
      }
      
      // 18, Combo (If not set, the choiceField is a listBox!!)
      if (opts.combo) {
        flags = setBitPosition(flags, 18);
      }
  
      // 19, Edit
      if (opts.edit) {
        flags = setBitPosition(flags, 19);
      }
  
      // 20, Sort
      if (opts.sort) {
        flags = setBitPosition(flags, 20);
      }
      
      // 21, FileSelect, PDF 1.4...
      if (opts.fileSelect && PDFVersion >= 1.4) {
        flags = setBitPosition(flags, 21);
      }
  
      // 22, MultiSelect (PDF 1.4)
      if (opts.multiSelect && PDFVersion >= 1.4) {
        flags = setBitPosition(flags, 22);
      }
  
      // 23, DoNotSpellCheck (PDF 1.4)
      if (opts.doNotSpellCheck && PDFVersion >= 1.4) {
        flags = setBitPosition(flags, 23);
      }
  
      // 24, DoNotScroll (PDF 1.4)
      if (opts.doNotScroll == true && PDFVersion >= 1.4) {
        flags = setBitPosition(flags, 24);
      }
      
      // 25, RichText (PDF 1.4)
      if (opts.richText && PDFVersion >= 1.4) {
        flags = setBitPosition(flags, 25);
      }
      
      return flags;
    }
  
    var calculateCoordinates = function (args) {
      var x = args[0];
      var y = args[1];
      var w = args[2];
      var h = args[3];
  
      var coordinates = {};
  
      if (Array.isArray(x)) {
        x[0] = scale(x[0]);
        x[1] = scale(x[1]);
        x[2] = scale(x[2]);
        x[3] = scale(x[3]);
      } else {
        x = scale(x);
        y = scale(y);
        w = scale(w);
        h = scale(h);
      }
      coordinates.lowerLeft_X = x || 0;
      coordinates.lowerLeft_Y = scale(pageHeight) - y - h || 0;
      coordinates.upperRight_X = x + w || 0;
      coordinates.upperRight_Y = scale(pageHeight) - y || 0;
  
      return [coordinates.lowerLeft_X.toFixed(2), coordinates.lowerLeft_Y.toFixed(2), coordinates.upperRight_X.toFixed(2), coordinates.upperRight_Y.toFixed(2)];
    };
  
    var calculateAppearanceStream = function (formObject) {
      if (formObject.appearanceStreamContent) {
        // If appearanceStream is already set, use it
        return formObject.appearanceStreamContent;
      }
  
      if (!formObject.V && !formObject.DV) {
        return;
      }
  
      // else calculate it
  
      var stream = [];
      var text = formObject.V || formObject.DV;
      var calcRes = calculateX(formObject, text);
  
      stream.push('/Tx BMC');
      stream.push('q');
      stream.push('/F1 ' + calcRes.fontSize.toFixed(2) + ' Tf');
      stream.push('1 0 0 1 0 0 Tm');// Text Matrix
      
      stream.push('BT'); // Begin Text
      stream.push(calcRes.text);
  
      stream.push('ET'); // End Text
      stream.push('Q')
      stream.push('EMC');
  
      var appearanceStreamContent = new createFormXObject(formObject);
      appearanceStreamContent.stream = stream.join("\n");
  
      var appearance = {
        N: {
          'Normal': appearanceStreamContent
        }
      };
  
      return appearanceStreamContent;
    };
  
    var calculateX = function (formObject, text, font, maxFontSize) {
      var maxFontSize = maxFontSize || 12;
      var font = font || "helvetica";
      var returnValue = {
        text: "",
        fontSize: ""
      };
      // Remove Brackets
      text = (text.substr(0, 1) == '(') ? text.substr(1) : text;
      text = (text.substr(text.length - 1) == ')') ? text.substr(0, text.length - 1) : text;
      // split into array of words
      var textSplit = text.split(' ');
  
      /**
      * the color could be ((alpha)||(r,g,b)||(c,m,y,k))
      * 
      * @type {string}
      */
      var color = "0 g\n";
      var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
      var lineSpacing = 2;
      var borderPadding = 2;
  
  
      var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
      height = (height < 0) ? -height : height;
      var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
      width = (width < 0) ? -width : width;
  
      var isSmallerThanWidth = function (i, lastLine, fontSize) {
        if (i + 1 < textSplit.length) {
          var tmp = lastLine + " " + textSplit[i + 1];
          var TextWidth = ((calculateFontSpace(tmp, fontSize + "px", font).width));
          var FieldWidth = (width - 2 * borderPadding);
          return (TextWidth <= FieldWidth);
        } else {
          return false;
        }
      };
  
  
      fontSize++;
      FontSize: while (true) {
        var text = "";
        fontSize--;
        var textHeight = calculateFontSpace("3", fontSize + "px", font).height;
        var startY = (formObject.multiline) ? height - fontSize : (height - textHeight) / 2;
        startY += lineSpacing;
        var startX = -borderPadding;
  
        var lastX = startX, lastY = startY;
        var firstWordInLine = 0, lastWordInLine = 0;
        var lastLength = 0;
  
        var y = 0;
        if (fontSize <= 0) {
          // In case, the Text doesn't fit at all
          fontSize = 12;
          text = "(...) Tj\n";
          text += "% Width of Text: " + calculateFontSpace(text, "1px").width + ", FieldWidth:" + width + "\n";
          break;
        }
  
        lastLength = calculateFontSpace(textSplit[0] + " ", fontSize + "px", font).width;
  
        var lastLine = "";
        var lineCount = 0;
        Line:
          for (var i in textSplit) {
            if (textSplit.hasOwnProperty(i)) {
            lastLine += textSplit[i] + " ";
            // Remove last blank
            lastLine = (lastLine.substr(lastLine.length - 1) == " ") ? lastLine.substr(0, lastLine.length - 1) : lastLine;
            var key = parseInt(i);
            lastLength = calculateFontSpace(lastLine + " ", fontSize + "px", font).width;
            var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
            var isLastWord = i >= textSplit.length - 1;
            if (nextLineIsSmaller && !isLastWord) {
              lastLine += " ";
              continue; // Line
            } else if (!nextLineIsSmaller && !isLastWord) {
              if (!formObject.multiline) {
                continue FontSize;
              } else {
                if (((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing) > height) {
                  // If the Text is higher than the
                  // FieldObject
                  continue FontSize;
                }
                lastWordInLine = key;
                // go on
              }
            } else if (isLastWord) {
              lastWordInLine = key;
            } else {
              if (formObject.multiline && ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing) > height) {
                // If the Text is higher than the FieldObject
                continue FontSize;
              }
            }
  
            var line = '';
  
            for (var x = firstWordInLine; x <= lastWordInLine; x++) {
              line += textSplit[x] + ' ';
            }
  
            // Remove last blank
            line = (line.substr(line.length - 1) == " ") ? line.substr(0, line.length - 1) : line;
            // lastLength -= blankSpace.width;
            lastLength = calculateFontSpace(line, fontSize + "px", font).width;
  
            // Calculate startX
            switch (formObject.Q) {
              case 2: // Right justified
                startX = (width - lastLength - borderPadding);
                break;
              case 1:// Q = 1 := Text-Alignment: Center
                startX = (width - lastLength) / 2;
                break;
              case 0:
              default:
                startX = borderPadding;
                break;
            }
            text += (startX.toFixed(2)) + ' ' + (lastY.toFixed(2)) + ' Td\n';
            text += '(' + line + ') Tj\n';
            // reset X in PDF
            text += (-startX.toFixed(2)) + ' 0 Td\n';
  
            // After a Line, adjust y position
            lastY = -(fontSize + lineSpacing);
            lastX = startX;
  
            // Reset for next iteration step
            lastLength = 0;
            firstWordInLine = lastWordInLine + 1;
            lineCount++;
  
            lastLine = "";
            continue Line;
            }
          }
        break;
      }
  
      returnValue.text = text;
      returnValue.fontSize = fontSize;
  
      return returnValue;
    };
  
    /**
    * small workaround for calculating the TextMetric approximately
    * 
    * @param text
    * @param fontsize
    * @returns {TextMetrics} (Has Height and Width)
    */
    var calculateFontSpace = function (text, fontSize, fontType) {
  	fontType = fontType || "helvetica";
      var font = scope.internal.getFont(fontType);
      var width = scope.getStringUnitWidth(text, {font : font, fontSize: parseFloat(fontSize), charSpace: 0}) * parseFloat(fontSize);
      var height = scope.getStringUnitWidth("3", {font : font, fontSize: parseFloat(fontSize), charSpace: 0}) * parseFloat(fontSize) * 1.5;
      var result = {height: height, width: width};
      return result;
    };
  
    var acroformPluginTemplate = {
      fields: [],
      xForms: [],
      /**
      * acroFormDictionaryRoot contains information about the AcroForm
      * Dictionary 0: The Event-Token, the AcroFormDictionaryCallback has
      * 1: The Object ID of the Root
      */
      acroFormDictionaryRoot: null,
      /**
      * After the PDF gets evaluated, the reference to the root has to be
      * reset, this indicates, whether the root has already been printed
      * out
      */
      printedOut: false,
      internal: null,
      isInitialized: false
    };
    
    var annotReferenceCallback = function () {
  	  var fields = scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields;
      for (var i in fields) {
  		if (fields.hasOwnProperty(i)) {
  		  var formObject = fields[i];
  		  // add Annot Reference!
  		  if (formObject.hasAnnotation) {
  			// If theres an Annotation Widget in the Form Object, put the
  			// Reference in the /Annot array
  			createAnnotationReference.call(scope, formObject);
  		  }
  		}
  	}
    };
    
    var putForm = function (formObject) {
      if (scope.internal.acroformPlugin.printedOut) {
        scope.internal.acroformPlugin.printedOut = false;
        scope.internal.acroformPlugin.acroFormDictionaryRoot = null;
      }
      if (!scope.internal.acroformPlugin.acroFormDictionaryRoot) {
        initializeAcroForm.call(scope);
      }
      scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject);
    };
    /**
    * Create the Reference to the widgetAnnotation, so that it gets referenced
    * in the Annot[] int the+ (Requires the Annotation Plugin)
    */
    var createAnnotationReference = function (object) {
      var options = {
        type: 'reference',
        object: object
      };
      scope.annotationPlugin.annotations[scope.internal.getPageInfo(object.page).pageNumber].push(options);
    };
  
    // Callbacks
  
    var putCatalogCallback = function () {
      // Put reference to AcroForm to DocumentCatalog
      if (typeof scope.internal.acroformPlugin.acroFormDictionaryRoot != 'undefined') { 
        // for safety, shouldn't normally be the case
        scope.internal.write('/AcroForm ' + scope.internal.acroformPlugin.acroFormDictionaryRoot.objId + ' '
          + 0 + ' R');
      } else {
        console.log('Root missing...');
      }
    };
  
    /**
    * Adds /Acroform X 0 R to Document Catalog, and creates the AcroForm
    * Dictionary
    */
    var AcroFormDictionaryCallback = function () {
      // Remove event
      scope.internal.events.unsubscribe(scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID);
      delete scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID;
      scope.internal.acroformPlugin.printedOut = true;
    };
  
    /**
    * Creates the single Fields and writes them into the Document
    * 
    * If fieldArray is set, use the fields that are inside it instead of the
    * fields from the AcroRoot (for the FormXObjects...)
    */
    var createFieldCallback = function (fieldArray) {
      var standardFields = (!fieldArray);
  
      if (!fieldArray) {
        // in case there is no fieldArray specified, we want to print out
        // the Fields of the AcroForm
        // Print out Root
        scope.internal.newObjectDeferredBegin(scope.internal.acroformPlugin.acroFormDictionaryRoot.objId);
        scope.internal.out(scope.internal.acroformPlugin.acroFormDictionaryRoot.getString());
      }
  
      var fieldArray = fieldArray || scope.internal.acroformPlugin.acroFormDictionaryRoot.Kids;
  
      for (var i in fieldArray) {
  		
        if (fieldArray.hasOwnProperty(i)) {
  		  var key = i;
  		  var form = fieldArray[i];
  
  		  var oldRect = form.Rect;
  
  		  if (form.Rect) {
  			form.Rect = calculateCoordinates.call(this, form.Rect);
  		  }
  
  		  // Start Writing the Object
  		  scope.internal.newObjectDeferredBegin(form.objId);
  
  		  var content = form.objId + " 0 obj\n<<\n";
  
  		  if (typeof form === "object" && typeof form.getContent === "function") {
  			content += form.getContent();
  		  }
  
  		  form.Rect = oldRect;
  
  		  if (form.hasAppearanceStream && !form.appearanceStreamContent) {
  			// Calculate Appearance
  			var appearance = calculateAppearanceStream.call(this, form);
  			content += "/AP << /N " + appearance + " >>\n";
  
  			scope.internal.acroformPlugin.xForms.push(appearance);
  		  }
  
  		  // Assume AppearanceStreamContent is a Array with N,R,D (at least
  		  // one of them!)
  		  if (form.appearanceStreamContent) {
  			content += "/AP << ";
  			// Iterate over N,R and D
  			for (var k in form.appearanceStreamContent) {
  				if (form.appearanceStreamContent.hasOwnProperty(k)) {
  			  var value = form.appearanceStreamContent[k];
  			  content += ("/" + k + " ");
  			  content += "<< ";
  			  if (Object.keys(value).length >= 1 || Array.isArray(value)) {
  				// appearanceStream is an Array or Object!
  				for (var i in value) {
  				  if (value.hasOwnProperty(i)) {
  				  var obj = value[i];
  				  if (typeof obj === 'function') {
  					// if Function is referenced, call it in order
  					// to get the FormXObject
  					obj = obj.call(this, form);
  				  }
  				  content += ("/" + i + " " + obj + " ");
  
  				  // In case the XForm is already used, e.g. OffState
  				  // of CheckBoxes, don't add it
  				  if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0))
  					scope.internal.acroformPlugin.xForms.push(obj);
  			  
  				  }
  				}
  			  } else {
  				var obj = value;
  				if (typeof obj === 'function') {
  				  // if Function is referenced, call it in order to
  				  // get the FormXObject
  				  obj = obj.call(this, form);
  				}
  				content += ("/" + i + " " + obj + " \n");
  				if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0))
  				  scope.internal.acroformPlugin.xForms.push(obj);
  			  }
  			  content += " >>\n";
  				}
  			}
  
  			// appearance stream is a normal Object..
  			content += (">>\n");
  		  }
  
  		  content += (">>\nendobj\n");
  
  		  scope.internal.out(content);
        }
      }
      if (standardFields) {
        createXFormObjectCallback.call(this, scope.internal.acroformPlugin.xForms);
      }
    };
  
    var createXFormObjectCallback = function (fieldArray) {
      for (var i in fieldArray) {
  		  if (fieldArray.hasOwnProperty(i)) {
  		  var key = i;
  		  var form = fieldArray[i];
  		  // Start Writing the Object
  		  scope.internal.newObjectDeferredBegin(form && form.objId);
  
  		  var content = "";
  		  if (typeof form === "object" && typeof form.getString === "function") {
  			content = form.getString();
  		  }
  		  scope.internal.out(content);
  
  		  delete fieldArray[key];
  	  }
      }
    };
  
    var initializeAcroForm = function () {
      if (this.internal !== undefined && (this.internal.acroformPlugin === undefined || this.internal.acroformPlugin.isInitialized === false)) {
  
        scope = this;
  
        AcroFormField.FieldNum = 0;
        this.internal.acroformPlugin = JSON.parse(JSON.stringify(acroformPluginTemplate));
        if (this.internal.acroformPlugin.acroFormDictionaryRoot) {
          // return;
          throw new Error("Exception while creating AcroformDictionary");
        }
        scaleFactor = scope.internal.scaleFactor;
        pageHeight = scope.internal.pageSize.getHeight();
  
        // The Object Number of the AcroForm Dictionary
        scope.internal.acroformPlugin.acroFormDictionaryRoot = new AcroFormDictionary();
  
        // add Callback for creating the AcroForm Dictionary
        scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID = scope.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback);
  
        scope.internal.events.subscribe('buildDocument', annotReferenceCallback); // buildDocument
  
        // Register event, that is triggered when the DocumentCatalog is
        // written, in order to add /AcroForm
        scope.internal.events.subscribe('putCatalog', putCatalogCallback);
  
        // Register event, that creates all Fields
        scope.internal.events.subscribe('postPutPages', createFieldCallback);
        
        scope.internal.acroformPlugin.isInitialized = true;
      }
    }
  
    var arrayToPdfArray = function (array) {
      if (Array.isArray(array)) {
        var content = ' [';
        for (var i in array) {
  		  
        if (array.hasOwnProperty(i)) {
            var element = array[i].toString();
            content += element;
            content += ((i < array.length - 1) ? ' ' : '');
          }
        }
        content += ']';
    
        return content;
      }
    };
    
    var toPdfString = function (string) {
      string = string || "";
    
      // put Bracket at the Beginning of the String
      if (string.indexOf('(') !== 0) {
        string = '(' + string;
      }
      
      if (string.substring(string.length - 1) != ')') {
        string += ')';
      }
      return string;
    };
  
      // ##########################
      // Classes
      // ##########################
  
      var AcroFormPDFObject = function () {
        // The Object ID in the PDF Object Model
        // todo
        var _objId;
        Object.defineProperty(this, 'objId', {
          get: function () {
            if (!_objId) {
              _objId = scope.internal.newObjectDeferred();
            }
            if (!_objId) {
              console.log("Couldn't create Object ID");
            }
            return _objId
          },
          configurable: false
        });
      };
  
      AcroFormPDFObject.prototype.toString = function () {
        return this.objId + " 0 R";
      };
  
      AcroFormPDFObject.prototype.getString = function () {
        var res = this.objId + " 0 obj\n<<";
        var content = this.getContent();
  
        res += content + ">>\n";
        if (this.stream) {
          res += "stream\n";
          res += this.stream;
          res += "\nendstream\n";
        }
        res += "endobj\n";
        return res;
      };
  
      AcroFormPDFObject.prototype.getContent = function () {
        /**
        * Prints out all enumerable Variables from the Object
        * 
        * @param fieldObject
        * @returns {string}
        */
        var createContentFromFieldObject = function (fieldObject) {
          var content = '';
  
          var keys = Object.keys(fieldObject).filter(function (key) {
            return (key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_");
          });
  
          for (var i in keys) {
  			if (keys.hasOwnProperty(i)) {
            var key = keys[i];
            var value = fieldObject[key];
  
            /*
            * if (key == 'Rect' && value) { value =
            * AcroForm.internal.calculateCoordinates.call(jsPDF.API.acroformPlugin.internal,
            * value); }
            */
  
            if (value) {
              if (Array.isArray(value)) {
                content += '/' + key + ' ' + arrayToPdfArray(value) + "\n";
              } else if (value instanceof AcroFormPDFObject) {
                // In case it is a reference to another PDFObject,
                // take the referennce number
                content += '/' + key + ' ' + value.objId + " 0 R" + "\n";
              } else {
                content += '/' + key + ' ' + value + '\n';
              }
            }
  			}
          }
          return content;
        };
  
        var object = "";
  
        object += createContentFromFieldObject(this);
        return object;
      };
  
      var AcroFormXObject = function () {
        AcroFormPDFObject.call(this);
        this.Type = "/XObject";
        this.Subtype = "/Form";
        this.FormType = 1;
        this.BBox;
        this.Matrix;
        this.Resources = "2 0 R";
        this.PieceInfo;
        var _stream;
        Object.defineProperty(this, 'Length', {
          enumerable: true,
          get: function () {
            return (_stream !== undefined) ? _stream.length : 0;
          }
        });
        Object.defineProperty(this, 'stream', {
          enumerable: false,
          set: function (val) {
            _stream = val.trim();
          },
          get: function () {
            if (_stream) {
              return _stream;
            } else {
              return null;
            }
          }
        });
      };
  
      inherit(AcroFormXObject, AcroFormPDFObject);
      // ##### The Objects, the User can Create:
      
      var AcroFormDictionary = function () {
        AcroFormPDFObject.call(this);
        var _Kids = [];
        Object.defineProperty(this, 'Kids', {
          enumerable: false,
          configurable: true,
          get: function () {
            if (_Kids.length > 0) {
              return _Kids;
            } else {
              return;
            }
          }
        });
        Object.defineProperty(this, 'Fields', {
          enumerable: true,
          configurable: true,
          get: function () {
            return _Kids;
          }
        });
        // Default Appearance
        this.DA;
      };
  
      inherit(AcroFormDictionary, AcroFormPDFObject);
  
  
      // The Field Object contains the Variables, that every Field needs
      // Rectangle for Appearance: lower_left_X, lower_left_Y, width, height
      var AcroFormField = function () {
        'use strict';
        AcroFormPDFObject.call(this);
  
        var _Rect;
        Object.defineProperty(this, 'Rect', {
          enumerable: true,
          configurable: false,
          get: function () {
            if (!_Rect) {
              return;
            }
            var tmp = _Rect;
            // var calculatedRes =
            // AcroForm.internal.calculateCoordinates(_Rect); // do
            // later!
            return tmp
          },
          set: function (val) {
            _Rect = val;
          }
        });
  
        var _FT = "";
        Object.defineProperty(this, 'FT', {
          enumerable: true,
          set: function (val) {
            _FT = val
          },
          get: function () {
            return _FT
          }
        });
  	    
        var _F = 4;
        Object.defineProperty(this, 'F', {
          enumerable: true,
          set: function (val) {
            _F = val;
          },
          get: function () {
            return _F;
          }
        });
  
        /**
        * The Partial name of the Field Object. It has to be unique.
        */
        var _T;
  
        Object.defineProperty(this, 'T', {
          enumerable: true,
          configurable: false,
          set: function (val) {
            _T = val;
          },
          get: function () {
            if (!_T || _T.length < 1) {
              if (this instanceof AcroFormChildClass) {
                // In case of a Child from a Radio´Group, you don't
                // need a FieldName!!!
                return;
              }
              return "(FieldObject" + (AcroFormField.FieldNum++) + ")";
            }
            if (_T.substring(0, 1) == "(" && _T.substring(_T.length - 1)) {
              return _T;
            }
            return "(" + _T + ")";
          }
        });
  
        var _DA;
        // Defines the default appearance (Needed for variable Text)
        Object.defineProperty(this, 'DA', {
          enumerable: true,
          get: function () {
            if (!_DA) {
              return;
            }
            return '(' + _DA + ')'
          },
          set: function (val) {
            _DA = val
          }
        });
  
        var _DV;
        // Defines the default value
        Object.defineProperty(this, 'DV', {
          enumerable: true,
          configurable: true,
          get: function () {
            if (!_DV) {
              return;
            }
            return _DV
          },
          set: function (val) {
            _DV = val
          }
        });
        
        var _V;
        // Defines the default value
        Object.defineProperty(this, 'V', {
          enumerable: true,
          configurable: true,
          get: function () {
            if (!_V) {
              return;
            }
            return _V
          },
          set: function (val) {
            _V = val
          }
        });
  
        // this.Type = "/Annot";
        // this.Subtype = "/Widget";
        Object.defineProperty(this, 'Type', {
          enumerable: true,
          get: function () {
            return (this.hasAnnotation) ? "/Annot" : null;
          }
        });
  
        Object.defineProperty(this, 'Subtype', {
          enumerable: true,
          get: function () {
            return (this.hasAnnotation) ? "/Widget" : null;
          }
        });
  
        /**
        * 
        * @type {Array}
        */
        this.BG;
  
        Object.defineProperty(this, 'hasAnnotation', {
          enumerable: false,
          get: function () {
            if (this.Rect || this.BC || this.BG) {
              return true
            }
            return false;
          }
        });
  
        Object.defineProperty(this, 'hasAppearanceStream', {
          enumerable: false,
          configurable: true,
          writable: true
        });
  
        Object.defineProperty(this, 'page', {
          enumerable: false,
          configurable: true,
          writable: true
        });
      };
  
      inherit(AcroFormField, AcroFormPDFObject);
      
      var AcroFormChoiceField = function () {
        AcroFormField.call(this);
        // Field Type = Choice Field
        this.FT = "/Ch";
        // options
        this.Opt = [];
        this.V = '()';
        // Top Index
        this.TI = 0;
        /**
        * Defines, whether the
        * 
        * @type {boolean}
        */
  
        var _combo = false;
  
        Object.defineProperty(this, 'combo', {
          enumerable: false,
          get: function () {
            return _combo
          },
          set: function (val) {
            _combo = val
          }
        });
        /**
        * Defines, whether the Choice Field is an Edit Field. An Edit Field
        * is automatically an Combo Field.
        */
        Object.defineProperty(this, 'edit', {
          enumerable: true,
          set: function (val) {
            if (val == true) {
              this._edit = true;
              // ComboBox has to be true
              this.combo = true;
            } else {
              this._edit = false;
            }
          },
          get: function () {
            if (!this._edit) {
              return false;
            }
            return this._edit;
          },
          configurable: false
        });
        this.hasAppearanceStream = true;
      };
      inherit(AcroFormChoiceField, AcroFormField);
      
      var AcroFormListBox = function () {
        AcroFormChoiceField.call(this);
        this.combo = false;
      };
      inherit(AcroFormListBox, AcroFormChoiceField);
  
      var AcroFormComboBox = function () {
        AcroFormListBox.call(this);
        this.combo = true;
      };
      inherit(AcroFormComboBox, AcroFormListBox);
  
      var AcroFormEditBox = function () {
        AcroFormComboBox.call(this);
        this.edit = true;
      };
      inherit(AcroFormEditBox, AcroFormComboBox);
      
  
      var AcroFormButton = function () {
        AcroFormField.call(this);
        this.FT = "/Btn";
        // this.hasAnnotation = true;
      };
      inherit(AcroFormButton, AcroFormField);
      
      var AcroFormPushButton = function () {
        AcroFormButton.call(this);
  
        var _pushbutton = true;
        Object.defineProperty(this, 'pushbutton', {
          enumerable: false,
          get: function () {
            return _pushbutton;
          },
          set: function (val) {
            _pushbutton = val;
          }
        });
        
      };
      inherit(AcroFormPushButton, AcroFormButton);
  
      var AcroFormRadioButton = function () {
        AcroFormButton.call(this);
        
        var _radio = true;
        Object.defineProperty(this, 'radio', {
          enumerable: false,
          get: function () {
            return _radio;
          },
          set: function (val) {
            _radio = val;
          }
        });
        
        var _Kids = [];
        Object.defineProperty(this, 'Kids', {
          enumerable: true,
          get: function () {
            if (_Kids.length > 0) {
              return _Kids;
            }
          }
        });
  
        Object.defineProperty(this, '__Kids', {
          get: function () {
            return _Kids;
          }
        });
  
        var _noToggleToOff;
  
        Object.defineProperty(this, 'noToggleToOff', {
          enumerable: false,
          get: function () {
            return _noToggleToOff
          },
          set: function (val) {
            _noToggleToOff = val
          }
        });
  
  
        // this.hasAnnotation = false;
      };
      inherit(AcroFormRadioButton, AcroFormButton);
      
  
      /*
      * The Child classs of a RadioButton (the radioGroup) -> The single
      * Buttons
      */
      var AcroFormChildClass = function (parent, name) {
        AcroFormField.call(this);
        this.Parent = parent;
  
        // todo: set AppearanceType as variable that can be set from the
        // outside...
        this._AppearanceType = AcroFormAppearance.RadioButton.Circle; 
        // The Default appearanceType is the Circle
        this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name);
  
        // Set Print in the Annot Flag
        this.F = setBitPosition(this.F, 3, 1);
  
        // Set AppearanceCharacteristicsDictionary with default appearance
        // if field is not interacting with user
        this.MK = this._AppearanceType.createMK();
        // (8) -> Cross, (1)->  Circle, ()-> nothing
  
        // Default Appearance is Off
        this.AS = "/Off";// + name;
  
        this._Name = name;
      };
      inherit(AcroFormChildClass, AcroFormField);
  
      AcroFormRadioButton.prototype.setAppearance = function (appearance) {
        if (!('createAppearanceStream' in appearance && 'createMK' in appearance)) {
          console.log("Couldn't assign Appearance to RadioButton. Appearance was Invalid!");
          return;
        }
        for (var i in this.__Kids) {
  		  if (this.__Kids.hasOwnProperty(i)) {
          var child = this.__Kids[i];
  
          child.appearanceStreamContent = appearance.createAppearanceStream(child._Name);
          child.MK = appearance.createMK();
  		  }
        }
      };
  
      AcroFormRadioButton.prototype.createOption = function (name) {
        var parent = this;
        var kidCount = this.__Kids.length;
  
        // Create new Child for RadioGroup
        var child = new AcroFormChildClass(parent, name);
        // Add to Parent
        this.__Kids.push(child);
  
        jsPDFAPI.addField(child);
  
        return child;
      };
      
  
      var AcroFormCheckBox = function () {
        AcroFormButton.call(this);
        this.appearanceStreamContent = AcroFormAppearance.CheckBox.createAppearanceStream();
        this.MK = AcroFormAppearance.CheckBox.createMK();
        this.AS = "/On";
        this.V = "/On";
      };
      inherit(AcroFormCheckBox, AcroFormButton);
  
      var AcroFormTextField = function () {
        AcroFormField.call(this);
        this.DA = AcroFormAppearance.createDefaultAppearanceStream();
        this.F = 4;
        var _V;
        Object.defineProperty(this, 'V', {
          get: function () {
            if (_V) {
              return toPdfString(_V);
            } else {
              return _V;
            }
          },
          enumerable: true,
          set: function (val) {
            _V = val
          }
        });
  
        var _DV;
        Object.defineProperty(this, 'DV', {
          get: function () {
            if (_DV) {
              return toPdfString(_DV);
            } else {
              return _DV;
            }
          },
          enumerable: true,
          set: function (val) {
            _DV = val
          }
        });
  
        var _multiline = false;
        Object.defineProperty(this, 'multiline', {
          enumerable: false,
          get: function () {
            return _multiline
          },
          set: function (val) {
            _multiline = val;
          }
        });
  
        /**
        * For PDF 1.4
        * 
        * @type {boolean}
        */
        var _fileSelect = false;
        Object.defineProperty(this, 'fileSelect', {
          enumerable: false,
          get: function () {
            return _fileSelect
          },
          set: function (val) {
            _fileSelect = val;
          }
        });
        /**
        * For PDF 1.4
        * 
        * @type {boolean}
        */
        var _doNotSpellCheck = false;
        Object.defineProperty(this, 'doNotSpellCheck', {
          enumerable: false,
          get: function () {
            return _doNotSpellCheck
          },
          set: function (val) {
            _doNotSpellCheck = val;
          }
        });
        /**
        * For PDF 1.4
        * 
        * @type {boolean}
        */
        var _doNotScroll = false;
        Object.defineProperty(this, 'doNotScroll', {
          enumerable: false,
          get: function () {
            return _doNotScroll
          },
          set: function (val) {
            _doNotScroll = val;
          }
        });
  
        var _MaxLen = false;
        Object.defineProperty(this, 'MaxLen', {
          enumerable: true,
          get: function () {
            return _MaxLen;
          },
          set: function (val) {
            _MaxLen = val;
          }
        });
  
        Object.defineProperty(this, 'hasAppearanceStream', {
          enumerable: false,
          get: function () {
            return (this.V || this.DV);
          }
        });
  
      };
      inherit(AcroFormTextField, AcroFormField);
  
      var AcroFormPasswordField = function () {
        AcroFormTextField.call(this);
  
        var _password = true;
        Object.defineProperty(this, 'password', {
          enumerable: false,
          get: function () {
            return _password
          },
          set: function (val) {
            _password = val;
          }
        });
      };
      inherit(AcroFormPasswordField, AcroFormTextField);
      
  
    // Contains Methods for creating standard appearances
    var AcroFormAppearance = {
      CheckBox: {
        createAppearanceStream: function () {
          var appearance = {
            N: {
              On: AcroFormAppearance.CheckBox.YesNormal
            },
            D: {
              On: AcroFormAppearance.CheckBox.YesPushDown,
              Off: AcroFormAppearance.CheckBox.OffPushDown
            }
          };
  
          return appearance;
        },
        /**
          * If any other icons are needed, the number between the
          * brackets can be changed
          * 
          * @returns {string}
          */
        createMK: function () {
          return "<< /CA (3)>>";
        },
        /**
          * Returns the standard On Appearance for a CheckBox
          * 
          * @returns {AcroFormXObject}
          */
        YesPushDown: function (formObject) {
          var xobj = createFormXObject(formObject);
          var stream = [];
          var zapfDingbatsId = scope.internal.getFont("zapfdingbats", "normal").id;
          formObject.Q = 1; // set text-alignment as centered
          var calcRes = calculateX(formObject, "3", "ZapfDingbats", 50);
          stream.push("0.749023 g");
          stream.push("0 0 " + AcroFormAppearance.internal.getWidth(formObject).toFixed(2) + " " + AcroFormAppearance.internal.getHeight(formObject).toFixed(2) + " re");
          stream.push("f");
          stream.push("BMC");
          stream.push("q");
          stream.push("0 0 1 rg");
          stream.push("/" + zapfDingbatsId + " " + calcRes.fontSize.toFixed(2) + " Tf 0 g");
          stream.push("BT");
          stream.push(calcRes.text);
          stream.push("ET");
          stream.push("Q");
          stream.push("EMC");
          xobj.stream = stream.join("\n");
          return xobj;
        },
  
        YesNormal: function (formObject) {
          var xobj = createFormXObject(formObject);
          var zapfDingbatsId = scope.internal.getFont("zapfdingbats", "normal").id;
          var stream = [];
          formObject.Q = 1; // set text-alignment as centered
          var height = AcroFormAppearance.internal.getHeight(formObject);
          var width = AcroFormAppearance.internal.getWidth(formObject);
          var calcRes = calculateX(formObject, "3", "ZapfDingbats", height * 0.9);
          stream.push("1 g");
          stream.push("0 0 " + width.toFixed(2) + " " + height.toFixed(2) + " re");
          stream.push("f");
          stream.push("q");
          stream.push("0 0 1 rg");
          stream.push("0 0 " + (width - 1).toFixed(2) + " " + (height - 1).toFixed(2) + " re");
          stream.push("W");
          stream.push("n");
          stream.push("0 g");
          stream.push("BT");
          stream.push("/" + zapfDingbatsId + " " + calcRes.fontSize.toFixed(2) + " Tf 0 g");
          stream.push(calcRes.text);
          stream.push("ET");
          stream.push("Q");
          xobj.stream = stream.join("\n");
          return xobj;
        },
  
        /**
          * Returns the standard Off Appearance for a CheckBox
          * 
          * @returns {AcroFormXObject}
          */
        OffPushDown: function (formObject) {
          var xobj = createFormXObject(formObject);
          var stream = [];
          stream.push("0.749023 g");
          stream.push("0 0 " + AcroFormAppearance.internal.getWidth(formObject).toFixed(2) + " " + AcroFormAppearance.internal.getHeight(formObject).toFixed(2) + " re");
          stream.push("f");
          xobj.stream = stream.join("\n");
          return xobj;
        }
      },
  
      RadioButton: {
        Circle: {
          createAppearanceStream: function (name) {
            var appearanceStreamContent = {
              D: {
                'Off': AcroFormAppearance.RadioButton.Circle.OffPushDown
              },
              N: {}
            };
            appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Circle.YesNormal;
            appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Circle.YesPushDown;
            return appearanceStreamContent;
          },
          createMK: function () {
            return "<< /CA (l)>>";
          },
  
          YesNormal: function (formObject) {
            var xobj =  createFormXObject(formObject);
            var stream = [];
            // Make the Radius of the Circle relative to min(height,
              // width) of formObject
            var DotRadius = (AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject)) ?
            AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4;
            // The Borderpadding...
            DotRadius *= 0.9;
            var c = AcroFormAppearance.internal.Bezier_C;
            /*
              * The Following is a Circle created with Bezier-Curves.
              */
            stream.push("q");
            stream.push("1 0 0 1 " + AcroFormAppearance.internal.getWidth(formObject) / 2 + " " + AcroFormAppearance.internal.getHeight(formObject) / 2 + " cm");
            stream.push(DotRadius + " 0 m");
            stream.push(DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c");
            stream.push("-" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c");
            stream.push("-" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c");
            stream.push(DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c");
            stream.push("f");
            stream.push("Q");
            xobj.stream = stream.join("\n");
            return xobj;
          },
          YesPushDown: function (formObject) {
            var xobj = createFormXObject(formObject);
            var stream = [];
            var DotRadius = (AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject)) ?
            AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4;
            // The Borderpadding...
            DotRadius *= 0.9;
            // Save results for later use; no need to waste
              // processor ticks on doing math
            var k = DotRadius * 2;
            // var c = AcroFormAppearance.internal.Bezier_C;
            var kc = k * AcroFormAppearance.internal.Bezier_C;
            var dc = DotRadius * AcroFormAppearance.internal.Bezier_C;
  
            stream.push("0.749023 g");
            stream.push("q");
            stream.push("1 0 0 1 " + (AcroFormAppearance.internal.getWidth(formObject) / 2).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject) / 2).toFixed(2) + " cm");
            stream.push(k + " 0 m");
            stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
            stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
            stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
            stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
            stream.push("f");
            stream.push("Q");
            stream.push("0 g");
            stream.push("q");
            stream.push("1 0 0 1 " + (AcroFormAppearance.internal.getWidth(formObject) / 2).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject) / 2).toFixed(2) + " cm");
            stream.push(DotRadius + " 0 m");
            stream.push("" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c");
            stream.push("-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c");
            stream.push("-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c");
            stream.push(dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c");
            stream.push("f");
            stream.push("Q");
            xobj.stream = stream.join("\n");
            return xobj;
          },
          OffPushDown: function (formObject) {
            var xobj = createFormXObject(formObject);
            var stream = [];
            var DotRadius = (AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject)) ?
            AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4;
            // The Borderpadding...
            DotRadius *= 0.9;
            // Save results for later use; no need to waste
              // processor ticks on doing math
            var k = DotRadius * 2;
            // var c = AcroFormAppearance.internal.Bezier_C;
            var kc = k * AcroFormAppearance.internal.Bezier_C;
  
            stream.push("0.749023 g");
            stream.push("q");
            stream.push("1 0 0 1 " + (AcroFormAppearance.internal.getWidth(formObject) / 2).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject) / 2).toFixed(2) + " cm");
            stream.push(k + " 0 m");
            stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
            stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
            stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
            stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
            stream.push("f");
            stream.push("Q");
            xobj.stream = stream.join("\n");
            return xobj;
          },
        },
  
        Cross: {
          /**
            * Creates the Actual AppearanceDictionary-References
            * 
            * @param name
            * @returns
            */
          createAppearanceStream: function (name) {
            var appearanceStreamContent = {
              D: {
                'Off': AcroFormAppearance.RadioButton.Cross.OffPushDown
              },
              N: {}
            };
            appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Cross.YesNormal;
            appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Cross.YesPushDown;
            return appearanceStreamContent;
          },
          createMK: function () {
            return "<< /CA (8)>>";
          },
  
  
          YesNormal: function (formObject) {
            var xobj = createFormXObject(formObject);
            var stream = [];
            var cross = AcroFormAppearance.internal.calculateCross(formObject);
            stream.push("q");
            stream.push("1 1 " + (AcroFormAppearance.internal.getWidth(formObject) - 2).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject) - 2).toFixed(2) + " re");
            stream.push("W");
            stream.push("n");
            stream.push(cross.x1.x.toFixed(2) + " " + cross.x1.y.toFixed(2) + " m");
            stream.push(cross.x2.x.toFixed(2) + " " + cross.x2.y.toFixed(2) + " l");
            stream.push(cross.x4.x.toFixed(2) + " " + cross.x4.y.toFixed(2) + " m");
            stream.push(cross.x3.x.toFixed(2) + " " + cross.x3.y.toFixed(2) + " l");
            stream.push("s");
            stream.push("Q");
            xobj.stream = stream.join("\n");
            return xobj;
          },
          YesPushDown: function (formObject) {
            var xobj = createFormXObject(formObject);
            var cross = AcroFormAppearance.internal.calculateCross(formObject);
            var stream = [];
            stream.push("0.749023 g");
            stream.push("0 0 " + (AcroFormAppearance.internal.getWidth(formObject)).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject)).toFixed(2) + " re");
            stream.push("f");
            stream.push("q");
            stream.push("1 1 " + (AcroFormAppearance.internal.getWidth(formObject) - 2).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject) - 2).toFixed(2) + " re");
            stream.push("W");
            stream.push("n");
            stream.push(cross.x1.x.toFixed(2) + " " + cross.x1.y.toFixed(2) + " m");
            stream.push(cross.x2.x.toFixed(2) + " " + cross.x2.y.toFixed(2) + " l");
            stream.push(cross.x4.x.toFixed(2) + " " + cross.x4.y.toFixed(2) + " m");
            stream.push(cross.x3.x.toFixed(2) + " " + cross.x3.y.toFixed(2) + " l");
            stream.push("s");
            stream.push("Q");
            xobj.stream = stream.join("\n");
            return xobj;
          },
          OffPushDown: function (formObject) {
            var xobj = createFormXObject(formObject);
            var stream = [];
            stream.push("0.749023 g");
            stream.push("0 0 " + (AcroFormAppearance.internal.getWidth(formObject)).toFixed(2) + " " + (AcroFormAppearance.internal.getHeight(formObject)).toFixed(2) + " re");
            stream.push("f");
            xobj.stream = stream.join("\n");
            return xobj;
          }
        },
      },
  
      /**
        * Returns the standard Appearance
        * 
        * @returns {AcroFormXObject}
        */
      createDefaultAppearanceStream: function (formObject) {
        // Set Helvetica to Standard Font (size: auto)
        // Color: Black
        return "/F1 0 Tf 0 g";
      }
    };
  
    AcroFormAppearance.internal = {
      Bezier_C: 0.551915024494,
  
      calculateCross: function (formObject) {
        var min = function (x, y) {
          return (x > y) ? y : x;
        };
  
        var width = AcroFormAppearance.internal.getWidth(formObject);
        var height = AcroFormAppearance.internal.getHeight(formObject);
        var a = min(width, height);
        var crossSize = a;
        var borderPadding = 2; // The Padding in px
  
  
        var cross = {
          x1: { // upperLeft
            x: (width - a) / 2,
            y: ((height - a) / 2) + a,// height - borderPadding
          },
          x2: { // lowerRight
            x: ((width - a) / 2) + a,
            y: ((height - a) / 2)// borderPadding
          },
          x3: { // lowerLeft
            x: (width - a) / 2,
            y: ((height - a) / 2)// borderPadding
          },
          x4: { // upperRight
            x: ((width - a) / 2) + a,
            y: ((height - a) / 2) + a,// height - borderPadding
          }
        };
  
        return cross;
      },
    };
    AcroFormAppearance.internal.getWidth = function (formObject) {
      var result = 0;
      if (typeof formObject === "object") {
        result = scale(formObject.Rect[2]);// (formObject.Rect[2] -
                          // formObject.Rect[0]) || 0;
      }
      return result;
    };
    AcroFormAppearance.internal.getHeight = function (formObject) {
      var result = 0;
      if (typeof formObject === "object") {
        result = scale(formObject.Rect[3]);// (formObject.Rect[1] -
                          // formObject.Rect[3]) || 0;
      }
      return result;
    };
  
    // Public:
  
    jsPDFAPI.addField = function (fieldObject) {
      initializeAcroForm.call(this);
      // var opt = parseOptions(fieldObject);
      if (fieldObject instanceof AcroFormTextField) {
        this.addTextField.call(this, fieldObject);
      } else if (fieldObject instanceof AcroFormChoiceField) {
        this.addChoiceField.call(this, fieldObject);
      } else if (fieldObject instanceof AcroFormButton) {
        this.addButton.call(this, fieldObject);
      } else if (fieldObject instanceof AcroFormChildClass) {
        putForm.call(this, fieldObject);
      } else if (fieldObject) {
        // try to put..
        putForm.call(this, fieldObject);
      }
      fieldObject.page = scope.internal.getCurrentPageInfo().pageNumber;
      return this;
    };
  
    /**
    * Button FT = Btn
    */
    jsPDFAPI.addButton = function (opts) {
      initializeAcroForm.call(this);
      var options = opts || new AcroFormField();
    
      options.FT = '/Btn';
      options.Ff = calculateFlagsOnOptions(options.Ff, opts, scope.internal.getPDFVersion());
    
      putForm.call(this, options);
    
    };
    
    jsPDFAPI.addTextField = function (opts) {
      initializeAcroForm.call(this);
      var options = opts || new AcroFormField();
    
      options.FT = '/Tx';
    
    options.Ff = calculateFlagsOnOptions(options.Ff, opts, scope.internal.getPDFVersion());
    
    // Add field
      putForm.call(this, options);
    };
    
    jsPDFAPI.addChoiceField = function (opts) {
      initializeAcroForm.call(this);
      var options = opts || new AcroFormField();
    
      options.FT = '/Ch';
    
    options.Ff = calculateFlagsOnOptions(options.Ff, opts, scope.internal.getPDFVersion());
    // options.hasAnnotation = true;
    
    // Add field
      putForm.call(this, options);
    };
    
    if (typeof globalObj == "object") {
      globalObj["ChoiceField"] = AcroFormChoiceField;
      globalObj["ListBox"] = AcroFormListBox;
      globalObj["ComboBox"] = AcroFormComboBox;
      globalObj["EditBox"] = AcroFormEditBox;
      globalObj["Button"] = AcroFormButton;
      globalObj["PushButton"] = AcroFormPushButton;
      globalObj["RadioButton"] = AcroFormRadioButton;
      globalObj["CheckBox"] = AcroFormCheckBox;
      globalObj["TextField"] = AcroFormTextField;
      globalObj["PasswordField"] = AcroFormPasswordField;
      
      // backwardsCompatibility
      globalObj["AcroForm"] = {Appearance: AcroFormAppearance};
    }
    
    jsPDFAPI.AcroFormChoiceField = AcroFormChoiceField;
    jsPDFAPI.AcroFormListBox = AcroFormListBox;
    jsPDFAPI.AcroFormComboBox = AcroFormComboBox;
    jsPDFAPI.AcroFormEditBox = AcroFormEditBox;
    jsPDFAPI.AcroFormButton = AcroFormButton;
    jsPDFAPI.AcroFormPushButton = AcroFormPushButton;
    jsPDFAPI.AcroFormRadioButton = AcroFormRadioButton;
    jsPDFAPI.AcroFormCheckBox = AcroFormCheckBox;
    jsPDFAPI.AcroFormTextField = AcroFormTextField;
    jsPDFAPI.AcroFormPasswordField = AcroFormPasswordField;
    
    jsPDFAPI.AcroForm = {
      ChoiceField : AcroFormChoiceField,
      ListBox : AcroFormListBox,
      ComboBox : AcroFormComboBox,
      EditBox : AcroFormEditBox,
      Button : AcroFormButton,
      PushButton : AcroFormPushButton,
      RadioButton : AcroFormRadioButton,
      CheckBox : AcroFormCheckBox,
      TextField : AcroFormTextField,
      PasswordField : AcroFormPasswordField
    };
  })(jsPDF.API, (typeof window !== "undefined" && window || typeof global !== "undefined" && global));
  