Command and Attribute Format

Printing commands and attributes may be specified in a file, a string, or a JavaScript object. Regardless of the form, the contents must be in compliance with the JSON (JavaScript Object Notation) format.

In addition to meeting the restrictions specified for the JSON standard (www.json.org), printing commands and attributes should also follow the layout described here.

All settings intended for the Printing API must be contained within the LINEPRINTERCONTROL object, which contains the following required and optional members in this order:

"FormatVersion" : "1.0.0.0"

Following these basic format rules, a generic Command and Attribute JSON would look something like this:

{
"LINEPRINTERCONTROL" : {
    "FormatVersion" : "1.0.0.0",
    "DEFAULTS" : {
        "BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
    },
    "PRINTERS" : {
        "Printer1" : { "PrinterNumber" : 1, "StringSetting" : "Uno" },
        "Printer2" : { "PrinterNumber" : 2, "StringSetting" : "Dos" }
    }
}
}

Add Comments

Any name/value pair whose name begins with "COMMENT" is ignored. These string values are only intended to improve the readability, and should never contain actual printer settings. Based on this rule, the following LINEPRINTERCONTROL object is functionally identical to the one in the previous example:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"COMMENT" : "These values are used by every printer unless overridden.",
"BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
},
"PRINTERS" : {
"COMMENT" : "Separate entries for each printer model.",
"Printer1" : { "PrinterNumber" : 1, "StringSetting" : "Uno" },
"Printer2" : { "PrinterNumber" : 2, "StringSetting" : "Dos" }
}
}
}

Share Common Settings

Any name/value pair whose name begins with "INCLUDE" indicates an additional settings section to be included. The string value (or array of string values) associated with the name should match a separate object that appears later in the LINEPRINTERCONTROL object.

This rule allows multiple printers to share the same settings where appropriate. In the following simplified example, the INCLUDE member allows multiple printers to share the same Boolean setting values:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
},
"PRINTERS" : {
"Printer1" : { "INCLUDE" : "NumberedPrinter", "StringSetting" : "Uno" },
"Printer2" : { "INCLUDE" : "NumberedPrinter", "StringSetting" : "Dos" },
"PrinterA" : { "INCLUDE" : "LetteredPrinter", "StringSetting" : "Alpha" },
"NumberedPrinter" : { "HasNumberInName" : true, "HasLetterInName" : false },
"LetteredPrinter" : { "HasNumberInName" : false, "HasLetterInName" : true }
}
}
}

Based on this example, Printer1 and Printer2 would support settings for NumberedPrinter while PrinterA would not. This feature provides a convenient method of sharing settings across the same family of printer models.

The Printing API also supports multiple INCLUDE items in the same object. One way to do this is through the use of multiple INCLUDE_x members where x is a different number to distinguish the member names. The other method involves the use of an INCLUDE member with an array of string values as illustrated below:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
},
"PRINTERS" : {
"Printer1" : { "INCLUDE" : "Feature1", "PrinterCode" : 1 },
"Printer2" : { "INCLUDE" : "Feature2", "PrinterCode" : 2 },
"Printer3" : { "INCLUDE_1" : "Feature1", "INCLUDE_2" : "Feature2", "PrinterCode" : 3 },
"Printer4" : { "INCLUDE" : [ "Feature1", "Feature2" ], "PrinterCode" : 4 },
"Feature1" : { "EnableFeature1" : true },
"Feature2" : { "EnableFeature2" : true }
}
}
}

An object referenced by an INCLUDE or INCLUDE_x member can also include other objects. In this example, the Printer1 object includes the Feature1 object, which in turn includes the SubFeature1 object:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
},
"PRINTERS" : {
"Printer1" : { "INCLUDE" : "Feature1", "StringSetting" : "Uno" },
"Printer2" : { "INCLUDE" : "Feature2", "StringSetting" : "Dos" },
"Feature1" : { "INCLUDE" : "SubFeature1", "EnableFeature1" : true },
"SubFeature1" : { "EnableSubFeature1" : true },
"Feature2" : { "EnableFeature2" : true }
}
}
}

While the INCLUDE feature is a powerful tool, there are some limitations to what it can do:

Resolve Duplicate Setting Values

Speaking of duplicate values, the Printing API follows a fairly straightforward precedence rule for determining which values to store and which values to ignore. Basically, the first occurrence of a printer setting member found outside the DEFAULTS object defines the value. If a specific printer setting is not found outside the DEFAULTS section, then the default value is used instead. The following example illustrates this in better detail:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"NumSetting" : 1, "StringSetting" : "Default"
},
"PRINTERS" : {
"Printer1" : { "StringSetting" : "Uno" },
"Printer2" : { "INCLUDE" : "ExtraSetting", "NumSetting" : 2, "StringSetting" : "Dos" },
"Printer3" : { "INCLUDE" : "ExtraSetting", "NumSetting" : 3 },
"ExtraSetting" : { "StringSetting" : "Tres" }
}
}
}

In this example, it contains entries to support three different printer models ("Printer1", "Printer2", and "Printer3") and each model has two settings ("NumSetting" and "StringSetting"). The setting values are:

Printer NumSetting StringSetting
Printer1 1 Uno
Printer2 2 Dos
Printer3 3 Tres

The Printer1 object demonstrates the two simplest cases. It doesn’t specify a NumSetting value, so it simply inherits a value of 1 from the DEFAULTS object. Conversely, it does specify a StringSetting value of "Uno", which overrides the value of "Default" from the DEFAULTS object.

The Printer2 object illustrates how only the first occurrence of a value is used. In this case, the StringSetting value of "Dos" overrides the value of "Default" from the DEFAULTS object. However, by the time the ExtraSetting object is parsed, a non-default StringSetting value has already been found. As a result, the parser discards the "Tres" value.

The Printer3 object demonstrates that the ExtraSetting object can override the "Default" value, but only because the Printer3 object itself doesn’t specify the StringSetting value directly.

Specify an Array of Bytes

According to the JSON standard, an array of bytes would be specified by an array of numerical values. While this notation is still supported, the Printing API also allows applications to specify a byte array via a simple string value. When it detects the array bracket characters ‘[‘ and ‘]’ inside a string, the JSON parser will automatically translate the string into a series of bytes. The following example demonstrates several different ways to specify a simple escape sequence:

{
"LINEPRINTERCONTROL" : {
"FormatVersion" : "1.0.0.0",
"DEFAULTS" : {
"BoolSetting" : true, "NumSetting" : 42, "StringSetting" : "Default"
},
"PRINTERS" : {
"COMMENT" : "All of these printers have the same ByteSetting value",
"Printer1" : { "ByteSetting" : [ 27, 119, 33, 0 ] },
"Printer2" : { "ByteSetting" : "[0x1b,w,!,0x00]" },
"Printer3" : { "ByteSetting" : "[0x1bw!0x00]" },
"Printer4" : { "ByteSetting" : "[\u001bw!\u0000]" },
"Printer5" : { "ByteSetting" : "[\u001b,w,!,\u0000]" }
}
}
}

The Printer1 object uses the standard JSON array of number values method, while the remaining objects use the special string processing functionality.

The Printer2 object uses the legacy method of specifying hexadecimal values using "0x" followed by two hex digits. This matches the format used in the .NET LinePrinter configuration file. The Printer3 object uses the same notation, but omits the comma separators.

The Printer5 object uses the JSON escape sequence for hexadecimal characters (\u followed by four hex digits) to specify the byte values. And the Printer4 object uses the same escape sequence but omits the comma separators.

There are several important rules to follow when using special byte array character strings:

Label Printing Commands and Attributes

The Printing API supports both receipt printing and label printing via the same LINEPRINTERCONTROL JSON object although the settings in the DEFAULTS object mostly target receipt printing. The label printing commands and attributes follow similar rules described in the previous sections.

Label Printer Entries

The label printer entries are defined in the PRINTERS object like the receipt printers. You should override the Initialize and NormalFont settings for label printer entries as shown below:

"PRINTERS":
{
"PB22_Fingerprint":
{
"DisplayName":"PB22 Bt Label Printer",
"Initialize": [], "NormalFont": []
}
}

The Printing API sends the Initialize commands followed by the NormalFont commands to the printer after a connection is successfully established. Unless these settings are overridden, the ESC/P commands defined for Initialize and NormalFont in the DEFAULTS object are sent. This may not work well with label printers. In the above example, both Initialize and NormalFont settings were set to an empty array so no commands are sent after the printer connection is opened. You may customize these settings if you wish to initialize the printer with specific printer commands.

Label Definitions

To print labels, you also need to define the commands to instruct the printer to print the label with a certain layout. The Printing API supports both raw label data stream and storing and invoking a label format on the printer. It also supports variable substitutions in the data stream or label format.

The label definitions are defined in the LABELS object in groups. Each label group is an object whose name identifies the group. In the following example, the LABELS object contains one group identified by the name of "2in_FingerprintLabels". This group contains two label definition objects, ItemLabel and URL_QRLabel.

