Bar Codes


4D - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find

Bar Codes

By Eric Juhel, 4D Developer

Technical Note 02-20

Technical Notes for Technical Notes for 02-05 May, 2002

Summary


Bar codes are part of an automatic identification technique that is broadly used in stock management, production management, shipment tracing, libraries, picture libraries, etc.

This technical note demonstrates a technique for for creating, displaying and printing code bars that match standard codes. Considering that bar codes will depend on the symbology used or the activity requirements, we will describe the four following codes: EAN 39 (European Article Numbering), EAN 128, UPC (Universal Product Coding), and the EAN 13.

The techinique used for all four examples is identical, the most difficult part being the creation of two 1 by 1 pixel pictures in the picture library.

Principle


Bar codes were designed in the early 1950's but were not actually implemented until the 1970's. The principle of bar coding is to alternate spaces and black bars in order to represent characters. Each subgroup represents one character of the encoded string. The character that matches a combination in a subgroup is described in the standard definition.

Some bar codes are numerical only (UPC. EAN), while others have have a fixed length (UPC-A consists of 12 numbers, UPC-E consists of 6 numbers and EAN-13 and EAN-8 consists of, respectively 13 and 8 numbers). Furthermore, some bar codes use alphanumerical characters and control characters (Code 93, Code 128 and code 39).

The principle could be summed up like this: Place black and white pixels side by side in a picture and vertically resize that picture so that it complies to the standard size.

Creating Pictures in the Library


To store two pictures in the picture library that are 1 by 1 pixel in size, you can just create two empty pictures in the picture library, assign them a size of 1 by 1 pixel, and, then assign a black background to one of them.

After this is done now, go through the definition of the bar code standards to implement thr proper functions.

Bar Code EAN 39


The code EAN 39 is an alphanumerical code that encodes 43 characters: numbers from 0 to 9, uppercase letters A through Z in addition to the symbols "_", ".", "*", "/", "%", "$", "+" and the space bar. It also includes a delimiter character that is found at the beginning and end of the message.

A "word" in EAN code breaks down as follows:

1- a space

2- the beginning character (delimiter)

3- the message contents

4- the ending character (delimiter)

5- a space

Each character is represented by nine elements: five bars for even ranks, and four spaces for odd ranks. Among these elements two bars and a space are wider than the other 6 elements. This structure type where 3 elements out of nine are wider gave the code its name (EAN 39).

In some cases, the word is to be completed by a control character. This character is the "modulo" 43 of the sum of all characters in the word. The values for the characters in EAN 39 is established as follows:

Character   Value

00
11
22......
A0

......

Z35
dash36
period 37
space38
*39
$40
/41
+42
%43

How do you compute the width of a symbol in EAN 39?

The length of a EAN 39 code can be determined by the following formula, where W is the width of the narrower elements and R is the multiplying factor that defines the wider elements.

Parameters

M1, M2 - Margins

Margins have to be at least 6 mm or 10 times the width of the narrowest number

N - Number of characters to code

16 x W - width of data characters, including the spaces between characters

31 x W - width of the beginning and ending characters, including spaces between the beginning character and the data

16 x W - Width of the optional control character

Printing Width = N (3WR +7W) + 6RN + 13 N + (3RN + 7N) + M1 +M2

