PaperForms Barcode Performance

We have had some feedback around the performance of paper forms barcodes on large forms.  Seems that when customers use multiple barcodes to process large amounts of data, their form slows down. 

The reason the form slows down is because the barcode recalculates every time a field changes.  The calculation is doing several things:

  1. Generate minimal, unique names for each data item. When the names are included in the output, we want them to be as terse as possible, while still uniquely identifying the data.  To do this, each name needs to be compared to all other names.
  2. Gathering data values to be included in the output
  3. Formatting the result as delimited text

It’s the first item that takes the bulk of the time.  In order to find the minimal name, the script compares each data node name against all others and iteratively expands the names until they are unique.  The algorithm appears to have O(n2) performance — which means that it degrades quickly when the number of data elements grows large.

There are three techniques you can use to improve the performance:

1. Do the work in the prePrint event

Move the barcode calculation to the prePrint event. In the barcode properties, uncheck "Automatic Scripting" and move the script from the calculate event to the prePrint event. Now, instead of recomputing the barcode every time a field changes, we compute the barcode only once — just before it gets printed.

2. Use unique field names

When the script encounters duplicate field names, it does lots of extra work to resolve them.  So don’t ask the script to do so much work.  Use unique field names. For example, instead of:

item[0].quantity
item[0].price
item[1].quantity
item[1].price
item[2].quantity
item[2].price

try:

item[0].quantity0
item[0].price0
item[1].quantity1
item[1].price1
item[2].quantity2
item[2].price2

Not only will the script complete more quickly, but the names written to the barcode value will be shorter.  When they are not unique, they get prefixed with their subform name.  When they’re unique, they are left unqualified.

3. Do not include names — and modify the script

Since the bulk of the work that the script does is to come up with minimal unique names, let’s not write out the names.  Uncheck the "Include Field Names" option.  Unfortunately, the script goes through the effort to produce unique names even when names are not included in the output. You need to modify the script to prevent it from calculating names. Uncheck "Automatic Scripting" and add the lines in red below.

19 function encode(node)
20 {
21   var barcodeLabel = this.caption.value.text.value;
22   if (includeLabel == true && barcodeLabel.length > 0)
23   {
24     fieldNames.push(labelID);
25     fieldValues.push(barcodeLabel);
26   }
27 
28   if(collection != null)
29   {
30     // Create an array of all child nodes in the form
31     var entireFormNodes = new Array();
       if (includeFieldNames) {
32       collectChildNodes(xfa.datasets.data, entireFormNodes);
       }
33 
34     // Create an array of all nodes in the collection
35     var collectionNodes = new Array();
36     var nodes = collection.evaluate();
37 
38     for(var i = 0; i < nodes.length; ++i)
39     {
40       collectChildNodes(nodes.item(i), collectionNodes);
41     }
42 
43      // If the form has two or more fields sharing the …
44     // parents of these fields, as well as the subscript …
45     // their parents, will be used to differentiate …
46     // to take as little space in the barcode as possible, …
47     // data in the object names only when necessary …
       if (includeFieldNames) {
48       resolveDuplicates(collectionNodes, entireFormNodes,…);
       }

If you implement this option, odds are you won’t bother with the first two methods.  The performance of the script is now O(n) and should work fine in the calculate event with non-unique names. And … is it just me?  I get a kick out of watching the 2D barcode re-draw itself every time I modify a field.