"LABELS":
{
"2in_FingerprintLabels":
{
"ItemLabel":
{
"LabelDataStream": "DIR 4:AN 7:PP 30, 120:FT \"Swiss 721 Bold Condensed BT\",16:PT \"ItemName$$\":PP 120,75:BARSET \"CODE128\",3,1,4,150:PB \"ItemNo$$\":PP 280, 260:FT \"Letter Gothic 12 Pitch BT\",14:PT \"ItemNo$$\":PF\r\n",
"VarPostfix": "$$"
},
"URL_QRLabel":
{
"StoreFormat": "INPUT ON\r\nLAYOUT INPUT \"URLQRLABEL.LAY\"\r\nDIR 4:AN 7:PP 100, 20:FT \"Swiss 721 Bold Condensed BT\",16:PT VAR1$:PP 200, 20:FT \"Letter Gothic 12 Pitch BT\",14:PT VAR2$:PP 70,450:BARSET \"QRCODE\",1,1,8,2,2:PB VAR3$\r\nLAYOUT END\r\nINPUT OFF\r\n",
"InvokeFormat": "INPUT OFF\r\nFORMAT INPUT \"#\",\"@\",\"|\"\r\nINPUT ON\r\nLAYOUT RUN \"URLQRLABEL.LAY\"\r\n#qTextLine1$|qTextLine2$|qURL$|@\r\nPF\r\nINPUT OFF\r\n",
"VarPrefix": "q",
"VarPostfix": "$"
}
}
}

The label definition object may contain one or more of the following members:

Each label definition object needs to contain either a LabelDataStream member or an InvokeFormat member. If both members are specified, the Printing API only uses the LabelDataStream member.

The Printing API will substitute the variables defined in the LabelDataStream and the InvokeFormat members with the data specified in the API method. A complete variable name includes the VarPrefix and the VarPostfix values. For instance, the "qURL$" variable name specified in the InvokeFormat above starts with "q" (VarPrefix) and ends with "$" (VarPostfix). The purpose of the prefix and postfix is to distinguish the variable name from other printer commands.

The Printing API method takes key-value pairs for the variable substitutions where each key specifies the variable name (without prefix and suffix) and the key value specifies the data to replace the variable with. The Printing API will form the complete variable name based on the VarPrefix and VarPostfix settings. For more information, please refer to the language specific API documentation.

Include Label Groups in Printer Settings

You may use the LABEL_x member to include a label group to the printer settings, where x is a number to make the member name unique. For instance, the following example includes the 2in_FingerprintLabels label group. Now the application can use the Printing API to print either the ItemLabel or the URL_QRLabel to a printer using the PB22_Fingerprint settings.

"PRINTERS":
{
"PB22_Fingerprint":
{
"DisplayName":"PB22 Bt Label Printer",
"LABEL_01": "2in_FingerprintLabels",
"Initialize": [], "NormalFont": []
}
}

Printer Status Commands and Attributes

The Printing API provides methods for retrieving the current state of specific printer attributes like paper presence and battery condition. These status retrieval commands are controlled by a special STATUS object within the LINEPRINTERCONTROL JSON object. The STATUS object contains one or more status name/value pairs linked to different printers in the PRINTERS object through the special keywords STATUS_QUERIES and STATUS_EVENTS (reserved for future use).

Status Query Entries

Adding support for status query functionality to the JSON object is fairly similar to adding shared include sections or label sections.

First, a link is added to the printer object that ties a printer entry to the appropriate query status section later in the JSON object. That link is identified by the string value specified by the STATUS_QUERIES keyword.

Next, a query object matching that value is added to the STATUS object. That query object contains all the settings necessary to perform the status request on the printer.

The following sample illustrates a JSON object containing two different printers (Printer1 and Printer2) that both share the same status query object (Common_StatusQueries):

"LINEPRINTERCONTROL":
{
    "FormatVersion": "1.0.0.0",
    "PRINTERS":
    {
        "Printer1":
        { "PrinterNumber": 1, "STATUS_QUERIES": "Common_StatusQueries" },
	"Printer2":
        { "PrinterNumber": 2, "STATUS_QUERIES": "Common_StatusQueries" }
    },
    "STATUS":
    {
        "Common_StatusQueries":
        {
            "QUERIES":
            [
                {
                    "GetStatusCommand": "[0x1b,{,S,T,?,}]",
                    "StatusInitTimeout": 5000,
                    "StatusGapTimeout": 500,
                    "StatusEndResponse": "[}]",
                    "RESPONSES":
                    [
                        { "PrinterMsg" : "[P,:,N]", "MsgNo" : 223 },
                        { "PrinterMsg" : "[B,:,V]", "MsgNo" : 226 }
                    ]
                }
            ]
        }
    }
}

As seen in the preceding example, the Common_StatusQueries object consists of a single QUERIES object whose value is an array of possible query objects. In this example, we only have a single query object, but on some printers more than one action may be required to retrieve all of the desired information.

The query object contains several values that control how the Printing API acquires the status information from the printer:

In addition to those values, a status query object normally contains an array of possible printer responses. This array is identified by the reserved RESPONSES keyword. Each response object contains two pieces of information:

In the preceding example, there were two potential responses identified by the P:N and B:V byte sequences. The status query logic would simply read through the bytes returned by the printer looking for either the P:N or B:V character sequence. If the sequence P:N was found in the reply, then the value 223 is returned, while if B:V were detected, then 226 is returned. Also, if both sequences occurred in the printer reply, then both values would be returned by the status query.