Implementing the function EAN_EditBarcode_39

   C_LONGINT($0;$error)  `error
   C_POINTER($1;$pict_BarCode)  `pointer to barcode picture
   C_TEXT($2)  `text to encode
   C_TEXT($string_entered;$vCode_Alpha)  `string for retrieving
   C_PICTURE($black_pixel)  `Black pixel out of library
   C_PICTURE($white_pixel)  `White pixel out of library
   C_LONGINT($modulo;$sum)  `check sum
   C_LONGINT($found)  `array index
   C_LONGINT($j;$i)  `loop counters
   C_PICTURE($picture;$pixel)  `final picture and bar for final build
   C_BOOLEAN($control)  `True if control character needs to be there
   
   ARRAY LONGINT($tl_code;0)
   ARRAY TEXT($ta_code;0)
   
   $pict_BarCode:=$1
   $string_entered:=$2
   
   If (Count parameters=3)
      $control:=True
   End if 
      
   If (Length($string_entered)>0)  `If there is a string to code
      
      GET PICTURE FROM LIBRARY(1000;$black_pixel)
      GET PICTURE FROM LIBRARY(1001;$white_pixel)
      
   If (Picture size($black_pixel)>0) & (Picture size($white_pixel)>0)  `Do the pictures exist?
   
         `loading choice list
      LIST TO ARRAY("Characters_set_39";$ta_code;$tl_code)
      
      If (Size of array($ta_code)>0)  `Do the choice lists exist?
          
         For ($i;1;Length($string_entered);1)  `Looping through the length of the string
               `researching the rank of the character using its ASCII code    
            $found:=Find in array($tl_code;Ascii(Uppercase($string_entered[[$i]])))
            
            If ($found>0)  `if the rank was retrieved
               $code:=$ta_code{$found}  `retrieving the 9 elements of the code
                  For ($j;1;9;1)  `looping to interpret the 9 elements
                     If (($j/2)#($j\2))  `if the position is odd
                        $pixel:=$black_pixel  `working with the black pixel
                     Else 
                        $pixel:=$white_pixel  `working with the white pixel
                     End if 
                     If ($code[[$j]]="1")  `if code 1 then it has to be thicker
                        $pixel:=$pixel*+3
                     End if 
                      $picture:=$picture+$pixel  `adding the current bar to the final picture
                  End for 
               End if 
               $picture:=$picture+$white_pixel  `adding a space as character separator
               If ($control)  `if control character is needed
                  $sum:=$sum+($found-1)  `there is a difference of 1 between the rank and actual value
               End if 
            End for 
               
            If ($sum>0)  `if control character is needed
               $modulo:=($sum/43)-1  `substracting 1 to match the value in the choice list
               $code:=$ta_code{$modulo}  `retrieving the 9 elements of the code
               For ($j;1;9;1)  `loop to interpret the 9 elements
                  If (($j/2)#($j\2))  `if an odd position
                     $pixel:=$black_pixel  `working with black pixel
                  Else 
                     $pixel:=$white_pixel  `working with white pixel
                  End if 
                  If ($code[[$j]]="1")  `if code 1 then increased thickness
                     $pixel:=$pixel*+3
                  End if 
                     $picture:=$picture+$pixel  `adding the current bar to the final picture
               End for 
            End if   ` If ($sum>0)
            
            $picture:=$picture*/60  `vertical size for picture
            $pict_BarCode->:=$picture  `assigning the picture to the picture displayed
            $error:=0  `no error
            
         Else 
               `choice list is missing
            ALERT("Resource error for the choice list...")
            $error:=1
         
         End if 
            
      Else 
      
         `picture in library error
         ALERT("Resource error for the pictures...")
         $error:=2
         
      End if 
    
   Else 
      `error with the string entered
      ALERT("The string to encode is empty...")
    $error:=3
   
   End if 
   
   
   $0:=$error
   

The code for each character is stored in a choice list named "Characters_Set_39". Using a choice list lets us define a reference number for each element in the list. We chose this reference to be the ASCII code of the encoded character.

The function proceeds in several steps:

1 - string to encode is recognized and characters are processed one by one

2 - identifying the character using its ASCII code

3 - researching the 9 elements of the code that matches the character

4 - selecting the black or white pixel based on the rank of the character (odd or even).

5 - taking into account the value of the element (0 or 1) to manage the width of the bar

6 - taking into account a possible control character

Bar Code EAN 128


The code EAN 128 is an alphanumerical code that encodes 103 of the ASCII characters. Each character encoding consists of playing on the distance between three spaces and bars which is the equivalent of putting 11 elements side by side. A bar or a space can be one, two, or three elements side by side. Bars are always in an even position and spaces are always in an odd position.

There are three ways for encoding a string in EAN 128, depending on the nature of the characters it includes. These ways are commonly referred to as code A, code B and code C.

Code A applies to strings with uppercase letters only.

Code B applies to strings with both uppercase and lowercase letters.

Code C applies to strings with pair-grouped numbers.

The coding also includes a beginning character which will depend on the encoding method used, and ending character that is common to the three encoding types. Finally, there will be a control character which is a the modulo 103 of the sum of all characters weighted by their position.

An example: the string "DIMENSION"

The presence of only uppercase characters leads to the use of code A, which makes the beginning character "A". This character is not taken into account in the computation of the control character.

Implementing the function EAN_Edit_Barcode_128

As with the previous encoding, the mapping of the characters is stored in a choice list named Characters_Set_128 which allows us to define a reference number for each item. The last four characters in the list represent the beginning and ending characters.

As with the previous code, the reference used is the ASCII value of the coded character. For the beginning and ending characters, that reference is arbitrary and not significant.

The function proceeds in several steps:

1 - identifying the code type to use (A, B or C)

2 - computing the control character

3 - updating the string to encode with the additional characters

4 - recognition of the string and processing each character, one at a time

5 - identifying characters using their ASCII code

6 - loading the element that matches the code

7 - taking the position (odd or even) into account to know which picture to use

8- weighting the pixel

Function EAN_Edit_Barcode_128

   C_LONGINT($0;$error)  `error
   C_POINTER($1;$pict_BarCode)  `pointer to bar code picture
   C_TEXT($2)  `text to encode
   C_TEXT($String_entered;$vCode_Alpha)  `retrieving string
   C_PICTURE($Black_Pixel)  `black pixel from picture library
   C_PICTURE($Black_Pixel)  `white pixel from picture library
   C_LONGINT($modulo;$somme)  `check sum
   C_LONGINT($Found)  `array indices
   C_LONGINT($j;$i)  `loop indices
   
   ARRAY LONGINT($tl_code;0)
   ARRAY TEXT($ta_code;0)
   
   $modulo:=103
   $somme:=$modulo
   $pict_BarCode:=$1
   $String_entered:=$2
   
   If (Length($String_entered)>0)
   
      GET PICTURE FROM LIBRARY(1000;$Black_Pixel)
      GET PICTURE FROM LIBRARY(1001;$White_pixel)
      
      If (Picture size($Black_Pixel)>0) & (Picture size($White_pixel)>0)
            `loading patterns and references
            `reference = ASCII code and the rank = value for referenced character
         LIST TO ARRAY("Characters_set_128";$ta_code;$tl_code)
            `a control character is mandatory for code 128. 
            `control character is modulo 103 of the weighted sum of all characters 
         
         If (Size of array($ta_code)>0)
               `computing remainder
            For ($i;1;Length($String_entered);1)
               `ASCII code is used as reference in choice list        
               `the index $found matches the rank of the character $i 
               `in the pattern definition
               $Found:=Find in array($tl_code;Ascii($String_entered[[$i]]))
               If ($Found>0)
                  $somme:=$somme+(($Found-1)*$i)  `weighting based on position
               End if 
            End for 
               `retrieving remainder
            $somme:=$somme\$modulo
            $vCode_Alpha:=$String_entered
                  `creating the string to code
            $String_entered:=Char(135)+$String_entered+Char($tl_code{$somme+1})+Char(138)
               `creating the string
               `calling patterns for each character (refer to references)
            For ($i;1;Length($String_entered);1)
               $Found:=Find in array($tl_code;Ascii($String_entered[[$i]]))
               If ($Found>0)
                  $code:=$ta_code{$Found}
                  For ($j;1;Length($code);1)
                     If (($j/2)#($j\2))  ` if not in even position
                        $pixel:=$Black_Pixel  `then it is a bar
                     Else 
                        $pixel:=$White_pixel  `otherwise it is a space
                     End if 
                     $pixel:=$pixel*+(Num($code[[$j]]))  `multiplying by the value [[$j]]
                     $pict_BarCode->:=$pict_BarCode->+$pixel
                  End for 
               End if 
               $pict_BarCode->:=$pict_BarCode->+$White_pixel  `
            End for 
         
            $String_entered:=$vCode_Alpha
            
            $pict_BarCode->:=$pict_BarCode->*/30
            $error:=0
            
         Else 
               `choice list is missing
            ALERT("Resource error for the choice list...")
            $error:=1
            
         End if 
         
      Else 
         
         `erreur images bibliothèque
         ALERT("Resource error for the pictures...")
         $error:=2
         
      End if 
      
   Else 
      `error with the string entered
      ALERT("The string to encode is empty...")
      $error:=3
      
   End if 
   
   
   $0:=$error
   

UPC and EAN Bar Codes


The EAN code is a numerical code designed for retail businesses. In the US, this code is the UPC code. The UPC and EAN codes share some common traits:

1- They address numerical data only.

2- They both have two bars and two spaces by character.

3- There are seven modules per character.

4- There are four level codes, and a bar or a space can be 1, 2, 3, or 4 modules wide.

5- They both have a mandatory control character.

EAN 13 symbols encodes 12 or 8 digits, the most common case being 12 digits. The UPC coding includes three subtypes: A, B, and E. We will exploring the type A, which encodes 12 characters.

Example:

UPC A Code

The 12 coded characters break down into three categories:

1- The first character is a system number that is supposed to describe a context

2- The 10 next characters are the actual encoded data

3- The last character is the control character

Separators indicate the beginning, middle and end of the encoded data.

The UPC coding imposes a peculiar mechanism when it comes to representing numbers: each number is coded on 7 binary elements where 1 is a black bar and 0 is a space (white bar). What is very peculiar with that is that the right and left sections are using inverted binary representation.

Number mapping with the UPC mapping:

Computing the control character

The steps to compute the control character are as follows:

1 - starting from the right assigning successively the odd and even positions to characters (the rightmost character is always the odd position character)

2 - adding the values of characters that have an odd position and multiplying the total by three

3 - adding the values of characters that have an even position

4 - adding the previous results

5 - subtracting the resulting value from the next multiple of 10

6- the control character is the result

For example:

The sum is 85 and the next multiple of 10 is therefore 90, which makes a control character of 5.

Implementing the function EAN_EditBarcode_UPC_A

The coding of the 9 numbers is stored in a choice list named "Characters_set_UPCa". This list only lists the mapping for the left section. The right section will be processed using the same list but using an inverted process.

Code EAN 13


The numbering of the system code is the main difference between the the EAN and the UPC A code.

In the EAN code, the system code, which is usually the country, is coded on two or three characters. Please refer to the appendixes for a list of those codes.

Another unique feature of the EAN 13 code is how the characters of the left section are encoded: the coding is different depending on the "status" (Odd or Even) of the character. Here, we use the term status rather than position since, according to the EAN standard, the position is not the only criterion to be considered when defining a character as Odd or Even. The parity status also takes into account the value of the first character. Please note that the second character is always considered as having an odd parity. A reference table determines the parity of the elements of the left section, based on the first character.

Table 1: Parity of the characters of the left section

In addition to the number encoding, the EAN 13 standard uses a second table that indicates the bar code based on the parity of the character and the section in which it is located.

Table 2: EAN 13 character encoding

The steps to compute the control code are identical to those of the UPC code:

1- Starting from the right, assign successively the odd and even position to the characters (the rightmost character is always to be considered as odd).

2- Add the values of the odd-positioned characters and mulitiply the total by 3.

3- Add the values of the even-positioned characters.

4- Add both totals.

5- Subtract the resultiing value from the next multiple of 10 to get the control character.

6- Determine the parity of the characters of the left section.

To determine the parity, we will be using a choice list named "Odd_Even" that reflects the mapping described in table 1. In the table, "0" represents the odd parity and "1" represents the even parity.

Implementing the function EAN_EditBarcode_13

   
   C_LONGINT($0;$error)  `error
   C_POINTER($1;$pict_BarCode)  `pointer to code bar picture
   C_TEXT($2)  `text to encode
   C_TEXT($String_Entered)  `retrieving string
   C_PICTURE($black_pixel)  `Black pixel out of library
   C_PICTURE($black_pixel)  `White pixel out of library
   C_LONGINT($modulo;$sum)  `checksum
   C_LONGINT($found)  `array index
   C_LONGINT($j;$i)  `loop counters
   C_LONGINT($String_length)  `llength of the string to encode
   C_STRING(3;$Code_country)  `system code (country of origin)
   ARRAY LONGINT($tl_code;0)
   ARRAY TEXT($ta_code;0)
   ARRAY TEXT($ta_odd_even;0)  `parity mask for left section
   
   $pict_BarCode:=$1
   $String_to_encode:=$2
   
   $String_length:=Length($String_to_encode)
   
   If ($String_length#12) & ($String_length#13)
      ALERT("Entry error, "+Char(13)+"the length of the string should be 12 or 13 characters...")
    $error:=-1
   Else 
   End if 
   
   If ($error=0)
      
      ARRAY STRING(7;$ta_CaracteSet;20)
      LIST TO ARRAY("Characters_set_13";$ta_CaracteSet)
      LIST TO ARRAY("odd_even";$ta_odd_even)
      
      If ((Size of array($ta_CaracteSet)=0) | (Size of array($ta_odd_even)=0))
         ALERT("Resource error in the choice lists...")
         $error:=1
      End if 
      
      If ($error=0)
      
         ARRAY STRING(7;$ta_left_hand;10)
         ARRAY STRING(7;$ta_left_even_hand;10)
         ARRAY STRING(7;$ta_right_hand;10)
         
         GET PICTURE FROM LIBRARY(1000;$black_pixel)
         GET PICTURE FROM LIBRARY(1001;$white_pixel)
         
         If (Picture size($black_pixel)=0) & (Picture size($white_pixel)=0)
            ALERT("Picture resource error")
            $error:=2
         End if 
         
      End if 
      
      If ($error=0)
         
         $image:=$white_pixel*+17
         
         $image2:=$white_pixel*+17
         
         For ($i;1;10)
            $ta_left_hand{$i}:=$ta_CaracteSet{$i}
            $ta_right_hand{$i}:=$ta_CaracteSet{$i+10}
            $ta_left_even_hand{$i}:=$ta_CaracteSet{$i+20}
         End for 
         
         $Code_country:=""
            `left guard bars -> 101
         $image:=$image+$black_pixel+$white_pixel+$black_pixel
         $image2:=$image2+$black_pixel+$white_pixel+$black_pixel
         
         `the country
         Case of 
         : ($String_length=13)
            $Code_country:=Substring($String_to_encode;1;3)
            $Code_manufactury:=Substring($String_to_encode;4)
         : ($String_length=12)
             $Code_country:=Substring($String_to_encode;1;2)
            $Code_manufactury:=Substring($String_to_encode;3)
         : ($String_length<12)
            $Code_country:=""
         End case 
         
            `$odd_even ->  determines the parity of the elements of the left section
            `adding to identify its index in the list "Odd_Even"
            `"Odd_Even" -> array $ta_odd_even
            
         $odd_even:=Num($String_to_encode[[1]])+1
         
         If ($Code_country#"")
            
               `computing the control character on 12 characters
               `as the last character is always considered with an odd parity
               `inverting if the position is even -> it is considered odd
               
             $check:=0
               For ($i;12;1;-1)
                  If (($i/2)#($i\2))  `odd position
                     $check:=$check+(Num($String_to_encode[[$i]]))  `even parity
                  Else 
                     $check:=$check+(Num($String_to_encode[[$i]])*3)  `odd parity
                  End if 
               End for 
               
               $check_S:=String($check)
               $check:=10-Num(Substring($check_s;Length($check_s)))  `10-extract the last number
               
               $String_to_encode:=$String_to_encode+String($check)
               $codealpha:=Substring($String_to_encode;2)  `encoding after second character
               
               $image:=$image | $image
               $image2:=$image2 | $image2
                  `Left Hand bars
               For ($i;1;6;1)
                  $digit:=Num($codealpha[[$i]])+1  
                     `since we encode only after the second character => shifting $i by 1
                  If ($ta_odd_even{$odd_even}[[$i]]="0")  `ODD 
                     For ($rang;1;7;1)
                        If ($ta_left_hand{$digit}[[$rang]]="0")
                           $image:=$image+$white_pixel
                        Else 
                           $image:=$image+$black_pixel
                        End if 
                        $image2:=$image2+$white_pixel
                        $image:=$image | $image
                        $image2:=$image2 | $image2
                     End for 
                  Else   `-> EVEN PARITY
                     For ($rang;1;7;1)
                        If ($ta_left_even_hand{$digit}[[$rang]]="0")
                           $image:=$image+$white_pixel
                        Else 
                           $image:=$image+$black_pixel
                        End if
                        $image2:=$image2+$white_pixel
                        $image:=$image | $image
                        $image2:=$image2 | $image2
                     End for 
                  End if 
            
            End for 
            
               `center guard bars -> 01010
            $image:=$image+$white_pixel+$black_pixel+$white_pixel+$black_pixel+$white_pixel
            $image2:=$image2+$white_pixel+$black_pixel+$white_pixel+$black_pixel+$white_pixel
            
               `Right Hand bars
             For ($i;7;12;1)
               $digit:=Num($codealpha[[$i]])+1
               For ($rang;1;7;1)
                  If ($ta_right_hand{$digit}[[$rang]]="0")
                     $image:=$image+$white_pixel
                  Else 
                     $image:=$image+$black_pixel
                  End if 
                  $image2:=$image2+$white_pixel
               End for 
            End for 
            
               `right guard bars -> 101
            $image:=$image+$black_pixel+$white_pixel+$black_pixel
            $image2:=$image2+$black_pixel+$white_pixel+$black_pixel
            
            $image:=$image*/40
            $image2:=$image2*/5
            $image:=$image/$image2
            
            $text_low:=Substring($Code_country;1;1)+(" "*5)+
            Substring($String_to_encode;2;6)+(" "*5)+Substring($String_to_encode;8)+(" "*5)
            $chart:=CT New offscreen area 
            $text:=CT Draw text ($chart;0;0;120;12;$text_low)
            CT SET TEXT ATTRIBUTES ($chart;$text;CT Font number ("Helvetica");10;Plain ;
            CT Index to color (16);0)
            $picture_text:=CT Area to picture ($chart;$text)
            CT DELETE OFFSCREEN AREA ($chart)
            $picture_text:=($picture_text/41)
            $image:=$image & $picture_text
            
            $pict_BarCode->:=$image
            
         End if 
      
      End if 
   
   End if 
   
   

Particularity of the ISBN code (International Standard Book Number):

The ISBN code is destined to publishers and uses the EAN 13 coding. It corresponds to a 9-character string to which a control character is added. The code is divided into four distinct parts.

Examples:

The book 4D Expert has the following ISBN code: 2 - 212 -09163 - X which breaks down as follows:

- 2 represents the language or the country of origin

- 212 represents the publisher

- 09163 is a number assigned by the publisher

- X is the control character

To create the ISBN bar code, we used a method similar to the EAN 13 with a system code of 978. In other words, we coded the string: 978 2212 09163

Computing the control character for the ISBN code

The control character's computation is based on the sum of the 9 values, each weighted with it own coeficient. The coeficient value begins with 1 for the rightmost character and is incremented by one each time the character position is shifted to the left. The sum is then divided by 11 and the control character is the result of the substraction 11 - division remainder. When the result equals 10, the control character is the letter "X".

EAN 39 Mapping:

EAN 128 Mapping:

Main ountry codes for the ISBN encoding:

0 English )(UK,US,Australia,NZ,Canada,

1 English )South Africa,Zimbabwe)

2 French (France,Belgium,Canada,Switzerland)

3 German (Germany,Austria,Switzerland)

4 Japan

5 USSR

7 China

84 Spain

87 Denmark

88 Italian (Italy,Switzerland)

91 Sweden

92 International

Additional references:

http://www.barcodeisland.com/symbolgy.phtml

http://www.adams1.com/pub/russadam/barcode1.html


4D - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find