[barcode] Telepen ASCII Symbology

Markus Kuhn Markus.Kuhn@cl.cam.ac.uk
Fri, 22 Nov 2002 15:16:00 +0000


Alessandro Rubini wrote on 2002-11-21 22:50 UTC:
> new url: http://www.telepen-barcode.co.uk/barcode_symbol.asp
> 
> However, this isn't clear at all to me. They're making quite a bit
> of self-glorification without giving useable information.

Admittedly, the page gives not a really good description, but apart from
the fact that the mod 127 checksum also needs to be inverted, all the
necessary information is indeed there. In a nutshell: To process the bit
sequence, you need a state machine with two states. In the start state,
you accept bit sequences 00, 010, 01, 1 (these transition are
distinguishable by the 4 possible narrow/wide black/white stripe
combinations), and in the second state you accept only bit sequences 10,
1 (anything starting with 0 could have been handled by staying in the
start state). You always make the state transition that accepts most
bits. The sequences 01 and 10 cause a transition between the two states,
all others do not cause the state to change. It's a rather clever
scheme, imho.

> Obviously, you're welcome to contribute the encoding by yourself.  As
> an alternative, I'd like to see a useable description of the format so
> I can consider implementing it.  

I have written and attached a Perl script that, when I tested it,
successfully encoded both the example on the above web page as well as
numerous of our the University of Cambridge library cards correctly. I
hope that counts as a sufficiently useable description of the Telepen
ASCII barcode.

Best regards,

Markus

-- 
Markus G. Kuhn, Computer Laboratory, University of Cambridge, UK
Email: mkuhn at acm.org,  WWW: <http://www.cl.cam.ac.uk/~mgk25/>




#!/usr/bin/perl
# Markus.Kuhn@cl.cam.ac.uk, 2002-11-22

# Encode 7-bit ASCII string into Telepen barcode
# http://www.telepen-barcode.co.uk/barcode_symbol.asp
# Output: string in which '.' and 'B' represent equally wide white and
#         black vertical strokes.
sub telepen
{
    my ($text) = @_;
    my $bits;
    my $barcode;
    my $checksum = 0;

    # Append checksum byte to $text
    for ($i = 0; $i < length($text); $i++) {
	$checksum += ord(substr($text, $i, 1)) & 0x7f;
    }
    $text .= chr(~($checksum % 127) & 0x7f);
    # Convert $text to LSB-first bit sequence with even parity
    while (length($text) > 0) {
	my $char = ord($text);
	my $ones = 0;
	$text = substr($text, 1);
	$checksum += $char;
	for ($i = 0; $i < 7; $i++) {
	    $ones +=  ($char >> $i) & 1;
	    $bits .= (($char >> $i) & 1) ? '1' : '0';
	}
	$bits .= ($ones & 1) ? '1' : '0';
    };
    # Add start and stop codes
    $bits = "11111010${bits}01011111";
    # Now apply Telepen encoding state machine
    my $state = 0;
    while (length($bits) > 0) {
	if ($bits =~ /^010/ && $state == 0) {
	    $barcode .= 'BBB...';
	    $bits = $';
	} elsif ($bits =~ /^00/ && $state == 0) {
	    $barcode .= 'BBB.';
	    $bits = $';
	} elsif ($bits =~ /^01/ && $state == 0) {
	    $barcode .= 'B...';
	    $bits = $';
	    $state = 1;
	} elsif ($bits =~ /^10/ && $state == 1) {
	    $barcode .= 'B...';
	    $bits = $';
	    $state = 0;
	} elsif ($bits =~ /^1/) {
	    $barcode .= 'B.';
	    $bits = $';
	} else {
	    die("Oops, something impossible happend!\n$bits\n");
	}
    }
    return $barcode;
}

# Convert ./B output format of telepen() into PBM graphics file
sub barcode2pbm
{
    my ($barcode) = @_;
    my $hborder = 10;
    my $vborder = 10;
    my $width = length($barcode) + 2*$hborder;
    my $rows = 30;
    my $height = $rows + 2*$vborder;

    $barcode =~ s/B/1 /g;
    $barcode =~ s/\./0 /g;
    $barcode = ('0 ' x $hborder) . $barcode . ('0 ' x $hborder);
    $barcode = "$barcode\n" x $rows;
    $barcode = (((("0 " x $width) . "\n") x $vborder) . $barcode .
		((("0 " x $width) . "\n") x $vborder));
    return "P1\n$width $height\n$barcode";
}


if ($#ARGV < 0) {
    print STDERR "Print Telepen barcode as PBM file.\n\n";
    print STDERR "Usage: telepen.pl <ascii-string>\n\n";
    exit 1;
};

print barcode2pbm(telepen($ARGV[0]));