EAN-8 Barcode Generator

MG Oct 5th 2008 - I recently bought a cheap barcode scanner to play with, and am trying to reproduce the barcodes it scans on-screen. Based very, very heavily on PS's code for EAN-13 generation, here's similar code which produces EAN-8 barcodes. You can find the spec for EAN-8 that I used here [1 ].

# EAN 8 barcode generation
# Specification described at http://www.barcodeisland.com/ean8.phtml
# Based heavily on code by Pascal Scheffers from https://wiki.tcl-lang.org/10538

proc ean8_csum {number} {

  set sum 0

  foreach {odd even} [split "[string range ${number} 0 6]0" ""] {
    incr sum [expr {$odd*3}]
    incr sum [expr {$even*1}]
  }

  set check [expr {$sum % 10}]
  if { $check > 0 } {
       return [expr {10 - $check}]
     }

  return $check;

};# ean8_csum

proc ean8 {number} {

  if { [string length $number] != 7 && [string length $number] != 8 } {
       puts "Must be 7 or 8 digits long"
       return;
     }

  # EAN8 digits, the ones represent black bars, the zeroes white space.
  # Two pairs of digits: lefthand-odd(A) and righthand

  set digits {
    {0 0001101 1110010}
    {1 0011001 1100110}
    {2 0010011 1101100}
    {3 0111101 1000010}
    {4 0100011 1011100}
    {5 0110001 1001110}
    {6 0101111 1010000}
    {7 0111011 1000100}
    {8 0110111 1001000}
    {9 0001011 1110100}
  }

  # If we get a 7 digit number, append the checkdigit to that. Otherwise, verify checkdigit.
  set csum [ean8_csum [string range $number 0 6]]
  if { [string length $number] == 7 } {
       set number $number[ean8_csum $number]
     } elseif { [string index $number 7] != $csum } {
       puts "Invalid code"
       return;
     }

  # All EAN8 codes start with 'left guard bars':
  lappend bars 101

  # First four digits:
  foreach digit [split [string range $number 0 3] ""] {
    lappend bars [lindex [lindex $digits $digit] 1]
  }

  # center guard bars:
  lappend bars 01010

  # the right hand chars, all encoded the same:
  foreach digit [split [string range $number 4 8] ""] {
    lappend bars [lindex [lindex $digits $digit] 2]
  }

  # and the final guards:
  lappend bars 101

  return [list $bars $number];
};# ean8

# Tk demo code:

package require Tk

wm title . "EAN-8 Barcode"

label .lbar -text "Barcode"
entry .barcode -textvariable barcode -width 15
button .show -text show -command do_display
bind . <Return> [list .show invoke]
grid .lbar .barcode .show -sticky nw

canvas .c -width 200 -height 100

grid x .c - -sticky nw

proc do_display { } {
  global barcode
  if { [string length $barcode] < 7 } {
        bell -displayof .
        return;
     }

  .c delete all
  set b [ean8 $barcode]

  set x 25
  foreach barset [lindex $b 0] {
    set bars [split $barset ""]
    if { [llength $bars] == 7 } {
         set len 40
       } else {
         set len 46
       }
    foreach bar $bars {
      incr x 1
      if { $bar } {
           .c create line $x 15 $x [expr $len+15]
         }
    }
  }

  # And create the human readable text below it:
  .c create text 43 60 -text [string range [lindex $b 1] 0 3]
  .c create text 75 60 -text [string range [lindex $b 1] 4 8]
};# do_display

set barcode {55123457}

do_display

catch {console show}