Decoding Code 39

January 31, 2009 | John Dybowski

Code 3 of 9
Code 39 is a barcode with a full alphanumeric character set. Additionally, it includes a unique start and stop code (*) and seven special characters (- . $ / + % and space). The name 39 is derived from its code structure, which consists of three wide elements out of a total of nine elements - 3 of 9. These nine elements are comprised of five bars and four spaces. An inter-character gap separates adjacent characters.

Table 1 - Code 39 Encoding

Code 39 uses just two element widths, characterized as narrow and wide. By convention, a narrow element is called the X dimension. All X dimensions must be of equal size within the symbol. The dimension of a wide element is a multiple of X. This ratio can vary within certain limits but once selected must remain consistent throughout the symbol. Generally, a wide to narrow ratio in the range of 2:1 to 3:1 is acceptable.

Code 39 is classified as a discreet code, in that the characters each stand alone being separated from each other by an inter-character gap. Since the inter-character gap is not an integral part of the character encoding it can be loosely toleranced, generally between X and 3X.

A special start/stop code is defined as an ASCII '*'. Its purpose is to denote the leading and trailing ends of a Code 39 symbol. The bar/space pattern of this code is unique and allows the symbol to be bi-directionally scanned. Table 1 shows the Code 39 code assignments for all available characters. Note how the last four characters in the table don't fit the established coding pattern where all the other characters have two wide bars and one wide space of the three wide elements. An example of the Code 39 character "A" encoding is shown in Figure 1.

Figure 1 - Code 39 Character 'A' Encoding


Combining the discreet encoding attribute with the fixed 3 of 9 structure results in a code that is classified as self checking. This makes the possibility of a mis-decode much less likely since a substitution error can only occur if two or more elements are misinterpreted. This could happen, for example, if a spot on a narrow bar lined up with a void on a wide bar in the same scan line and if the resulting bar pattern turned out to be a legal Code 39 character.

Figure 2 - A Complete Code 39 Barcode Symbol

In addition to the bars and spaces that make up a barcode characters and the inter-character gaps that separate these characters, there is one more component to a Code 39 symbol. This is the quiet zone, free and clear of any printing, to either side of the "picket fence" pattern. The quiet zone must be at least 10 times the X dimension. Now, with this information we can take the pattern of bars and spaces to assemble a start code, some data characters, and a stop code. Framing this with the requisite quiet zones results in a complete barcode symbol shown in Figure 2.

Decoding 39
In keeping with my goal of providing a simplified development framework, I'll demonstrate just the essence of a Code 39 decoding algorithm, which is an implementation of the logic described in the AIM (Automatic Identification Manufacturers) Reference Decode Algorithm for USS-39.

At this point it would be useful to make a couple of general observations. The decode algorithm I'm presenting contains the basic steps for deciphering a Code 39 symbol. The underlying logic is sound but ccould be expanded upon. For example, you might wish to add secondary checks for acceleration, inter-character gap, and absolute dimensions. Realize, that these secondary checks could add as much code as the basic algorithm itself. As a result, the underlying logic of the algorithm could be significantly obscured.

It's not unusual to encounter barcode labels that aren't up to the specification for a variety of reasons. This may be due to dimensional tolerance problems, ink spread, poor print contrast ratio, inadequate quiet zone, etc. And just because the barcode label is deficient doesn't mean people don't expect you to be able to read it. So these are good reasons why the reference decode algorithm should be just a starting point.

The basic steps of the Code 39 decode algorithm are:

You'll notice that the algorithm assumes the samples were collected in a forward direction and makes no attempt to determine if the scan was actually performed in reverse. To handle this situation, if the initial decode fails, the sample buffer is simply reversed and the algorithm is invoked once again. This approach simplifies the code and its testing.

A number of techniques can be applied to help the algorithm to read marginal and out-of-spec barcode labels. Even with today's printer technology, poor barcode labels continue to be produced. Generally, the problem lies with the print contrast ratio and ink spread. Ink spread results in the bars being larger and the spaces being proportionally smaller. As the decode algorithm calculates the character width based on the total of all the bars and spaces of the character, and the resulting narrow/wide threshold is applied to both the bars and spaces, variations in the bars and spaces for a given multiple of the X dimension can lead to decode problems. It turns out that it's easy to employ an alternate technique to calculate a separate threshold for the bars and a separate threshold for the spaces, which is the way some of the newer Barcodes are designed. This techniques works well until you get to the last four character in the Code 39 table. These don't conform to the established code structure used by all the other characters where, of the three wide elements, two are bars and one is a space; the last four characters all have three wide spaces. A reasonable strategy would be to utilize the special bar and space reference only if the primary algorithm fails to decode. This is the tactic I take in my Code 39 decode algirithm.

The primary algorithm can also be enhanced by taking multiple iterations through the sample buffer, judicially modifying the reference multiplier on each pass. Although these tricks might be useful when trying to read deficient symbols, you can be assured they're not going to improve your mis-decode rate.

Optional Check Digit
A check digit is seldom used with Code 39 but if one is needed for a specific application there's a standard method used to calculate one. The check digit is the modulo 43 sum of all the data character values in the symbol. It is placed as the last data character of the symbol.

For Example
Data: 12345ABCDE/
Sum of data values: 1 + 2 + 3 + 4 + 5 + 10 + 11 + 12 + 13 + 14 + 40 = 115
115 divided by 43 = 2 with a remainder of 29
Referring to Table 2, 29 yields the character T, which is the check digit
Data with check digit: 12345ABCDE/T

Table 2 - Character/Value Set for Code 39 Check Character Calculation
Char Value Char Value Char Value Char Value 0 0 B 11 M 22 X 33 1 1 C 12 N 23 Y 34 2 2 D 13 O 24 Z 35 3 3 E 14 P 25 - 36 4 4 F 15 Q 26 . 37 5 5 G 16 R 27 space 38 6 6 H 17 S 28 $ 39 7 7 I 18 T 29 / 40 8 8 J 19 U 30 + 41 9 9 K 20 V 31 % 42 A 10 L 21 W 32