reportlab: barcode moved to reportlab/graphics
authorrgbecker
Thu, 04 May 2006 10:48:36 +0000
changeset 2587 8984967879af
parent 2586 1cfd7c468127
child 2588 ea348c8bdef1
reportlab: barcode moved to reportlab/graphics
reportlab/graphics/barcode/README
reportlab/graphics/barcode/TODO
reportlab/graphics/barcode/VERSION
reportlab/graphics/barcode/__init__.py
reportlab/graphics/barcode/code128.py
reportlab/graphics/barcode/code39.py
reportlab/graphics/barcode/code93.py
reportlab/graphics/barcode/common.py
reportlab/graphics/barcode/eanbc.py
reportlab/graphics/barcode/fourstate.py
reportlab/graphics/barcode/test.py
reportlab/graphics/barcode/usps.py
reportlab/graphics/barcode/widgets.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/README	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,59 @@
+Symbologies Currently Supported
+===============================
+
+The following have, at a minimum, been verified to scan with a WASP
+CCD barcode scanner (found one bug in my code, two in the scanner!).
+Some have had more extensive testing:
+
+	Interleaved 2 of 5
+	MSI
+	Codabar
+	Code 39 (Standard Character Set)
+	Code 39 (Extended Character Set)
+	Code 93 (Standard Character Set)
+	Code 93 (Extended Character Set)
+	Code 128 (Automatic use of A, B, C, with some optimizations -- 
+		more coming)
+
+The following have been tested by sending a fair number of mailpieces
+with them:
+
+	USPS FIM
+	USPS POSTNET
+
+The following have not been tested, as none of the scanners I have
+access to support them:
+
+	Code 11
+
+
+Future Plans, Consulting
+========================
+
+Soon:
+
+I plan to implement the following linear codes soon:
+
+	UPC/EAN(/JAN)
+
+The following are in progress, but I lack a way to verify them
+(scanners I have access to don't read them), and I don't have complete
+specs for the UK style.
+
+	Royal Mail 4-State (UK/NL/etc style, and Australian style)
+
+Down the road, I'd like to do some 2D symbologies. Likely first candidate
+is PDF417. MaxiCode, Aztec Code, and some of the stacked symbologies are
+also good candidates.
+
+I am available to do implementation of additional symbologies for hire. 
+Because I enjoy hacking barcodes, my rates for work in this particular
+area are very low and are mainly to help offset costs associated with
+obtaining related documents and/or to buy or gain access to scanning
+equipment for symbologies if I don't already have a scanner that
+supports them.  Loans of equipment are also accepted. 
+
+For more information, contact:
+
+Ty Sarna
+tsarna@sarna.org
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/TODO	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,24 @@
+See also README for some plans and info on consulting.
+
+- Overall framework docs
+
+- Finish Aussie Rules 4-State, for which I have complete docs now (yay
+  USPS and aupost.com.au for putting specs online. Too bad UKPost doesn't.)
+
+- Investigate USPS PLANET stuff
+
+- Higher-level objects that handle barcoded address blocks with correct
+  spacings and such (US, AU, UK/etc?)
+
+- Even higher-level objects that represent mailpieces and place the
+  above-style address block objects, FIM codes, "place stamp here" blocks,
+  etc, correctly?
+
+- Framework for laying out labels on various styles of n-up label
+  sheets, like Avery labels, etc?
+
+- Decide if Plessey is worth doing. MSI-like (MSI is actually derived from
+  it), but specs were never formalized. Probably only useful for legacy
+  applications. If you need it, mail me.
+
+- Get someone to test Code 11, or find a scanner that handles it
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/VERSION	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,1 @@
+0.9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/__init__.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,126 @@
+#
+# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+__version__ = '0.9'
+
+def getCodes():
+    """Returns a dict mapping code names to widgets"""
+
+    from widgets import (BarcodeI2of5,
+                BarcodeCode128,
+                BarcodeStandard93,
+                BarcodeExtended93,
+                BarcodeStandard39,
+                BarcodeExtended39,
+                BarcodeMSI,
+                BarcodeCodabar,
+                BarcodeCode11,
+                BarcodeFIM,
+                BarcodePOSTNET)
+
+    #newer codes will typically get their own module
+    from eanbc import Ean13BarcodeWidget, Ean8BarcodeWidget
+
+
+    #the module exports a dictionary of names to widgets, to make it easy for
+    #apps and doc tools to display information about them.
+    codes = {}
+    for widget in (
+                BarcodeI2of5,
+                BarcodeCode128,
+                BarcodeStandard93,
+                BarcodeExtended93,
+                BarcodeStandard39,
+                BarcodeExtended39,
+                BarcodeMSI,
+                BarcodeCodabar,
+                BarcodeCode11,
+                BarcodeFIM,
+                BarcodePOSTNET,
+                Ean13BarcodeWidget,
+                Ean8BarcodeWidget,
+                ):
+        codeName = widget.codeName
+        codes[codeName] = widget
+
+    return codes
+
+def getCodeNames():
+    """Returns sorted list of supported bar code names"""
+    return sorted(getCodes().keys())
+
+def createBarcodeDrawing(codeName, **options):
+    """This creates and returns a drawing with a barcode.
+    """    
+    from reportlab.graphics.shapes import Drawing, Group
+
+    codes = getCodes()
+    bcc = codes[codeName]
+    width = options.pop('width',None)
+    height = options.pop('height',None)
+    isoScale = options.pop('isoScale',0)
+    kw = {}
+    for k,v in options.iteritems():
+        if k.startswith('_') or k in bcc._attrMap: kw[k] = v
+    bc = bcc(**kw)
+
+    #size it after setting the data    
+    x1, y1, x2, y2 = bc.getBounds()
+    w = float(x2 - x1)
+    h = float(y2 - y1)
+    sx = width not in ('auto',None)
+    sy = height not in ('auto',None)
+    if sx or sy:
+        sx = sx and width/w or 1.0
+        sy = sy and height/h or 1.0
+        if isoScale:
+            if sx<1.0 and sy<1.0:
+                sx = sy = max(sx,sy)
+            else:
+                sx = sy = min(sx,sy)
+
+        w *= sx
+        h *= sy
+    else:
+        sx = sy = 1
+
+    #bc.x = -sx*x1
+    #bc.y = -sy*y1
+    d = Drawing(width=w,height=h,transform=[sx,0,0,sy,-sx*x1,-sy*y1])
+    d.add(bc, "_bc")
+    return d
+
+def createBarcodeImageInMemory(codeName, **options):
+    """This creates and returns barcode as an image in memory.
+    """    
+    d = createBarcodeDrawing(codeName, **options)
+    return d.asString(format)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/code128.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,322 @@
+#
+# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.lib.units import inch
+from common import MultiWidthBarcode
+from string import digits
+
+_patterns = {
+    0   :   'BaBbBb',    1   :   'BbBaBb',    2   :   'BbBbBa',
+    3   :   'AbAbBc',    4   :   'AbAcBb',    5   :   'AcAbBb',
+    6   :   'AbBbAc',    7   :   'AbBcAb',    8   :   'AcBbAb',
+    9   :   'BbAbAc',    10  :   'BbAcAb',    11  :   'BcAbAb',
+    12  :   'AaBbCb',    13  :   'AbBaCb',    14  :   'AbBbCa',
+    15  :   'AaCbBb',    16  :   'AbCaBb',    17  :   'AbCbBa',
+    18  :   'BbCbAa',    19  :   'BbAaCb',    20  :   'BbAbCa',
+    21  :   'BaCbAb',    22  :   'BbCaAb',    23  :   'CaBaCa',
+    24  :   'CaAbBb',    25  :   'CbAaBb',    26  :   'CbAbBa',
+    27  :   'CaBbAb',    28  :   'CbBaAb',    29  :   'CbBbAa',
+    30  :   'BaBaBc',    31  :   'BaBcBa',    32  :   'BcBaBa',
+    33  :   'AaAcBc',    34  :   'AcAaBc',    35  :   'AcAcBa',
+    36  :   'AaBcAc',    37  :   'AcBaAc',    38  :   'AcBcAa',
+    39  :   'BaAcAc',    40  :   'BcAaAc',    41  :   'BcAcAa',
+    42  :   'AaBaCc',    43  :   'AaBcCa',    44  :   'AcBaCa',
+    45  :   'AaCaBc',    46  :   'AaCcBa',    47  :   'AcCaBa',
+    48  :   'CaCaBa',    49  :   'BaAcCa',    50  :   'BcAaCa',
+    51  :   'BaCaAc',    52  :   'BaCcAa',    53  :   'BaCaCa',
+    54  :   'CaAaBc',    55  :   'CaAcBa',    56  :   'CcAaBa',
+    57  :   'CaBaAc',    58  :   'CaBcAa',    59  :   'CcBaAa',
+    60  :   'CaDaAa',    61  :   'BbAdAa',    62  :   'DcAaAa',
+    63  :   'AaAbBd',    64  :   'AaAdBb',    65  :   'AbAaBd',
+    66  :   'AbAdBa',    67  :   'AdAaBb',    68  :   'AdAbBa',
+    69  :   'AaBbAd',    70  :   'AaBdAb',    71  :   'AbBaAd',
+    72  :   'AbBdAa',    73  :   'AdBaAb',    74  :   'AdBbAa',
+    75  :   'BdAbAa',    76  :   'BbAaAd',    77  :   'DaCaAa',
+    78  :   'BdAaAb',    79  :   'AcDaAa',    80  :   'AaAbDb',
+    81  :   'AbAaDb',    82  :   'AbAbDa',    83  :   'AaDbAb',
+    84  :   'AbDaAb',    85  :   'AbDbAa',    86  :   'DaAbAb',
+    87  :   'DbAaAb',    88  :   'DbAbAa',    89  :   'BaBaDa',
+    90  :   'BaDaBa',    91  :   'DaBaBa',    92  :   'AaAaDc',
+    93  :   'AaAcDa',    94  :   'AcAaDa',    95  :   'AaDaAc',
+    96  :   'AaDcAa',    97  :   'DaAaAc',    98  :   'DaAcAa',
+    99  :   'AaCaDa',    100 :   'AaDaCa',    101 :   'CaAaDa',
+    102 :   'DaAaCa',    103 :   'BaAdAb',    104 :   'BaAbAd',
+    105 :   'BaAbCb',    106 :   'BcCaAaB'
+}
+
+starta, startb, startc, stop = 103, 104, 105, 106
+
+seta = {
+        ' ' :   0,        '!' :   1,        '"' :   2,        '#' :   3,
+        '$' :   4,        '%' :   5,        '&' :   6,       '\'' :   7,
+        '(' :   8,        ')' :   9,        '*' :  10,        '+' :  11,
+        ',' :  12,        '-' :  13,        '.' :  14,        '/' :  15,
+        '0' :  16,        '1' :  17,        '2' :  18,        '3' :  19,
+        '4' :  20,        '5' :  21,        '6' :  22,        '7' :  23,
+        '8' :  24,        '9' :  25,        ':' :  26,        ';' :  27,
+        '<' :  28,        '=' :  29,        '>' :  30,        '?' :  31,
+        '@' :  32,        'A' :  33,        'B' :  34,        'C' :  35,
+        'D' :  36,        'E' :  37,        'F' :  38,        'G' :  39,
+        'H' :  40,        'I' :  41,        'J' :  42,        'K' :  43,
+        'L' :  44,        'M' :  45,        'N' :  46,        'O' :  47,
+        'P' :  48,        'Q' :  49,        'R' :  50,        'S' :  51,
+        'T' :  52,        'U' :  53,        'V' :  54,        'W' :  55,
+        'X' :  56,        'Y' :  57,        'Z' :  58,        '[' :  59,
+       '\\' :  60,        ']' :  61,        '^' :  62,        '_' :  63,
+     '\x00' :  64,     '\x01' :  65,     '\x02' :  66,     '\x03' :  67,
+     '\x04' :  68,     '\x05' :  69,     '\x06' :  70,     '\x07' :  71,
+     '\x08' :  72,     '\x09' :  73,     '\x0a' :  74,     '\x0b' :  75,
+     '\x0c' :  76,     '\x0d' :  77,     '\x0e' :  78,     '\x0f' :  79,
+     '\x10' :  80,     '\x11' :  81,     '\x12' :  82,     '\x13' :  83,
+     '\x14' :  84,     '\x15' :  85,     '\x16' :  86,     '\x17' :  87,
+     '\x18' :  88,     '\x19' :  89,     '\x1a' :  90,     '\x1b' :  91,
+     '\x1c' :  92,     '\x1d' :  93,     '\x1e' :  94,     '\x1f' :  95,
+     '\xf3' :  96,     '\xf2' :  97,    'SHIFT' :  98,     'TO_C' :  99,
+     'TO_B' : 100,     '\xf4' : 101,     '\xf1' : 102
+}
+
+setb = {
+        ' ' :   0,        '!' :   1,        '"' :   2,        '#' :   3,
+        '$' :   4,        '%' :   5,        '&' :   6,       '\'' :   7,
+        '(' :   8,        ')' :   9,        '*' :  10,        '+' :  11,
+        ',' :  12,        '-' :  13,        '.' :  14,        '/' :  15,
+        '0' :  16,        '1' :  17,        '2' :  18,        '3' :  19,
+        '4' :  20,        '5' :  21,        '6' :  22,        '7' :  23,
+        '8' :  24,        '9' :  25,        ':' :  26,        ';' :  27,
+        '<' :  28,        '=' :  29,        '>' :  30,        '?' :  31,
+        '@' :  32,        'A' :  33,        'B' :  34,        'C' :  35,
+        'D' :  36,        'E' :  37,        'F' :  38,        'G' :  39,
+        'H' :  40,        'I' :  41,        'J' :  42,        'K' :  43,
+        'L' :  44,        'M' :  45,        'N' :  46,        'O' :  47,
+        'P' :  48,        'Q' :  49,        'R' :  50,        'S' :  51,
+        'T' :  52,        'U' :  53,        'V' :  54,        'W' :  55,
+        'X' :  56,        'Y' :  57,        'Z' :  58,        '[' :  59,
+       '\\' :  60,        ']' :  61,        '^' :  62,        '_' :  63,
+        '`' :  64,        'a' :  65,        'b' :  66,        'c' :  67,
+        'd' :  68,        'e' :  69,        'f' :  70,        'g' :  71,
+        'h' :  72,        'i' :  73,        'j' :  74,        'k' :  75,
+        'l' :  76,        'm' :  77,        'n' :  78,        'o' :  79,
+        'p' :  80,        'q' :  81,        'r' :  82,        's' :  83,
+        't' :  84,        'u' :  85,        'v' :  86,        'w' :  87,
+        'x' :  88,        'y' :  89,        'z' :  90,        '{' :  91,
+        '|' :  92,        '}' :  93,        '~' :  94,     '\x7f' :  95,
+     '\xf3' :  96,     '\xf2' :  97,    'SHIFT' :  98,     'TO_C' :  99,
+     '\xf4' : 100,     'TO_A' : 101,     '\xf1' : 102
+}
+
+setc = {
+    '00': 0, '01': 1, '02': 2, '03': 3, '04': 4,
+    '05': 5, '06': 6, '07': 7, '08': 8, '09': 9,
+    '10':10, '11':11, '12':12, '13':13, '14':14,
+    '15':15, '16':16, '17':17, '18':18, '19':19,
+    '20':20, '21':21, '22':22, '23':23, '24':24,
+    '25':25, '26':26, '27':27, '28':28, '29':29,
+    '30':30, '31':31, '32':32, '33':33, '34':34,
+    '35':35, '36':36, '37':37, '38':38, '39':39,
+    '40':40, '41':41, '42':42, '43':43, '44':44,
+    '45':45, '46':46, '47':47, '48':48, '49':49,
+    '50':50, '51':51, '52':52, '53':53, '54':54,
+    '55':55, '56':56, '57':57, '58':58, '59':59,
+    '60':60, '61':61, '62':62, '63':63, '64':64,
+    '65':65, '66':66, '67':67, '68':68, '69':69,
+    '70':70, '71':71, '72':72, '73':73, '74':74,
+    '75':75, '76':76, '77':77, '78':78, '79':79,
+    '80':80, '81':81, '82':82, '83':83, '84':84,
+    '85':85, '86':86, '87':87, '88':88, '89':89,
+    '90':90, '91':91, '92':92, '93':93, '94':94,
+    '95':95, '96':96, '97':97, '98':98, '99':99,
+
+    'TO_B' : 100,    'TO_A' : 101,    '\xf1' : 102
+}
+
+setmap = {
+    'TO_A' : (seta, setb),
+    'TO_B' : (setb, seta),
+    'TO_C' : (setc, None),
+    'START_A' : (starta, seta, setb),
+    'START_B' : (startb, setb, seta),
+    'START_C' : (startc, setc, None),
+}
+tos = setmap.keys()
+
+class Code128(MultiWidthBarcode):
+    """
+    Code 128 is a very compact symbology that can encode the entire
+    128 character ASCII set, plus 4 special control codes,
+    (FNC1-FNC4, expressed in the input string as \xf1 to \xf4).
+    Code 128 can also encode digits at double density (2 per byte)
+    and has a mandatory checksum.  Code 128 is well supported and
+    commonly used -- for example, by UPS for tracking labels.
+    
+    Because of these qualities, Code 128 is probably the best choice
+    for a linear symbology today (assuming you have a choice).
+
+    Options that may be passed to constructor:
+
+        value (int, or numeric string. required.):
+            The value to encode.
+   
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+            Minumum is .0075 inch (7.5 mils).
+            
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        quiet (bool, default 1):
+            Wether to include quiet zones in the symbol.
+            
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or 10 barWidth
+            
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+            
+    Sources of Information on Code 128:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/code_128.html
+    http://www.adams1.com/pub/russadam/128code.html
+    http://www.barcodeman.com/c128.html
+
+    Official Spec, "ANSI/AIM BC4-1999, ISS" is available for US$45 from
+    http://www.aimglobal.org/aimstore/
+    """
+    barWidth = inch * 0.0075
+    lquiet = None
+    rquiet = None
+    quiet = 1
+    barHeight = None
+    def __init__(self, value='', **args):
+
+        if type(value) is type(1):
+            value = str(value)
+            
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
+            if self.rquiet is None:
+                self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        MultiWidthBarcode.__init__(self, value)
+
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in self.value:
+            if ord(c) > 127 and c not in '\xf1\xf2\xf3\xf4':
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def _trailingDigitsToC(self, l):
+        # Optimization: trailing digits -> set C double-digits
+        c = 1
+        savings = -1 # the TO_C costs one character
+        rl = ['STOP']
+        while c < len(l):
+            i = (-c - 1)
+            if l[i] == '\xf1':
+                c = c + 1
+                rl.insert(0, '\xf1')
+                continue
+            elif len(l[i]) == 1 and l[i] in digits \
+             and len(l[i-1]) == 1 and l[i-1] in digits:
+                c += 2
+                savings += 1
+                rl.insert(0, l[i-1] + l[i])
+                continue
+            else:
+                break
+        if savings > 0:
+            return l[:-c] + ['TO_C'] + rl
+        else:
+            return l
+
+    def encode(self):
+        # First, encode using only B
+        s = self.validated
+        l = ['START_B']
+        for c in s:
+            if not setb.has_key(c):
+                l = l + ['TO_A', c, 'TO_B']
+            else:
+                l.append(c)
+        l.append('STOP')
+
+        l = self._trailingDigitsToC(l)
+
+        # Finally, replace START_X,TO_Y with START_Y
+        if l[1] in tos:
+            l[:2] = ['START_' + l[1][-1]]
+
+#        print `l`
+
+        # encode into numbers
+        start, set, shset = setmap[l[0]]
+        e = [start]
+        
+        l = l[1:-1]
+        while l:
+            c = l[0]
+            if c == 'SHIFT':
+                e = e + [set[c], shset[l[1]]]
+                l = l[2:]
+            elif c in tos:
+                e.append(set[c])
+                set, shset = setmap[c]
+                l = l[1:]
+            else:
+                e.append(set[c])
+                l = l[1:]
+
+        c = e[0]
+        for i in range(1, len(e)):
+            c = c + i * e[i]
+        self.encoded = e + [c % 103, stop]
+        return self.encoded
+
+    def decompose(self):
+        self.decomposed = ''.join([_patterns[c] for c in self.encoded])
+        return self.decomposed
+
+    def _humanText(self):
+        return self.value
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/code39.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,248 @@
+#
+# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.lib.units import inch
+from common import Barcode
+import string
+
+_patterns = {
+    '0':    ("bsbSBsBsb", 0),       '1': ("BsbSbsbsB", 1),
+    '2':    ("bsBSbsbsB", 2),       '3': ("BsBSbsbsb", 3),
+    '4':    ("bsbSBsbsB", 4),       '5': ("BsbSBsbsb", 5),
+    '6':    ("bsBSBsbsb", 6),       '7': ("bsbSbsBsB", 7),
+    '8':    ("BsbSbsBsb", 8),       '9': ("bsBSbsBsb", 9),
+    'A':    ("BsbsbSbsB", 10),      'B': ("bsBsbSbsB", 11),
+    'C':    ("BsBsbSbsb", 12),      'D': ("bsbsBSbsB", 13),
+    'E':    ("BsbsBSbsb", 14),      'F': ("bsBsBSbsb", 15),
+    'G':    ("bsbsbSBsB", 16),      'H': ("BsbsbSBsb", 17),
+    'I':    ("bsBsbSBsb", 18),      'J': ("bsbsBSBsb", 19),
+    'K':    ("BsbsbsbSB", 20),      'L': ("bsBsbsbSB", 21),
+    'M':    ("BsBsbsbSb", 22),      'N': ("bsbsBsbSB", 23),
+    'O':    ("BsbsBsbSb", 24),      'P': ("bsBsBsbSb", 25),
+    'Q':    ("bsbsbsBSB", 26),      'R': ("BsbsbsBSb", 27),
+    'S':    ("bsBsbsBSb", 28),      'T': ("bsbsBsBSb", 29),
+    'U':    ("BSbsbsbsB", 30),      'V': ("bSBsbsbsB", 31),
+    'W':    ("BSBsbsbsb", 32),      'X': ("bSbsBsbsB", 33),
+    'Y':    ("BSbsBsbsb", 34),      'Z': ("bSBsBsbsb", 35),
+    '-':    ("bSbsbsBsB", 36),      '.': ("BSbsbsBsb", 37),
+    ' ':    ("bSBsbsBsb", 38),      '*': ("bSbsBsBsb", 39),
+    '$':    ("bSbSbSbsb", 40),      '/': ("bSbSbsbSb", 41),
+    '+':    ("bSbsbSbSb", 42),      '%': ("bsbSbSbSb", 43)
+}
+
+_valchars = [
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
+    'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+    'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+    'X', 'Y', 'Z', '-', '.', ' ', '*', '$', '/', '+', '%'
+]
+
+_extended = {
+    '\0':   "%U",    '\01':  "$A",    '\02':  "$B",    '\03':  "$C",
+    '\04':  "$D",    '\05':  "$E",    '\06':  "$F",    '\07':  "$G",
+    '\010': "$H",    '\011': "$I",    '\012': "$J",    '\013': "$K",
+    '\014': "$L",    '\015': "$M",    '\016': "$N",    '\017': "$O",
+    '\020': "$P",    '\021': "$Q",    '\022': "$R",    '\023': "$S",
+    '\024': "$T",    '\025': "$U",    '\026': "$V",    '\027': "$W",
+    '\030': "$X",    '\031': "$Y",    '\032': "$Z",    '\033': "%A",
+    '\034': "%B",    '\035': "%C",    '\036': "%D",    '\037': "%E",
+    '!':    "/A",    '"':    "/B",    '#':    "/C",    '$':    "/D",
+    '%':    "/E",    '&':    "/F",    '\'':   "/G",    '(':    "/H",
+    ')':    "/I",    '*':    "/J",    '+':    "/K",    ',':    "/L",
+    '/':    "/O",    ':':    "/Z",    ';':    "%F",    '<':    "%G",
+    '=':    "%H",    '>':    "%I",    '?':    "%J",    '@':    "%V",
+    '[':    "%K",    '\\':   "%L",    ']':    "%M",    '^':    "%N",
+    '_':    "%O",    '`':    "%W",    'a':    "+A",    'b':    "+B",
+    'c':    "+C",    'd':    "+D",    'e':    "+E",    'f':    "+F",
+    'g':    "+G",    'h':    "+H",    'i':    "+I",    'j':    "+J",
+    'k':    "+K",    'l':    "+L",    'm':    "+M",    'n':    "+N",
+    'o':    "+O",    'p':    "+P",    'q':    "+Q",    'r':    "+R",
+    's':    "+S",    't':    "+T",    'u':    "+U",    'v':    "+V",
+    'w':    "+W",    'x':    "+X",    'y':    "+Y",    'z':    "+Z",
+    '{':    "%P",    '|':    "%Q",    '}':    "%R",    '~':    "%S",
+    '\177': "%T"
+}
+
+
+_stdchrs = string.digits + string.uppercase + "-. *$/+%"
+_extchrs = _stdchrs + string.lowercase + \
+    "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" + \
+    "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" + \
+    "!'#&\"(),:;<=>?@[\\]^_`{|}~\177"
+
+def _encode39(value, cksum, stop):
+    v = sum([_patterns[c][1] for c in value]) % 43
+    if cksum:
+        value += _valchars[v]
+    if stop: value = '*'+value+'*'
+    return value
+
+class _Code39Base(Barcode):
+    barWidth = inch * 0.0075
+    lquiet = None
+    rquiet = None
+    quiet = 1
+    gap = None
+    barHeight = None
+    ratio = 2.2
+    checksum = 1
+    bearers = 0.0
+    stop = 1
+    def __init__(self, value = "", **args):
+        for k, v in args.iteritems():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        Barcode.__init__(self, value)
+
+    def decompose(self):
+        dval = ""
+        for c in self.encoded:
+            dval = dval + _patterns[c][0] + 'i'
+        self.decomposed = dval[:-1]
+        return self.decomposed
+
+    def _humanText(self):
+        return self.stop and self.encoded[1:-1] or self.encoded
+
+class Standard39(_Code39Base):
+    """
+    Options that may be passed to constructor:
+
+        value (int, or numeric string. required.):
+            The value to encode.
+
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+            Minumum is .0075 inch (7.5 mils).
+
+        ratio (float, default 2.2):
+            The ratio of wide elements to narrow elements.
+            Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
+            barWidth is greater than 20 mils (.02 inch))
+
+        gap (float or None, default None):
+            width of intercharacter gap. None means "use barWidth".
+
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        checksum (bool, default 1):
+            Wether to compute and include the check digit
+
+        bearers (float, in units of barWidth. default 0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 0 (no bearers).
+
+        quiet (bool, default 1):
+            Wether to include quiet zones in the symbol.
+
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or .15 times the symbol's
+            length.
+
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+        stop (bool, default 1):
+            Whether to include start/stop symbols.
+
+    Sources of Information on Code 39:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/code_39.html
+    http://www.adams1.com/pub/russadam/39code.html
+    http://www.barcodeman.com/c39_1.html
+
+    Official Spec, "ANSI/AIM BC1-1995, USS" is available for US$45 from
+    http://www.aimglobal.org/aimstore/
+    """
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in self.value:
+            if c in string.lowercase:
+                c = string.upper(c)
+            if c not in _stdchrs:
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        self.encoded = _encode39(self.validated, self.checksum, self.stop)
+        return self.encoded
+
+class Extended39(_Code39Base):
+    """
+    Extended Code 39 is a convention for encoding additional characters
+    not present in stanmdard Code 39 by using pairs of characters to
+    represent the characters missing in Standard Code 39.
+
+    See Standard39 for arguments.
+
+    Sources of Information on Extended Code 39:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/xcode_39.html
+    http://www.barcodeman.com/c39_ext.html
+    """
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in self.value:
+            if c not in _extchrs:
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        self.encoded = ""
+        for c in self.validated:
+            if _extended.has_key(c):
+                self.encoded = self.encoded + _extended[c]
+            elif c in _stdchrs:
+                self.encoded = self.encoded + c
+            else:
+                raise ValueError
+        self.encoded = _encode39(self.encoded, self.checksum,self.stop)
+        return self.encoded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/code93.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,236 @@
+#
+# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.lib.units import inch
+from common import MultiWidthBarcode
+import string
+
+_patterns = {
+  '0' : ('AcAaAb', 0),  '1' : ('AaAbAc', 1),  '2' : ('AaAcAb', 2),
+  '3' : ('AaAdAa', 3),  '4' : ('AbAaAc', 4),  '5' : ('AbAbAb', 5),
+  '6' : ('AbAcAa', 6),  '7' : ('AaAaAd', 7),  '8' : ('AcAbAa', 8),
+  '9' : ('AdAaAa', 9),  'A' : ('BaAaAc', 10), 'B' : ('BaAbAb', 11),
+  'C' : ('BaAcAa', 12), 'D' : ('BbAaAb', 13), 'E' : ('BbAbAa', 14),
+  'F' : ('BcAaAa', 15), 'G' : ('AaBaAc', 16), 'H' : ('AaBbAb', 17),
+  'I' : ('AaBcAa', 18), 'J' : ('AbBaAb', 19), 'K' : ('AcBaAa', 20),
+  'L' : ('AaAaBc', 21), 'M' : ('AaAbBb', 22), 'N' : ('AaAcBa', 23),
+  'O' : ('AbAaBb', 24), 'P' : ('AcAaBa', 25), 'Q' : ('BaBaAb', 26),
+  'R' : ('BaBbAa', 27), 'S' : ('BaAaBb', 28), 'T' : ('BaAbBa', 29),
+  'U' : ('BbAaBa', 30), 'V' : ('BbBaAa', 31), 'W' : ('AaBaBb', 32),
+  'X' : ('AaBbBa', 33), 'Y' : ('AbBaBa', 34), 'Z' : ('AbCaAa', 35),
+  '-' : ('AbAaCa', 36), '.' : ('CaAaAb', 37), ' ' : ('CaAbAa', 38),
+  '$' : ('CbAaAa', 39), '/' : ('AaBaCa', 40), '+' : ('AaCaBa', 41),
+  '%' : ('BaAaCa', 42), '#' : ('AbAbBa', 43), '!' : ('CaBaAa', 44),
+  '=' : ('CaAaBa', 45), '&' : ('AbBbAa', 46),
+  'start' : ('AaAaDa', -1),  'stop' : ('AaAaDaA', -2)
+}
+
+_charsbyval = {}
+for k, v in _patterns.items():
+    _charsbyval[v[1]] = k
+
+_extended = {
+    '\x00' : '!U',    '\x01' : '#A',    '\x02' : '#B',    '\x03' : '#C',
+    '\x04' : '#D',    '\x05' : '#E',    '\x06' : '#F',    '\x07' : '#G',
+    '\x08' : '#H',    '\x09' : '#I',    '\x0a' : '#J',    '\x0b' : '#K',
+    '\x0c' : '#L',    '\x0d' : '#M',    '\x0e' : '#N',    '\x0f' : '#O',
+    '\x10' : '#P',    '\x11' : '#Q',    '\x12' : '#R',    '\x13' : '#S',
+    '\x14' : '#T',    '\x15' : '#U',    '\x16' : '#V',    '\x17' : '#W',
+    '\x18' : '#X',    '\x19' : '#Y',    '\x1a' : '#Z',    '\x1b' : '!A',
+    '\x1c' : '!B',    '\x1d' : '!C',    '\x1e' : '!D',    '\x1f' : '!E',
+    '!'    : '=A',    '"'    : '=B',    '#'    : '=C',    '$'    : '=D',
+    '%'    : '=E',    '&'    : '=F',    '\''   : '=G',    '('    : '=H',
+    ')'    : '=I',    '*'    : '=J',    '+'    : '=K',    ','    : '=L',
+    '/'    : '=O',    ':'    : '=Z',    ';'    : '!F',    '<'    : '!G',
+    '='    : '!H',    '>'    : '!I',    '?'    : '!J',    '@'    : '!V',
+    '['    : '!K',    '\\'   : '!L',    ']'    : '!M',    '^'    : '!N',
+    '_'    : '!O',    '`'    : '!W',    'a'    : '&A',    'b'    : '&B',
+    'c'    : '&C',    'd'    : '&D',    'e'    : '&E',    'f'    : '&F',
+    'g'    : '&G',    'h'    : '&H',    'i'    : '&I',    'j'    : '&J',
+    'k'    : '&K',    'l'    : '&L',    'm'    : '&M',    'n'    : '&N',
+    'o'    : '&O',    'p'    : '&P',    'q'    : '&Q',    'r'    : '&R',
+    's'    : '&S',    't'    : '&T',    'u'    : '&U',    'v'    : '&V',
+    'w'    : '&W',    'x'    : '&X',    'y'    : '&Y',    'z'    : '&Z',
+    '{'    : '!P',    '|'    : '!Q',    '}'    : '!R',    '~'    : '!S',
+    '\x7f' : '!T'
+}
+
+def _encode93(str):
+    s = map(None, str)
+    s.reverse()
+
+    # compute 'C' checksum
+    i = 0; v = 1; c = 0
+    while i < len(s):
+        c = c + v * _patterns[s[i]][1]
+        i = i + 1; v = v + 1
+        if v > 20:
+            v = 1
+    s.insert(0, _charsbyval[c % 47])
+
+    # compute 'K' checksum
+    i = 0; v = 1; c = 0
+    while i < len(s):
+        c = c + v * _patterns[s[i]][1]
+        i = i + 1; v = v + 1
+        if v > 15:
+            v = 1
+    s.insert(0, _charsbyval[c % 47])
+
+    s.reverse()
+
+    return string.join(s, '')
+
+class _Code93Base(MultiWidthBarcode):
+    barWidth = inch * 0.0075
+    lquiet = None
+    rquiet = None
+    quiet = 1
+    barHeight = None
+    stop = 1
+    def __init__(self, value='', **args):
+
+        if type(value) is type(1):
+            value = str(value)
+            
+        for (k, v) in args.iteritems():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        MultiWidthBarcode.__init__(self, value)
+
+    def decompose(self):
+        dval = self.stop and [_patterns['start'][0]] or []
+        dval += [_patterns[c][0] for c in self.encoded]
+        if self.stop: dval.append(_patterns['stop'][0])
+        self.decomposed = ''.join(dval)
+        return self.decomposed
+
+class Standard93(_Code93Base):
+    """
+    Code 93 is a Uppercase alphanumeric symbology with some punctuation.
+    See Extended Code 93 for a variant that can represent the entire
+    128 characrter ASCII set.
+    
+    Options that may be passed to constructor:
+
+        value (int, or numeric string. required.):
+            The value to encode.
+   
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+            Minumum is .0075 inch (7.5 mils).
+            
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        quiet (bool, default 1):
+            Wether to include quiet zones in the symbol.
+            
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or 10 barWidth
+            
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+        stop (bool, default 1):
+            Whether to include start/stop symbols.
+
+    Sources of Information on Code 93:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/code_93.html
+
+    Official Spec, "NSI/AIM BC5-1995, USS" is available for US$45 from
+    http://www.aimglobal.org/aimstore/
+    """
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in self.value:
+            if c in string.lowercase:
+                c = string.upper(c)
+            if not _patterns.has_key(c):
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        self.encoded = _encode93(self.validated)
+        return self.encoded
+
+
+class Extended93(_Code93Base):
+    """
+    Extended Code 93 is a convention for encoding the entire 128 character
+    set using pairs of characters to represent the characters missing in
+    Standard Code 93. It is very much like Extended Code 39 in that way.
+    
+    See Standard93 for arguments.
+    """    
+
+    def validate(self):
+        vval = []
+        self.valid = 1
+        a = vval.append
+        for c in self.value:
+            if not _patterns.has_key(c) and not _extended.has_key(c):
+                self.valid = 0
+                continue
+            a(c)
+        self.validated = ''.join(vval)
+        return self.validated
+
+    def encode(self):
+        self.encoded = ""
+        for c in self.validated:
+            if _patterns.has_key(c):
+                self.encoded = self.encoded + c
+            elif _extended.has_key(c):
+                self.encoded = self.encoded + _extended[c]
+            else:
+                raise ValueError
+        self.encoded = _encode93(self.encoded)
+        return self.encoded
+
+    def _humanText(self):
+        return self.validated+self.encoded[-2:]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/common.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,748 @@
+#
+# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.platypus.flowables import Flowable
+from reportlab.lib.units import inch
+import string
+
+class Barcode(Flowable):
+    """Abstract Base for barcodes. Includes implementations of
+    some methods suitable for the more primitive barcode types"""
+
+    fontName = 'Courier'
+    fontSize = 12
+    humanReadable = 0
+
+    def _humanText(self):
+        return self.encoded
+
+    def __init__(self, value='',**args):
+        self.value = value
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+
+        if not hasattr(self, 'gap'):
+            self.gap = None
+
+        self.validate()
+        self.encode()
+        self.decompose()
+        self.computeSize()
+
+    def validate(self):
+        self.valid = 1
+        self.validated = self.value
+
+    def encode(self):
+        self.encoded = self.validated
+
+    def decompose(self):
+        self.decomposed = self.encoded
+
+    def computeSize(self, *args):
+        barWidth = self.barWidth
+        wx = barWidth * self.ratio
+
+        if self.gap == None:
+            self.gap = barWidth
+
+        w = 0.0
+
+        for c in self.decomposed:
+            if c in 'sb':
+                w = w + barWidth
+            elif c in 'SB':
+                w = w + wx
+            else: # 'i'
+                w = w + self.gap
+
+        if self.barHeight is None:
+            self.barHeight = w * 0.15
+            self.barHeight = max(0.25 * inch, self.barHeight)
+            if self.bearers:
+                self.barHeight = self.barHeight + self.bearers * 2.0 * barWidth
+
+        if self.quiet:
+            w += self.lquiet + self.rquiet
+
+        self.height = self.barHeight
+        self.width = w
+
+    def draw(self):
+        barWidth = self.barWidth
+        wx = barWidth * self.ratio
+
+        left = self.quiet and self.lquiet or 0
+        b = self.bearers * barWidth
+        bb = b * 0.5
+        tb = self.barHeight - (b * 1.5)
+
+        for c in self.decomposed:
+            if c == 'i':
+                left = left + self.gap
+            elif c == 's':
+                left = left + barWidth
+            elif c == 'S':
+                left = left + wx
+            elif c == 'b':
+                self.rect(left, bb, barWidth, tb)
+                left = left + barWidth
+            elif c == 'B':
+                self.rect(left, bb, wx, tb)
+                left = left + wx
+
+        if self.bearers:
+            self.rect(self.lquiet, 0, \
+                self.width - (self.lquiet + self.rquiet), b)
+            self.rect(self.lquiet, self.barHeight - b, \
+                self.width - (self.lquiet + self.rquiet), b)
+
+        self.drawHumanReadable()
+
+    def drawHumanReadable(self):
+        if self.humanReadable:
+            #we have text
+            from reportlab.pdfbase.pdfmetrics import getAscent, stringWidth
+            s = str(self._humanText())
+            fontSize = self.fontSize
+            fontName = self.fontName
+            w = stringWidth(s,fontName,fontSize)
+            width = self.width
+            if self.quiet:
+                width -= self.lquiet+self.rquiet
+                x = self.lquiet
+            else:
+                x = 0
+            if w>width: fontSize *= width/float(w)
+            y = 1.07*getAscent(fontName)*fontSize/1000.
+            self.annotate(x+width/2.,-y,s,fontName,fontSize)
+
+    def rect(self, x, y, w, h):
+        self.canv.rect(x, y, w, h, stroke=0, fill=1)
+
+    def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
+        canv = self.canv
+        canv.saveState()
+        canv.setFont(self.fontName,fontSize)
+        if anchor=='middle': func = 'drawCentredString'
+        elif anchor=='end': func = 'drawRightString'
+        else: func = 'drawString'
+        getattr(canv,func)(text,x,y)
+        canv.restoreState()
+
+class MultiWidthBarcode(Barcode):
+    """Base for variable-bar-width codes like Code93 and Code128"""
+
+    def computeSize(self, *args):
+        barWidth = self.barWidth
+        oa, oA = ord('a') - 1, ord('A') - 1
+
+        w = 0.0
+
+        for c in self.decomposed:
+            oc = ord(c)
+            if c in string.lowercase:
+                w = w + barWidth * (oc - oa)
+            elif c in string.uppercase:
+                w = w + barWidth * (oc - oA)
+
+        if self.barHeight is None:
+            self.barHeight = w * 0.15
+            self.barHeight = max(0.25 * inch, self.barHeight)
+
+        if self.quiet:
+            w += self.lquiet + self.rquiet
+
+        self.height = self.barHeight
+        self.width = w
+
+    def draw(self):
+        oa, oA = ord('a') - 1, ord('A') - 1
+        barWidth = self.barWidth
+        left = self.quiet and self.lquiet or 0
+
+        for c in self.decomposed:
+            oc = ord(c)
+            if c in string.lowercase:
+                left = left + (oc - oa) * barWidth
+            elif c in string.uppercase:
+                w = (oc - oA) * barWidth
+                self.rect(left, 0, w, self.barHeight)
+                left += w
+        self.drawHumanReadable()
+
+class I2of5(Barcode):
+    """
+    Interleaved 2 of 5 is a numeric-only barcode.  It encodes an even
+    number of digits; if an odd number is given, a 0 is prepended.
+
+    Options that may be passed to constructor:
+
+        value (int, or numeric string. required.):
+            The value to encode.
+
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+            Minumum is .0075 inch (7.5 mils).
+
+        ratio (float, default 2.2):
+            The ratio of wide elements to narrow elements.
+            Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
+            barWidth is greater than 20 mils (.02 inch))
+
+        gap (float or None, default None):
+            width of intercharacter gap. None means "use barWidth".
+
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        checksum (bool, default 1):
+            Whether to compute and include the check digit
+
+        bearers (float, in units of barWidth. default 3.0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 3 x-dimensions.
+            Set to zero for no bearer bars. (Bearer bars help detect
+            misscans, so it is suggested to leave them on).
+
+        quiet (bool, default 1):
+            Whether to include quiet zones in the symbol.
+
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or .15 times the symbol's
+            length.
+
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+        stop (bool, default 1):
+            Whether to include start/stop symbols.
+
+    Sources of Information on Interleaved 2 of 5:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html
+    http://www.adams1.com/pub/russadam/i25code.html
+
+    Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from
+    http://www.aimglobal.org/aimstore/
+    """
+
+    patterns = {
+        'start' : 'bsbs',
+        'stop' : 'Bsb',
+
+        'B0' : 'bbBBb',     'S0' : 'ssSSs',
+        'B1' : 'BbbbB',     'S1' : 'SsssS',
+        'B2' : 'bBbbB',     'S2' : 'sSssS',
+        'B3' : 'BBbbb',     'S3' : 'SSsss',
+        'B4' : 'bbBbB',     'S4' : 'ssSsS',
+        'B5' : 'BbBbb',     'S5' : 'SsSss',
+        'B6' : 'bBBbb',     'S6' : 'sSSss',
+        'B7' : 'bbbBB',     'S7' : 'sssSS',
+        'B8' : 'BbbBb',     'S8' : 'SssSs',
+        'B9' : 'bBbBb',     'S9' : 'sSsSs'
+    }
+
+    barHeight = None
+    barWidth = inch * 0.0075
+    ratio = 2.2
+    checksum = 1
+    bearers = 3.0
+    quiet = 1
+    lquiet = None
+    rquiet = None
+    stop = 1
+
+    def __init__(self, value='', **args):
+
+        if type(value) == type(1):
+            value = str(value)
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in string.strip(self.value):
+            if c not in string.digits:
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        s = self.validated
+
+        # make sure result will be a multiple of 2 digits long,
+        # checksum included
+        if ((len(self.validated) % 2 == 0) and self.checksum) \
+        or ((len(self.validated) % 2 == 1) and not self.checksum):
+            s = '0' + s
+
+        if self.checksum:
+            c = 0
+            cm = 3
+
+            for d in s:
+                c = c + cm * int(d)
+                if cm == 3:
+                    cm = 1
+                else:
+                    cm = 3
+
+            d = 10 - (int(d) % 10)
+            s = s + `d`
+
+        self.encoded = s
+
+    def decompose(self):
+        dval = self.stop and [self.patterns['start']] or []
+        a = dval.append
+
+        for i in xrange(0, len(self.encoded), 2):
+            b = self.patterns['B' + self.encoded[i]]
+            s = self.patterns['S' + self.encoded[i+1]]
+
+            for i in range(0, len(b)):
+                a(b[i] + s[i])
+
+        if self.stop: a(self.patterns['stop'])
+        self.decomposed = ''.join(dval)
+        return self.decomposed
+
+class MSI(Barcode):
+    """
+    MSI is a numeric-only barcode.
+
+    Options that may be passed to constructor:
+
+        value (int, or numeric string. required.):
+            The value to encode.
+
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+
+        ratio (float, default 2.2):
+            The ratio of wide elements to narrow elements.
+
+        gap (float or None, default None):
+            width of intercharacter gap. None means "use barWidth".
+
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        checksum (bool, default 1):
+            Wether to compute and include the check digit
+
+        bearers (float, in units of barWidth. default 0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 0 (no bearers).
+
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or 10 barWidths.
+
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+        stop (bool, default 1):
+            Whether to include start/stop symbols.
+
+    Sources of Information on MSI Bar Code:
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html
+    http://www.adams1.com/pub/russadam/plessy.html
+    """
+
+    patterns = {
+        'start' : 'Bs',          'stop' : 'bSb',
+
+        '0' : 'bSbSbSbS',        '1' : 'bSbSbSBs',
+        '2' : 'bSbSBsbS',        '3' : 'bSbSBsBs',
+        '4' : 'bSBsbSbS',        '5' : 'bSBsbSBs',
+        '6' : 'bSBsBsbS',        '7' : 'bSBsBsBs',
+        '8' : 'BsbSbSbS',        '9' : 'BsbSbSBs'
+    }
+
+    stop = 1
+    barHeight = None
+    barWidth = inch * 0.0075
+    ratio = 2.2
+    checksum = 1
+    bearers = 0.0
+    quiet = 1
+    lquiet = None
+    rquiet = None
+
+    def __init__(self, value="", **args):
+
+        if type(value) == type(1):
+            value = str(value)
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        for c in string.strip(self.value):
+            if c not in string.digits:
+                self.valid = 0
+                continue
+            vval = vval + c
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        s = self.validated
+
+        if self.checksum:
+            c = ''
+            for i in range(1, len(s), 2):
+                c = c + s[i]
+            d = str(int(c) * 2)
+            t = 0
+            for c in d:
+                t = t + int(c)
+            for i in range(0, len(s), 2):
+                t = t + int(s[i])
+            c = 10 - (t % 10)
+
+            s = s + str(c)
+
+        self.encoded = s
+
+    def decompose(self):
+        dval = self.stop and [self.patterns['start']] or [] 
+        dval += [self.patterns[c] for c in self.encoded]
+        if self.stop: dval.append(self.patterns['stop'])
+        self.decomposed = ''.join(dval)
+        return self.decomposed
+
+class Codabar(Barcode):
+    """
+    Codabar is a numeric plus some puntuation ("-$:/.+") barcode
+    with four start/stop characters (A, B, C, and D).
+
+    Options that may be passed to constructor:
+
+        value (string. required.):
+            The value to encode.
+
+        barWidth (float, default .0065):
+            X-Dimension, or width of the smallest element
+            minimum is 6.5 mils (.0065 inch)
+
+        ratio (float, default 2.0):
+            The ratio of wide elements to narrow elements.
+
+        gap (float or None, default None):
+            width of intercharacter gap. None means "use barWidth".
+
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        checksum (bool, default 0):
+            Whether to compute and include the check digit
+
+        bearers (float, in units of barWidth. default 0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 0 (no bearers).
+
+        quiet (bool, default 1):
+            Whether to include quiet zones in the symbol.
+
+        stop (bool, default 1):
+            Whether to include start/stop symbols.
+
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or 10 barWidth
+
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+    Sources of Information on Codabar
+
+    http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html
+    http://www.barcodeman.com/codabar.html
+
+    Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from
+    http://www.aimglobal.org/aimstore/
+    """
+
+    patterns = {
+        '0':    'bsbsbSB',        '1':    'bsbsBSb',        '2':    'bsbSbsB',
+        '3':    'BSbsbsb',        '4':    'bsBsbSb',        '5':    'BsbsbSb',
+        '6':    'bSbsbsB',        '7':    'bSbsBsb',        '8':    'bSBsbsb',
+        '9':    'BsbSbsb',        '-':    'bsbSBsb',        '$':    'bsBSbsb',
+        ':':    'BsbsBsB',        '/':    'BsBsbsB',        '.':    'BsBsBsb',
+        '+':    'bsBsBsB',        'A':    'bsBSbSb',        'B':    'bSbSbsB',
+        'C':    'bsbSbSB',        'D':    'bsbSBSb'
+    }
+
+    values = {
+        '0' : 0,    '1' : 1,    '2' : 2,    '3' : 3,    '4' : 4,
+        '5' : 5,    '6' : 6,    '7' : 7,    '8' : 8,    '9' : 9,
+        '-' : 10,   '$' : 11,   ':' : 12,   '/' : 13,   '.' : 14,
+        '+' : 15,   'A' : 16,   'B' : 17,   'C' : 18,   'D' : 19
+        }
+
+    chars = string.digits + "-$:/.+"
+
+    stop = 1
+    barHeight = None
+    barWidth = inch * 0.0065
+    ratio = 2.0 # XXX ?
+    checksum = 0
+    bearers = 0.0
+    quiet = 1
+    lquiet = None
+    rquiet = None
+
+    def __init__(self, value='', **args):
+        if type(value) == type(1):
+            value = str(value)
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        s = string.strip(self.value)
+        for i in range(0, len(s)):
+            c = s[i]
+            if c not in self.chars:
+                if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'):
+                    self.Valid = 0
+                    continue
+            vval = vval + c
+
+        if self.stop:
+            if vval[0] not in 'ABCD':
+                vval = 'A' + vval
+            if vval[-1] not in 'ABCD':
+                vval = vval + vval[0]
+
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        s = self.validated
+
+        if self.checksum:
+            v = sum([self.values[c] for c in s])
+            s += self.chars[v % 16]
+
+        self.encoded = s
+
+    def decompose(self):
+        dval = ''.join([self.patterns[c]+'i' for c in self.encoded])
+        self.decomposed = dval[:-1]
+        return self.decomposed
+
+class Code11(Barcode):
+    """
+    Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus
+    dash ("-"). 11 characters total, hence the name.
+
+        value (int or string. required.):
+            The value to encode.
+
+        barWidth (float, default .0075):
+            X-Dimension, or width of the smallest element
+
+        ratio (float, default 2.2):
+            The ratio of wide elements to narrow elements.
+
+        gap (float or None, default None):
+            width of intercharacter gap. None means "use barWidth".
+
+        barHeight (float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.
+
+        checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
+            How many checksum digits to include. -1 ("auto") means
+            1 if the number of digits is 10 or less, else 2.
+
+        bearers (float, in units of barWidth. default 0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 0 (no bearers).
+
+        quiet (bool, default 1):
+            Wether to include quiet zones in the symbol.
+
+        lquiet (float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or 10 barWidth
+
+        rquiet (float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.
+
+    Sources of Information on Code 11:
+
+    http://www.cwi.nl/people/dik/english/codes/barcodes.html
+    """
+
+    chars = string.digits + '-'
+
+    patterns = {
+        '0' : 'bsbsB',        '1' : 'BsbsB',        '2' : 'bSbsB',
+        '3' : 'BSbsb',        '4' : 'bsBsB',        '5' : 'BsBsb',
+        '6' : 'bSBsb',        '7' : 'bsbSB',        '8' : 'BsbSb',
+        '9' : 'Bsbsb',        '-' : 'bsBsb',        'S' : 'bsBSb' # Start/Stop
+    }
+
+    values = {
+        '0' : 0,    '1' : 1,    '2' : 2,    '3' : 3,    '4' : 4,
+        '5' : 5,    '6' : 6,    '7' : 7,    '8' : 8,    '9' : 9,
+        '-' : 10,
+    }
+
+    stop = 1
+    barHeight = None
+    barWidth = inch * 0.0075
+    ratio = 2.2 # XXX ?
+    checksum = -1 # Auto
+    bearers = 0.0
+    quiet = 1
+    lquiet = None
+    rquiet = None
+    def __init__(self, value='', **args):
+        if type(value) == type(1):
+            value = str(value)
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        if self.quiet:
+            if self.lquiet is None:
+                self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
+                self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
+        else:
+            self.lquiet = self.rquiet = 0.0
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        vval = ""
+        self.valid = 1
+        s = string.strip(self.value)
+        for i in range(0, len(s)):
+            c = s[i]
+            if c not in self.chars:
+                self.Valid = 0
+                continue
+            vval = vval + c
+
+        self.validated = vval
+        return vval
+
+    def encode(self):
+        s = self.validated
+
+        if self.checksum == -1:
+            if len(s) <= 10:
+                self.checksum = 1
+            else:
+                self.checksum = 2
+
+        if self.checksum > 0:
+            # compute first checksum
+            i = 0; v = 1; c = 0
+            while i < len(s):
+                c = c + v * string.index(self.chars, s[-(i+1)])
+                i = i + 1; v = v + 1
+                if v > 10:
+                    v = 1
+            s = s + self.chars[c % 11]
+
+        if self.checksum > 1:
+            # compute second checksum
+            i = 0; v = 1; c = 0
+            while i < len(s):
+                c = c + v * string.index(self.chars, s[-(i+1)])
+                i = i + 1; v = v + 1
+                if v > 9:
+                    v = 1
+            s = s + self.chars[c % 10]
+
+        self.encoded = self.stop and ('S' + s + 'S') or s
+
+    def decompose(self):
+        dval = [self.patterns[c]+'i' for c in self.encoded]
+        self.decomposed = ''.join(dval[:-1])
+        return self.decomposed
+
+    def _humanText(self):
+        return self.stop and self.encoded[1:-1] or self.encoded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/eanbc.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,339 @@
+__all__=(
+        'Ean13BarcodeWidget','isEanString',
+        )
+from reportlab.graphics.shapes import Group, String, Rect
+from reportlab.lib import colors
+from reportlab.pdfbase.pdfmetrics import stringWidth
+from reportlab.lib.validators import isNumber, isColor, isString, Validator, isBoolean
+from reportlab.lib.attrmap import *
+from reportlab.graphics.charts.areas import PlotArea
+from reportlab.lib.units import mm
+
+#work out a list of manufacturer codes....
+_eanNumberSystems = [
+         ('00-13', 'USA & Canada'),
+         ('20-29', 'In-Store Functions'),
+         ('30-37', 'France'),
+         ('40-44', 'Germany'),
+         ('45', 'Japan (also 49)'),
+         ('46', 'Russian Federation'),
+         ('471', 'Taiwan'),
+         ('474', 'Estonia'),
+         ('475', 'Latvia'),
+         ('477', 'Lithuania'),
+         ('479', 'Sri Lanka'),
+         ('480', 'Philippines'),
+         ('482', 'Ukraine'),
+         ('484', 'Moldova'),
+         ('485', 'Armenia'),
+         ('486', 'Georgia'),
+         ('487', 'Kazakhstan'),
+         ('489', 'Hong Kong'),
+         ('49', 'Japan (JAN-13)'),
+         ('50', 'United Kingdom'),
+         ('520', 'Greece'),
+         ('528', 'Lebanon'),
+         ('529', 'Cyprus'),
+         ('531', 'Macedonia'),
+         ('535', 'Malta'),
+         ('539', 'Ireland'),
+         ('54', 'Belgium & Luxembourg'),
+         ('560', 'Portugal'),
+         ('569', 'Iceland'),
+         ('57', 'Denmark'),
+         ('590', 'Poland'),
+         ('594', 'Romania'),
+         ('599', 'Hungary'),
+         ('600-601', 'South Africa'),
+         ('609', 'Mauritius'),
+         ('611', 'Morocco'),
+         ('613', 'Algeria'),
+         ('619', 'Tunisia'),
+         ('622', 'Egypt'),
+         ('625', 'Jordan'),
+         ('626', 'Iran'),
+         ('64', 'Finland'),
+         ('690-692', 'China'),
+         ('70', 'Norway'),
+         ('729', 'Israel'),
+         ('73', 'Sweden'),
+         ('740', 'Guatemala'),
+         ('741', 'El Salvador'),
+         ('742', 'Honduras'),
+         ('743', 'Nicaragua'),
+         ('744', 'Costa Rica'),
+         ('746', 'Dominican Republic'),
+         ('750', 'Mexico'),
+         ('759', 'Venezuela'),
+         ('76', 'Switzerland'),
+         ('770', 'Colombia'),
+         ('773', 'Uruguay'),
+         ('775', 'Peru'),
+         ('777', 'Bolivia'),
+         ('779', 'Argentina'),
+         ('780', 'Chile'),
+         ('784', 'Paraguay'),
+         ('785', 'Peru'),
+         ('786', 'Ecuador'),
+         ('789', 'Brazil'),
+         ('80-83', 'Italy'),
+         ('84', 'Spain'),
+         ('850', 'Cuba'),
+         ('858', 'Slovakia'),
+         ('859', 'Czech Republic'),
+         ('860', 'Yugloslavia'),
+         ('869', 'Turkey'),
+         ('87', 'Netherlands'),
+         ('880', 'South Korea'),
+         ('885', 'Thailand'),
+         ('888', 'Singapore'),
+         ('890', 'India'),
+         ('893', 'Vietnam'),
+         ('899', 'Indonesia'),
+         ('90-91', 'Austria'),
+         ('93', 'Australia'),
+         ('94', 'New Zealand'),
+         ('955', 'Malaysia'),
+         ('977', 'International Standard Serial Number for Periodicals (ISSN)'),
+         ('978', 'International Standard Book Numbering (ISBN)'),
+         ('979', 'International Standard Music Number (ISMN)'),
+         ('980', 'Refund receipts'),
+         ('981-982', 'Common Currency Coupons'),
+         ('99', 'Coupons')
+         ]
+
+manufacturerCodes = {}
+for (k, v) in _eanNumberSystems:
+    words = k.split('-')
+    if len(words)==2:
+        fromCode = int(words[0])
+        toCode = int(words[1])
+        for code in range(fromCode, toCode+1):
+            manufacturerCodes[code] = v
+    else:
+        manufacturerCodes[int(k)] = v
+
+class isEan13String(Validator):
+    def test(self,x):
+        return type(x) is str and len(x)<=12 and len([c for c in x if c in "0123456789"])==12
+isEan13String = isEan13String()
+
+class Ean13BarcodeWidget(PlotArea):
+    codeName = "EAN13"
+    _attrMap = AttrMap(BASE=PlotArea,
+        value = AttrMapValue(isEan13String, desc='the number'),
+        fontName = AttrMapValue(isString, desc='fontName'),
+        fontSize = AttrMapValue(isNumber, desc='font size'),
+        x = AttrMapValue(isNumber, desc='x-coord'),
+        y = AttrMapValue(isNumber, desc='y-coord'),
+        barFillColor = AttrMapValue(isColor, desc='bar color'),
+        barHeight = AttrMapValue(isNumber, desc='Height of bars.'),
+        barWidth = AttrMapValue(isNumber, desc='Width of bars.'),
+        barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
+        barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'),
+        textColor = AttrMapValue(isColor, desc='human readable text color'),
+        humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
+        quiet = AttrMapValue(isBoolean, desc='if quiet zone to be used'),
+        lquiet = AttrMapValue(isBoolean, desc='left quiet zone length'),
+        rquiet = AttrMapValue(isBoolean, desc='right quiet zone length'),
+        )
+    _digits=12
+    _start_right = 7    #for ean-13 left = [0:7] right=[7:13]
+    _nbars = 113
+    barHeight = 25.93*mm    #millimeters
+    barWidth = (37.29/_nbars)*mm
+    humanReadable = 1
+    _0csw = 1
+    _1csw = 3
+
+    #Left Hand Digits.
+    _left = (   ("0001101", "0011001", "0010011", "0111101",
+                "0100011", "0110001", "0101111", "0111011",
+                "0110111", "0001011",
+                ),  #odd left hand digits
+                ("0100111", "0110011", "0011011", "0100001",
+                "0011101", "0111001", "0000101", "0010001",
+                "0001001", "0010111"),  #even left hand digits
+            )
+
+    _right = ("1110010", "1100110", "1101100", "1000010",
+            "1011100", "1001110", "1010000", "1000100",
+            "1001000", "1110100")
+
+    quiet = 1
+    rquiet = lquiet = None
+    _tail = "101"
+    _sep = "01010"
+
+    _lhconvert={
+            "0": (0,0,0,0,0,0),
+            "1": (0,0,1,0,1,1),
+            "2": (0,0,1,1,0,1),
+            "3": (0,0,1,1,1,0),
+            "4": (0,1,0,0,1,1),
+            "5": (0,1,1,0,0,1),
+            "6": (0,1,1,1,0,0),
+            "7": (0,1,0,1,0,1),
+            "8": (0,1,0,1,1,0),
+            "9": (0,1,1,0,1,0)
+            }
+    fontSize = 8        #millimeters
+    fontName = 'Helvetica'
+    textColor = barFillColor = barStrokeColor = colors.black
+    barStrokeWidth = 0
+    x = 0
+    y = 0
+    def __init__(self,value='123456789012',**kw):
+        self.value=max(self._digits-len(value),0)*'0'+value[:self._digits]
+        for k, v in kw.iteritems():
+            setattr(self, k, v)
+
+    width = property(lambda self: self.barWidth*(self._nbars-18+self._calc_quiet(self.lquiet)+self._calc_quiet(self.rquiet)))
+
+    def wrap(self,aW,aH):
+        return self.width,self.barHeight
+
+    def _encode_left(self,s,a):
+        cp = self._lhconvert[s[0]]      #convert the left hand numbers
+        _left = self._left
+        z = ord('0')
+        for i,c in enumerate(s[1:self._start_right]):
+            a(_left[cp[i]][ord(c)-z])
+
+    def _short_bar(self,i):
+        i += 9 - self._lquiet
+        return self.humanReadable and ((12<i<55) or (57<i<101))
+
+    def _calc_quiet(self,v):
+        if self.quiet:
+            if v is None:
+                v = 9
+            else:
+                x = float(max(v,0))/self.barWidth
+                v = int(x)
+                if v-x>0: v += 1
+        else:
+            v = 0
+        return v
+
+    def draw(self):
+        g = Group()
+        gAdd = g.add
+        barWidth = self.barWidth
+        width = self.width
+        barHeight = self.barHeight
+        x = self.x
+        y = self.y
+        gAdd(Rect(x,y,width,barHeight,fillColor=None,strokeColor=None,strokeWidth=0))
+        s = self.value+self._checkdigit(self.value)
+        self._lquiet = lquiet = self._calc_quiet(self.lquiet)
+        rquiet = self._calc_quiet(self.rquiet)
+        b = [lquiet*'0',self._tail] #the signal string
+        a = b.append
+        self._encode_left(s,a)
+        a(self._sep)
+
+        z = ord('0')
+        _right = self._right
+        for c in s[self._start_right:]:
+            a(_right[ord(c)-z])
+        a(self._tail)
+        a(rquiet*'0')
+
+        fontSize = self.fontSize
+        barFillColor = self.barFillColor
+        barStrokeWidth = self.barStrokeWidth
+
+        fth = fontSize*1.2
+        b = ''.join(b)
+
+        lrect = None
+        for i,c in enumerate(b):
+            if c=="1":
+                dh = self._short_bar(i) and fth or 0
+                yh = y+dh
+                if lrect and lrect.y==yh:
+                    lrect.width += barWidth
+                else:
+                    lrect = Rect(x,yh,barWidth,barHeight-dh,fillColor=barFillColor,strokeWidth=barStrokeWidth,strokeColor=barFillColor)
+                    gAdd(lrect)
+            else:
+                lrect = None
+            x += barWidth
+
+        if self.humanReadable: self._add_human_readable(s,gAdd)
+        return g
+
+    def _add_human_readable(self,s,gAdd):
+        barWidth = self.barWidth
+        fontSize = self.fontSize
+        textColor = self.textColor
+        fontName = self.fontName
+        fth = fontSize*1.2
+        # draw the num below the line.
+        c = s[0]
+        w = stringWidth(c,fontName,fontSize)
+        x = self.x+barWidth*(self._lquiet-8)
+        y = self.y + 0.2*fth
+
+        gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor))
+        x = self.x + (33-9+self._lquiet)*barWidth
+
+        c = s[1:7]
+        gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
+
+        x += 47*barWidth
+        c = s[7:]
+        gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
+
+    @classmethod
+    def _checkdigit(cls,num):
+        z = ord('0')
+        iSum = cls._0csw*sum([(ord(x)-z) for x in num[::2]]) \
+                 + cls._1csw*sum([(ord(x)-z) for x in num[1::2]])
+        return chr(z+((10-(iSum%10))%10))
+
+class isEan8String(Validator):
+    def test(self,x):
+        return type(x) is str and len(x)<=7 and len([c for c in x if c in "0123456789"])==7
+isEan8String = isEan8String()
+
+class Ean8BarcodeWidget(Ean13BarcodeWidget):
+    codeName = "EAN8"
+    _attrMap = AttrMap(BASE=Ean13BarcodeWidget,
+        value = AttrMapValue(isEan8String, desc='the number'),
+        )
+    _start_right = 4    #for ean-13 left = [0:7] right=[7:13]
+    _nbars = 85
+    _digits=7
+    _0csw = 3
+    _1csw = 1
+
+    def _encode_left(self,s,a):
+        cp = self._lhconvert[s[0]]      #convert the left hand numbers
+        _left = self._left[0]
+        z = ord('0')
+        for i,c in enumerate(s[0:self._start_right]):
+            a(_left[ord(c)-z])
+
+    def _short_bar(self,i):
+        i += 9 - self._lquiet
+        return self.humanReadable and ((12<i<41) or (43<i<73))
+
+    def _add_human_readable(self,s,gAdd):
+        barWidth = self.barWidth
+        fontSize = self.fontSize
+        textColor = self.textColor
+        fontName = self.fontName
+        fth = fontSize*1.2
+        # draw the num below the line.
+        y = self.y + 0.2*fth
+
+        x = (26.5-9+self._lquiet)*barWidth
+
+        c = s[0:4]
+        gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
+
+        x = (59.5-9+self._lquiet)*barWidth
+        c = s[4:]
+        gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/fourstate.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,81 @@
+#
+# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.lib.units import inch
+from common import Barcode
+import string
+
+# . 3 T Tracker
+# , 2 D Descender
+# ' 1 A Ascender
+# | 0 H Ascender/Descender
+
+_rm_patterns = {
+    "0" : "--||",   "1" : "-',|",   "2" : "-'|,",   "3" : "'-,|",
+    "4" : "'-|,",   "5" : "'',,",   "6" : "-,'|",   "7" : "-|-|",
+    "8" : "-|',",   "9" : "',-|",   "A" : "',',",   "B" : "'|-,",
+    "C" : "-,|'",   "D" : "-|,'",   "E" : "-||-",   "F" : "',,'",
+    "G" : "',|-",   "H" : "'|,-",   "I" : ",-'|",   "J" : ",'-|",
+    "K" : ",'',",   "L" : "|--|",   "M" : "|-',",   "N" : "|'-,",
+    "O" : ",-|'",   "P" : ",','",   "Q" : ",'|-",   "R" : "|-,'",
+    "S" : "|-|-",   "T" : "|',-",   "U" : ",,''",   "V" : ",|-'",
+    "W" : ",|'-",   "X" : "|,-'",   "Y" : "|,'-",   "Z" : "||--",
+
+    # start, stop
+    "(" : "'-,'",   ")" : "'|,|"
+}
+
+_ozN_patterns = {
+    "0" : "||",    "1" : "|'",    "2" : "|,",    "3" : "'|",    "4" : "''",
+    "5" : "',",    "6" : ",|",    "7" : ",'",    "8" : ",,",    "9" : ".|"
+}
+
+_ozC_patterns = {
+    "A" : "|||",    "B" : "||'",    "C" : "||,",    "D" : "|'|",
+    "E" : "|''",    "F" : "|',",    "G" : "|,|",    "H" : "|,'",
+    "I" : "|,,",    "J" : "'||",    "K" : "'|'",    "L" : "'|,",
+    "M" : "''|",    "N" : "'''",    "O" : "'',",    "P" : "',|",
+    "Q" : "','",    "R" : "',,",    "S" : ",||",    "T" : ",|'",
+    "U" : ",|,",    "V" : ",'|",    "W" : ",''",    "X" : ",',",
+    "Y" : ",,|",    "Z" : ",,'",    "a" : "|,.",    "b" : "|.|",
+    "c" : "|.'",    "d" : "|.,",    "e" : "|..",    "f" : "'|.",
+    "g" : "''.",    "h" : "',.",    "i" : "'.|",    "j" : "'.'",
+    "k" : "'.,",    "l" : "'..",    "m" : ",|.",    "n" : ",'.",
+    "o" : ",,.",    "p" : ",.|",    "q" : ",.'",    "r" : ",.,",
+    "s" : ",..",    "t" : ".|.",    "u" : ".'.",    "v" : ".,.",
+    "w" : "..|",    "x" : "..'",    "y" : "..,",    "z" : "...",
+    "0" : ",,,",    "1" : ".||",    "2" : ".|'",    "3" : ".|,",
+    "4" : ".'|",    "5" : ".''",    "6" : ".',",    "7" : ".,|",
+    "8" : ".,'",    "9" : ".,,",    " " : "||.",    "#" : "|'.",
+}
+
+#http://www.auspost.com.au/futurepost/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/test.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,185 @@
+#!/usr/pkg/bin/python
+
+import os, sys, time
+
+from rlextra.graphics.barcode.common import *
+from rlextra.graphics.barcode.code39 import *
+from rlextra.graphics.barcode.code93 import *
+from rlextra.graphics.barcode.code128 import *
+from rlextra.graphics.barcode.usps import *
+
+
+from reportlab.test import unittest
+from reportlab.test.utils import makeSuiteForClasses, outputfile, printLocation
+from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, Preformatted, PageBreak
+from reportlab.lib.units import inch, cm
+from reportlab.lib import colors
+
+from reportlab.pdfgen.canvas import Canvas
+from reportlab.lib.styles import getSampleStyleSheet
+from reportlab.platypus.paragraph import Paragraph
+from reportlab.platypus.frames import Frame
+from reportlab.platypus.flowables import XBox, KeepTogether
+from reportlab.graphics.shapes import Drawing
+
+from rlextra.graphics.barcode import getCodes, getCodeNames, createBarcodeDrawing
+def run():
+    styles = getSampleStyleSheet()
+    styleN = styles['Normal']
+    styleH = styles['Heading1']
+    story = []
+
+    #for codeNames in code
+    story.append(Paragraph('I2of5', styleN))
+    story.append(I2of5(1234, barWidth = inch*0.02, checksum=0))
+    story.append(Paragraph('MSI', styleN))
+    story.append(MSI(1234))
+    story.append(Paragraph('Codabar', styleN))
+    story.append(Codabar("A012345B", barWidth = inch*0.02))
+    story.append(Paragraph('Code 11', styleN))
+    story.append(Code11("01234545634563"))
+    story.append(Paragraph('Code 39', styleN))
+    story.append(Standard39("A012345B%R"))
+    story.append(Paragraph('Extended Code 39', styleN))
+    story.append(Extended39("A012345B}"))
+    story.append(Paragraph('Code93', styleN))
+    story.append(Standard93("CODE 93"))
+    story.append(Paragraph('Extended Code93', styleN))
+    story.append(Extended93("L@@K! Code 93 :-)")) #, barWidth=0.005 * inch))
+    story.append(Paragraph('Code 128', styleN))
+    c=Code128("AB-12345678") #, barWidth=0.005 * inch)
+    #print 'WIDTH =', (c.width / inch), 'barWidth =', (c.barWidth / inch)
+    #print 'LQ =', (c.lquiet / inch), 'RQ =', (c.rquiet / inch)
+    story.append(c)
+    story.append(Paragraph('USPS FIM', styleN))
+    story.append(FIM("A"))
+    story.append(Paragraph('USPS POSTNET', styleN))
+    story.append(POSTNET('78247-1043'))
+
+    from rlextra.graphics.barcode import createBarcodeDrawing
+    story.append(Paragraph('EAN13', styleN))
+    bcd = createBarcodeDrawing('EAN13', value='123456789012')
+    story.append(bcd)
+    story.append(Paragraph('EAN8', styleN))
+    bcd = createBarcodeDrawing('EAN8', value='1234567')
+    story.append(bcd)
+
+    story.append(Paragraph('Label Size', styleN))
+    story.append(XBox((2.0 + 5.0/8.0)*inch, 1 * inch, '1x2-5/8"'))
+    story.append(Paragraph('Label Size', styleN))
+    story.append(XBox((1.75)*inch, .5 * inch, '1/2x1-3/4"'))
+    c = Canvas('out.pdf')
+    f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1)
+    f.addFromList(story, c)
+    c.save()
+    print 'saved out.pdf'
+
+def fullTest(fileName="test_full.pdf"):
+    """Creates large-ish test document with a variety of parameters"""
+
+    story = []
+
+    styles = getSampleStyleSheet()
+    styleN = styles['Normal']
+    styleH = styles['Heading1']
+    styleH2 = styles['Heading2']
+    story = []
+
+    story.append(Paragraph('ReportLab Barcode Test Suite - full output', styleH))
+    story.append(Paragraph('Generated on %s' % time.ctime(time.time()), styleN))
+
+    story.append(Paragraph('', styleN))
+    story.append(Paragraph('Repository information for this build:', styleN))
+    #see if we can figure out where it was built, if we're running in source
+    if os.path.split(os.getcwd())[-1] == 'barcode' and os.path.isdir('.svn'):
+        #runnning in a filesystem svn copy
+        infoLines = os.popen('svn info').read()
+        story.append(Preformatted(infoLines, styles["Code"]))
+        
+    story.append(Paragraph('About this document', styleH2))
+    story.append(Paragraph('History and Status', styleH2))
+
+    story.append(Paragraph("""
+        This is the test suite and docoumentation for the ReportLab open source barcode API,
+        being re-released as part of the forthcoming ReportLab 2.0 release.
+        """, styleN))
+
+    story.append(Paragraph("""
+        Several years ago Ty Sarna contributed a barcode module to the ReportLab community.
+        Several of the codes were used by him in hiw work and to the best of our knowledge
+        this was correct.  These were written as flowable objects and were available in PDFs,
+        but not in our graphics framework.  However, we had no knowledge of barcodes ourselves
+        and did not advertise or extend the package.
+        """, styleN))
+
+    story.append(Paragraph("""
+        We "wrapped" the barcodes to be usable within our graphics framework; they are now available
+        as Drawing objects which can be rendered to EPS files or bitmaps.  For the last 2 years this
+        has been available in our Diagra and Report Markup Language products.  However, we did not
+        charge separately and use was on an "as is" basis.
+        """, styleN))
+
+    story.append(Paragraph("""
+        A major licensee of our technology has kindly agreed to part-fund proper productisation
+        of this code on an open source basis in Q1 2006.  This has involved addition of EAN codes
+        as well as a proper testing program.  Henceforth we intend to publicise the code more widely,
+        gather feedback, accept contributions of code and treat it as "supported".  
+        """, styleN))
+
+    story.append(Paragraph("""
+        This involved making available both downloads and testing resources.  This PDF document
+        is the output of the current test suite.  It contains codes you can scan (if you use a nice sharp
+        laser printer!), and will be extended over coming weeks to include usage examples and notes on
+        each barcode and how widely tested they are.  This is being done through documentation strings in
+        the barcode objects themselves so should always be up to date.
+        """, styleN))
+
+    story.append(Paragraph('Usage examples', styleH2))
+    story.append(Paragraph("""
+        To be completed
+        """, styleN))
+
+    story.append(Paragraph('The codes', styleH2))
+    story.append(Paragraph("""
+        Below we show a scannable code from each barcode, with and without human-readable text.
+        These are magnified about 2x from the natural size done by the original author to aid
+        inspection.  This will be expanded to include several test cases per code, and to add
+        explanations of checksums.  Be aware that (a) if you enter numeric codes which are too
+        short they may be prefixed for you (e.g. "123" for an 8-digit code becomes "00000123"),
+        and that the scanned results and readable text will generally include extra checksums
+        at the end.
+        """, styleN))
+
+    codeNames = getCodeNames()
+    from reportlab.lib.utils import flatten
+    width = [float(x[8:]) for x in sys.argv if x.startswith('--width=')]
+    height = [float(x[9:]) for x in sys.argv if x.startswith('--height=')]
+    isoScale = [int(x[11:]) for x in sys.argv if x.startswith('--isoscale=')]
+    options = {}
+    if width: options['width'] = width[0]
+    if height: options['height'] = height[0]
+    if isoScale: options['isoScale'] = isoScale[0]
+    scales = [x[8:].split(',') for x in sys.argv if x.startswith('--scale=')]
+    scales = map(float,scales and flatten(scales) or [1])
+    scales = map(float,scales and flatten(scales) or [1])
+    for scale in scales:
+        story.append(PageBreak())
+        story.append(Paragraph('Scale = %.1f'%scale, styleH2))
+        story.append(Spacer(36, 12))
+        for codeName in codeNames:
+            s = [Paragraph('Code: ' + codeName, styleH2)]
+            for hr in (0,1):
+                s.append(Spacer(36, 12))
+                dr = createBarcodeDrawing(codeName, humanReadable=hr,**options)
+                dr.renderScale = scale
+                s.append(dr)
+                s.append(Spacer(36, 12))
+            s.append(Paragraph('Barcode should say: ' + dr._bc.value, styleN))
+            story.append(KeepTogether(s))
+
+    SimpleDocTemplate(fileName).build(story)
+    print 'created', fileName
+
+if __name__=='__main__':
+    run()
+    fullTest()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/usps.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,228 @@
+#
+# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by Tyler C. Sarna.
+# 4. Neither the name of the author nor the names of contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from reportlab.lib.units import inch
+from common import Barcode
+import string
+
+_fim_patterns = {
+    'A' : "||  |  ||",
+    'B' : "| || || |",
+    'C' : "|| | | ||",
+    'D' : "||| | |||",
+    # XXX There is an E.
+    # The below has been seen, but dunno if it is E or not:
+    # 'E' : '|||| ||||'
+}
+
+_postnet_patterns = {
+    '1' : "...||",    '2' : "..|.|",    '3' : "..||.",    '4' : ".|..|",
+    '5' : ".|.|.",    '6' : ".||..",    '7' : "|...|",    '8' : "|..|.",
+    '9' : "|.|..",    '0' : "||...",    'S' : "|",
+}
+
+class FIM(Barcode):
+    """"
+    FIM (Facing ID Marks) encode only one letter.
+    There are currently four defined:
+
+    A   Courtesy reply mail with pre-printed POSTNET
+    B   Business reply mail without pre-printed POSTNET
+    C   Business reply mail with pre-printed POSTNET
+    D   OCR Readable mail without pre-printed POSTNET
+
+    Options that may be passed to constructor:
+
+        value (single character string from the set A - D. required.):
+            The value to encode.
+
+        quiet (bool, default 0):
+            Whether to include quiet zones in the symbol.
+
+    The following may also be passed, but doing so will generate nonstandard
+    symbols which should not be used. This is mainly documented here to
+    show the defaults:
+
+        barHeight (float, default 5/8 inch):
+            Height of the code. This might legitimately be overriden to make
+            a taller symbol that will 'bleed' off the edge of the paper,
+            leaving 5/8 inch remaining.
+
+        lquiet (float, default 1/4 inch):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or .15 times the symbol's
+            length.
+
+        rquiet (float, default 15/32 inch):
+            Quiet zone size to right left of code, if quiet is true.
+
+    Sources of information on FIM:
+
+    USPS Publication 25, A Guide to Business Mail Preparation
+    http://new.usps.com/cpim/ftp/pubs/pub25.pdf
+    """
+    barWidth = inch * (1.0/32.0)
+    spaceWidth = inch * (1.0/16.0)
+    barHeight = inch * (5.0/8.0)
+    rquiet = inch * (0.25)
+    lquiet = inch * (15.0/32.0)
+    quiet = 0
+    def __init__(self, value='', **args):
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        self.valid = 1
+        self.validated = ''
+        for c in self.value:
+            if c in string.whitespace:
+                continue
+            elif c in "abcdABCD":
+                self.validated = self.validated + string.upper(c)
+            else:
+                self.valid = 0
+
+        if len(self.validated) != 1:
+            raise ValueError, "Input must be exactly one character"
+
+        return self.validated
+
+    def decompose(self):
+        self.decomposed = ''
+        for c in self.encoded:
+            self.decomposed = self.decomposed + _fim_patterns[c]
+
+        return self.decomposed
+
+    def computeSize(self):
+        self.width = (len(self.decomposed) - 1) * self.spaceWidth + self.barWidth
+        if self.quiet:
+            self.width += self.lquiet + self.rquiet
+        self.height = self.barHeight
+
+    def draw(self):
+        left = self.quiet and self.lquiet or 0
+        for c in self.decomposed:
+            if c == '|':
+                self.rect(left, 0.0, self.barWidth, self.barHeight)
+            left += self.spaceWidth
+        self.drawHumanReadable()
+
+    def _humanText(self):
+        return self.value
+
+class POSTNET(Barcode):
+    """"
+    POSTNET is used in the US to encode "zip codes" (postal codes) on
+    mail. It can encode 5, 9, or 11 digit codes. I've read that it's
+    pointless to do 5 digits, since USPS will just have to re-print
+    them with 9 or 11 digits.
+
+    Sources of information on POSTNET:
+
+    USPS Publication 25, A Guide to Business Mail Preparation
+    http://new.usps.com/cpim/ftp/pubs/pub25.pdf
+    """
+    quiet = 0
+    shortHeight = inch * 0.050
+    barHeight = inch * 0.125
+    barWidth = inch * 0.018
+    spaceWidth = inch * 0.0275
+    def __init__(self, value='', **args):
+
+        for (k, v) in args.items():
+            setattr(self, k, v)
+
+        Barcode.__init__(self, value)
+
+    def validate(self):
+        self.validated = ''
+        self.valid = 1
+        count = 0
+        for c in self.value:
+            if c in (string.whitespace + '-'):
+                pass
+            elif c in string.digits:
+                count = count + 1
+                if count == 6:
+                    self.validated = self.validated + '-'
+                self.validated = self.validated + c
+            else:
+                self.valid = 0
+
+        if len(self.validated) not in [5, 10, 12]:
+            self.valid = 0
+
+        return self.validated
+
+    def encode(self):
+        self.encoded = "S"
+        check = 0
+        for c in self.validated:
+            if c in string.digits:
+                self.encoded = self.encoded + c
+                check = check + string.atoi(c)
+            elif c == '-':
+                pass
+            else:
+                raise ValueError, "Invalid character in input"
+        check = (10 - (check % 10)) % 10
+        self.encoded = self.encoded + `check` + 'S'
+        return self.encoded
+
+    def decompose(self):
+        self.decomposed = ''
+        for c in self.encoded:
+            self.decomposed = self.decomposed + _postnet_patterns[c]
+        return self.decomposed
+
+    def computeSize(self):
+        self.width = len(self.decomposed) * self.barWidth + (len(self.decomposed) - 1) * self.spaceWidth
+        self.height = self.barHeight
+
+    def draw(self):
+        sdown = self.barHeight - self.shortHeight
+        left = 0
+
+        for c in self.decomposed:
+            if c == '.':
+                h = self.shortHeight
+            else:
+                h = self.barHeight
+            self.rect(left, 0.0, self.barWidth, h)
+            left = left + self.barWidth + self.spaceWidth
+        self.drawHumanReadable()
+
+    def _humanText(self):
+        return self.encoded[1:-1]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reportlab/graphics/barcode/widgets.py	Thu May 04 10:48:36 2006 +0000
@@ -0,0 +1,304 @@
+#copyright ReportLab Europe Limited. 2000-2006
+#see license.txt for license details
+__version__=''' $Id$ '''
+__all__= (
+        'BarcodeI2of5',
+        'BarcodeCode128',
+        'BarcodeStandard93',
+        'BarcodeExtended93',
+        'BarcodeStandard39',
+        'BarcodeExtended39',
+        'BarcodeMSI',
+        'BarcodeCodabar',
+        'BarcodeCode11',
+        'BarcodeFIM',
+        'BarcodePOSTNET',
+        )
+
+from reportlab.lib.validators import isInt, isNumber, isColor, isString, isColorOrNone, OneOf, isBoolean, EitherOr, isNumberOrNone
+from reportlab.lib.attrmap import AttrMap, AttrMapValue
+from reportlab.lib.colors import black
+from reportlab.graphics.shapes import Line, Rect, Group, NotImplementedError, String
+from reportlab.graphics.charts.areas import PlotArea
+
+'''
+#snippet
+
+#first make your Drawing
+from reportlab.graphics.shapes import Drawing
+d= Drawing(100,50)
+
+#create and set up the widget
+from rlextra.graphics.barcode.widgets import BarcodeStandard93
+bc = BarcodeStandard93()
+bc.value = 'RGB-123456'
+
+#add to the drawing and save
+d.add(bc)
+#   d.save(formats=['gif','pict'],fnRoot='bc_sample')
+'''
+
+class _BarcodeWidget(PlotArea):
+    _attrMap = AttrMap(BASE=PlotArea,
+        barStrokeColor = AttrMapValue(isColorOrNone, desc='Color of bar borders.'),
+        barFillColor = AttrMapValue(isColorOrNone, desc='Color of bar interior areas.'),
+        barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
+        value = AttrMapValue(EitherOr((isString,isNumber)), desc='Value.'),
+        textColor = AttrMapValue(isColorOrNone, desc='Color of human readable text.'),
+        valid = AttrMapValue(isBoolean),
+        validated = AttrMapValue(isString,desc="validated form of input"),
+        encoded = AttrMapValue(None,desc="encoded form of input"),
+        decomposed = AttrMapValue(isString,desc="decomposed form of input"),
+        canv = AttrMapValue(None,desc="temporarily used for internal methods"),
+        gap = AttrMapValue(isNumberOrNone, desc='Width of inter character gaps.'),
+        )
+
+    barStrokeColor = barFillColor = textColor = black
+    barStrokeWidth = 0
+    _BCC = None
+    def __init__(self,BCC=None,_value='',**kw):
+        self._BCC = BCC
+        class Combiner(self.__class__,BCC):
+            __name__ = self.__class__.__name__
+        self.__class__ = Combiner
+        PlotArea.__init__(self)
+        self.x = self.y = 0
+        kw.setdefault('value',_value)
+        BCC.__init__(self,**kw)
+
+    def rect(self,x,y,w,h,**kw):
+        self._Gadd(Rect(self.x+x,self.y+y,w,h,
+                    strokeColor=self.barStrokeColor,strokeWidth=self.barStrokeWidth, fillColor=self.barFillColor))
+
+    def draw(self):
+        if not self._BCC: raise NotImplementedError("Abstract class %s cannot be drawn" % self.__class__.__name__)
+        self.canv = self
+        G = Group()
+        self._Gadd = G.add
+        self._Gadd(Rect(self.x,self.y,self.width,self.height,fillColor=None,strokeColor=None,strokeWidth=0.0001))
+        self._BCC.draw(self)
+        del self.canv, self._Gadd
+        return G
+
+    def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
+        self._Gadd(String(self.x+x,self.y+y,text,fontName=fontName,fontSize=fontSize,
+                            textAnchor=anchor,fillColor=self.textColor))
+
+class BarcodeI2of5(_BarcodeWidget):
+    """Interleaved 2 of 5 is used in distribution and warehouse industries.
+
+    It encodes an even-numbered sequence of numeric digits. There is an optional
+    module 10 check digit; if including this, the total length must be odd so that
+    it becomes even after including the check digit.  Otherwise the length must be
+    even. Since the check digit is optional, our library does not check it.
+    """
+
+    _tests = [
+        '12',
+        '1234',
+        '123456',
+        '12345678',
+        '1234567890'
+        ]
+    codeName = "I2of5"
+    _attrMap = AttrMap(BASE=_BarcodeWidget,
+        barWidth = AttrMapValue(isNumber,'''(float, default .0075):
+            X-Dimension, or width of the smallest element
+            Minumum is .0075 inch (7.5 mils).'''),
+        ratio = AttrMapValue(isNumber,'''(float, default 2.2):
+            The ratio of wide elements to narrow elements.
+            Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
+            barWidth is greater than 20 mils (.02 inch))'''),
+        gap = AttrMapValue(isNumberOrNone,'''(float or None, default None):
+            width of intercharacter gap. None means "use barWidth".'''),
+        barHeight = AttrMapValue(isNumber,'''(float, see default below):
+            Height of the symbol.  Default is the height of the two
+            bearer bars (if they exist) plus the greater of .25 inch
+            or .15 times the symbol's length.'''),
+        checksum = AttrMapValue(isBoolean,'''(bool, default 1):
+            Whether to compute and include the check digit'''),
+        bearers = AttrMapValue(isNumber,'''(float, in units of barWidth. default 3.0):
+            Height of bearer bars (horizontal bars along the top and
+            bottom of the barcode). Default is 3 x-dimensions.
+            Set to zero for no bearer bars. (Bearer bars help detect
+            misscans, so it is suggested to leave them on).'''),
+        quiet = AttrMapValue(isBoolean,'''(bool, default 1):
+            Whether to include quiet zones in the symbol.'''),
+
+        lquiet = AttrMapValue(isNumber,'''(float, see default below):
+            Quiet zone size to left of code, if quiet is true.
+            Default is the greater of .25 inch, or .15 times the symbol's
+            length.'''),
+
+        rquiet = AttrMapValue(isNumber,'''(float, defaults as above):
+            Quiet zone size to right left of code, if quiet is true.'''),
+        fontName = AttrMapValue(isString, desc='human readable font'),
+        fontSize = AttrMapValue(isNumber, desc='human readable font size'),
+        humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
+        stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
+        )
+    _bcTransMap = {}
+
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.common import I2of5
+        _BarcodeWidget.__init__(self,I2of5,1234,**kw)
+
+class BarcodeCode128(BarcodeI2of5):
+    """Code 128 encodes any number of characters in the ASCII character set.
+    """
+    _tests = [
+        'ReportLab Rocks!'
+        ]
+    codeName = "Code128"
+    _attrMap = AttrMap(BASE=BarcodeI2of5,UNWANTED=('bearers','checksum','ratio','checksum','stop'))
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.code128 import Code128
+        _BarcodeWidget.__init__(self,Code128,"AB-12345678",**kw)
+
+class BarcodeStandard93(BarcodeCode128):
+    """This is a compressed form of Code 39"""
+    codeName = "Standard93"
+    _attrMap = AttrMap(BASE=BarcodeCode128,
+        stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
+        )
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.code93 import Standard93
+        _BarcodeWidget.__init__(self,Standard93,"CODE 93",**kw)
+
+class BarcodeExtended93(BarcodeStandard93):
+    """This is a compressed form of Code 39, allowing the full ASCII charset"""
+    codeName = "Extended93"
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.code93 import Extended93
+        _BarcodeWidget.__init__(self,Extended93,"L@@K! Code 93 ;-)",**kw)
+
+class BarcodeStandard39(BarcodeI2of5):
+    """Code39 is widely used in non-retail, especially US defence and health.
+    Allowed characters are 0-9, A-Z (caps only), space, and -.$/+%*.
+    """
+
+    codeName = "Standard39"
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.code39 import Standard39
+        _BarcodeWidget.__init__(self,Standard39,"A012345B%R",**kw)
+
+class BarcodeExtended39(BarcodeI2of5):
+    """Extended 39 encodes the full ASCII character set by encoding
+    characters as pairs of Code 39 characters; $, /, % and + are used as
+    shift characters."""
+
+    codeName = "Extended39"
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.code39 import Extended39
+        _BarcodeWidget.__init__(self,Extended39,"A012345B}",**kw)
+
+class BarcodeMSI(BarcodeI2of5):
+    """MSI is used for inventory control in retail applications.
+
+    There are several methods for calculating check digits so we
+    do not implement one.
+    """
+    codeName = "MSI"
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.common import MSI
+        _BarcodeWidget.__init__(self,MSI,1234,**kw)
+
+class BarcodeCodabar(BarcodeI2of5):
+    """Used in blood banks, photo labs and FedEx labels.
+    Encodes 0-9, -$:/.+, and four start/stop characters A-D.
+    """
+    codeName = "Codabar"
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.common import Codabar
+        _BarcodeWidget.__init__(self,Codabar,"A012345B",**kw)
+
+class BarcodeCode11(BarcodeI2of5):
+    """Used mostly for labelling telecommunications equipment.
+    It encodes numeric digits.
+    """
+    codeName = "Code11"
+    _attrMap = AttrMap(BASE=BarcodeI2of5,
+        checksum = AttrMapValue(isInt,'''(integer, default 2):
+            Whether to compute and include the check digit(s).
+            (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
+            How many checksum digits to include. -1 ("auto") means
+            1 if the number of digits is 10 or less, else 2.'''),
+            )
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.common import Code11
+        _BarcodeWidget.__init__(self,Code11,"01234545634563",**kw)
+
+class BarcodeFIM(_BarcodeWidget):
+    """
+    FIM was developed as part of the POSTNET barcoding system. FIM (Face Identification Marking) is used by the cancelling machines to sort mail according to whether or not they have bar code and their postage requirements. There are four types of FIM called FIM A, FIM B, FIM C, and FIM D.
+
+    The four FIM types have the following meanings:
+        FIM A- Postage required pre-barcoded
+        FIM B - Postage pre-paid, no bar code exists
+        FIM C- Postage prepaid prebarcoded
+        FIM D- Postage required, no bar code exists
+    """
+    codeName = "FIM"
+    _attrMap = AttrMap(BASE=_BarcodeWidget,
+        barWidth = AttrMapValue(isNumber,'''(float, default 1/32in): the bar width.'''),
+        spaceWidth = AttrMapValue(isNumber,'''(float or None, default 1/16in):
+            width of intercharacter gap. None means "use barWidth".'''),
+        barHeight = AttrMapValue(isNumber,'''(float, default 5/8in): The bar height.'''),
+        quiet = AttrMapValue(isBoolean,'''(bool, default 0):
+            Whether to include quiet zones in the symbol.'''),
+        lquiet = AttrMapValue(isNumber,'''(float, default: 15/32in):
+            Quiet zone size to left of code, if quiet is true.'''),
+        rquiet = AttrMapValue(isNumber,'''(float, default 1/4in):
+            Quiet zone size to right left of code, if quiet is true.'''),
+        fontName = AttrMapValue(isString, desc='human readable font'),
+        fontSize = AttrMapValue(isNumber, desc='human readable font size'),
+        humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
+        )
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.usps import FIM
+        _BarcodeWidget.__init__(self,FIM,"A",**kw)
+
+class BarcodePOSTNET(_BarcodeWidget):
+    codeName = "POSTNET"
+    _attrMap = AttrMap(BASE=_BarcodeWidget,
+        barWidth = AttrMapValue(isNumber,'''(float, default 0.018*in): the bar width.'''),
+        spaceWidth = AttrMapValue(isNumber,'''(float or None, default 0.0275in): width of intercharacter gap.'''),
+        shortHeight = AttrMapValue(isNumber,'''(float, default 0.05in): The short bar height.'''),
+        barHeight = AttrMapValue(isNumber,'''(float, default 0.125in): The full bar height.'''),
+        fontName = AttrMapValue(isString, desc='human readable font'),
+        fontSize = AttrMapValue(isNumber, desc='human readable font size'),
+        humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
+        )
+    def __init__(self,**kw):
+        from rlextra.graphics.barcode.usps import POSTNET
+        _BarcodeWidget.__init__(self,POSTNET,"78247-1043",**kw)
+
+if __name__=='__main__':
+    import os, sys, glob
+    from reportlab.graphics.shapes import Drawing
+    os.chdir(os.path.dirname(sys.argv[0]))
+    if not os.path.isdir('out'):
+        os.mkdir('out')
+    map(os.remove,glob.glob(os.path.join('out','*')))
+    html = ['<html><head></head><body>']
+    a = html.append
+    for C in (BarcodeI2of5,
+            BarcodeCode128,
+            BarcodeStandard93,
+            BarcodeExtended93,
+            BarcodeStandard39,
+            BarcodeExtended39,
+            BarcodeMSI,
+            BarcodeCodabar,
+            BarcodeCode11,
+            BarcodeFIM,
+            BarcodePOSTNET,
+            ):
+        name = C.__name__
+        i = C()
+        D = Drawing(100,50)
+        D.add(i)
+        D.save(formats=['gif','pict'],outDir='out',fnRoot=name)
+        a('<h2>%s</h2><img src="%s.gif"><br>' % (name, name))
+    a('</body></html>')
+    open(os.path.join('out','index.html'),'w').write('\n'.join(html))