Code 39 can include upper case letters, numbers and limited punctuation. When planning or designing forms that will have bar codes on the, allow for the following space.
Minimum bar code space when document will be scanned
# characters of data don't count start/stop characters |
length (in) | height (in) |
---|---|---|
including quiet zone | ||
4 | 1.3 | 0.3 |
5 | 1.5 | 0.4 |
6 | 1.7 | 0.4 |
7 | 1.9 | 0.5 |
8 | 2.1 | 0.5 |
10 | 2.5 | 0.6 |
12 | 2.9 | 0.7 |
14 | 3.3 | 0.8 |
16 | 3.7 | 0.9 |
18 | 4.1 | 1.0 |
20 | 4.5 | 1.1 |
These sizes will work well for documents that will be scanned at 200 dpi (normal setting
for business document capture) or faxed. Faxes with bar codes should not be sent in the older
low-resolution fax setting, which was 100 dpi.
The bar code elements that lead to these recommendations are:
narrow bar width: .011 in (2.2 pixels at 200 dpi, or 1.1 pixels at 100 dpi which is barely hanging on for a low-res fax)
intercharacter gap: .053 in (the bar code 39 spec)
wide to narrow bar ratio: 2.5 (2.2 is acceptable but only makes the code slightly smaller)
width to height ratio: 0.26, which tolerates 15° of skew when scanning.
(a ratio of 0.15 is accpetable, but requires scanning to less than 9° of skew)
quiet zone: .11 in, minimum white space on left and right of the bars.
There is no space required above or below the bars.
Check Your Bar Code 39After you print your bar code, check that it conforms to the Bar Code 3 of 9 specification. Here's how a visual inspection can be easily accomplished:
|
|
Character | Value | Character | Value |
0 | 0 | M | 22 |
1 | 1 | N | 23 |
2 | 2 | O | 24 |
3 | 3 | P | 25 |
4 | 4 | Q | 26 |
5 | 5 | R | 27 |
6 | 6 | S | 28 |
7 | 7 | T | 29 |
8 | 8 | U | 30 |
9 | 9 | V | 31 |
A | 10 | W | 32 |
B | 11 | X | 33 |
C | 12 | Y | 34 |
D | 13 | Z | 35 |
E | 14 | - | 36 |
F | 15 | . | 37 |
G | 16 | space | 38 |
H | 17 | $ | 39 |
I | 18 | / | 40 |
J | 19 | + | 41 |
K | 20 | % | 42 |
L | 21 |
Acordex recommends the use of a checksum for all bar codes. Even though the character codes themselves are self-checking, damaged images (such as white or black vertical stipes can occur on faxes) can create valid but incorrect bar codes. The code with check digit is referred to as Code 39 mod 43.
Here is how to do the checksum calculation:
def append_c39_checksum(st): charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" return st + charset[ sum(charset.index(c) for c in st) % 43 ]
Const charSet As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" Function Mod43(C39 As String) As String For i = 1 To Len(C39) total = InStr(charSet, Mid(C39, i, 1)) - 1 + total Next i Mod43 = C39 & Mid(charSet, (total Mod 43 + 1), 1) End Function
' compute checksum for Code 39, translated by antiguide ' paste the code in a .vbs file (MsWindos) dim charSet charset= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" dim rejected ' string rejected="" dim total ' integer total=0 dim c39 c39=inputbox ("Code to generate: ") For i = 1 To Len(C39) dim rank rank= InStr(charSet, Mid(C39, i, 1)) - 1 if (rank >= 0) then total = total +rank else rejected=rejected & Mid(C39, i, 1) end if Next if rejected = "" then msgbox c39 & Mid(charSet, (total Mod 43 + 1), 1) else msgbox "wrong characters: " & rejected end if
public static final String charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; public static char getChecksum(String barCode) throws Exception { int total = 0; CharacterIterator it = new StringCharacterIterator(barCode); for (char ch = it.current(); ch != CharacterIterator.DONE; ch = it.next()) { int charValue = charSet.indexOf(ch); if (charValue == -1) { // Invalid character. throw new Exception("Input String '" +barCode+ "' contains characters that are invalid in a Code39 barcode."); } total += charValue; } int checksum = total % 43; return charSet.charAt(checksum); }
public string ValidateMod43(string barcode) { int subtotal = 0; const string charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; foreach (char c in barcode) subtotal += charSet.IndexOf(c); return charSet[subtotal%43].ToString(); }
use List::Util qw(sum); use feature 'state'; sub checksum { state $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%'; return substr( $charset, sum( 0, map { index $charset, $_ } split //, shift ) % 43, 1 ); }
function checksum( $string ) { $checksum = 0; $length = strlen( $string ); $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%'; for( $i=0; $i < $length; ++$i ) { $checksum += strpos( $charset, $string[$i] ); } return $charset[ $checksum % 43 ]; }
proc checksum string { set checksum 0 set charset "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" foreach char [split $string ""] { if {-1 == [set value [string first $char $charset]]} { return -code error "Wrong Code39 character:$char" } incr checksum $value } return [string index $charset [expr {$checksum % 43}]] }
The above examples are excerpted from Wikipedia.
Try a checksum calculation.
Input string:
Mod 43 checksum: