From d60676539b2001c4dd2021a87f1086a7012a3dde Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Oct 2007 06:17:00 +0000 Subject: [PATCH] Barcode extension of reportlab bzr revid: fp@tinyerp.com-b01bb6f0fe82521d3492a38e8215bdc3285d4442 --- bin/reportlab/extensions/barcode/__init__.py | 33 + bin/reportlab/extensions/barcode/code128.py | 321 ++++++++ bin/reportlab/extensions/barcode/code39.py | 255 +++++++ bin/reportlab/extensions/barcode/code93.py | 232 ++++++ bin/reportlab/extensions/barcode/common.py | 705 ++++++++++++++++++ bin/reportlab/extensions/barcode/fourstate.py | 81 ++ bin/reportlab/extensions/barcode/out.pdf | Bin 0 -> 7359 bytes bin/reportlab/extensions/barcode/test.py | 55 ++ bin/reportlab/extensions/barcode/usps.py | 231 ++++++ doc/tests/check_profile_l10n_all.py | 10 +- 10 files changed, 1918 insertions(+), 5 deletions(-) create mode 100644 bin/reportlab/extensions/barcode/__init__.py create mode 100644 bin/reportlab/extensions/barcode/code128.py create mode 100644 bin/reportlab/extensions/barcode/code39.py create mode 100644 bin/reportlab/extensions/barcode/code93.py create mode 100644 bin/reportlab/extensions/barcode/common.py create mode 100644 bin/reportlab/extensions/barcode/fourstate.py create mode 100644 bin/reportlab/extensions/barcode/out.pdf create mode 100644 bin/reportlab/extensions/barcode/test.py create mode 100644 bin/reportlab/extensions/barcode/usps.py diff --git a/bin/reportlab/extensions/barcode/__init__.py b/bin/reportlab/extensions/barcode/__init__.py new file mode 100644 index 00000000000..a96948744f1 --- /dev/null +++ b/bin/reportlab/extensions/barcode/__init__.py @@ -0,0 +1,33 @@ +# +# Copyright (c) 1996-2000 Tyler C. Sarna +# 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' diff --git a/bin/reportlab/extensions/barcode/code128.py b/bin/reportlab/extensions/barcode/code128.py new file mode 100644 index 00000000000..a69834c1ebc --- /dev/null +++ b/bin/reportlab/extensions/barcode/code128.py @@ -0,0 +1,321 @@ +# +# Copyright (c) 2000 Tyler C. Sarna +# 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. + + xdim (float, default .0075): + X-Dimension, or width of the smallest element + Minumum is .0075 inch (7.5 mils). + + height (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 xdim + + 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/ + """ + def __init__(self, value='', **args): + self.xdim = inch * 0.0275 + self.lquiet = None + self.rquiet = None + self.quiet = 1 + self.height = None + + 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.xdim * 10.0) + self.rquiet = max(inch * 0.25, self.xdim * 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 = c + 2 + savings = 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): + dval = '' + for c in self.encoded: + dval = dval + _patterns[c] + self.decomposed = dval + return self.decomposed diff --git a/bin/reportlab/extensions/barcode/code39.py b/bin/reportlab/extensions/barcode/code39.py new file mode 100644 index 00000000000..08e0c9d4b5d --- /dev/null +++ b/bin/reportlab/extensions/barcode/code39.py @@ -0,0 +1,255 @@ +# +# Copyright (c) 1996-2000 Tyler C. Sarna +# 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(str, cksum): + newval = "*" + v = 0 + for c in str: + v = v + _patterns[c][1] + newval = newval + c + v = v % 43 + if cksum: + newval = newval + _valchars[v] + return newval + '*' + + +class _Code39Base(Barcode): + def __init__(self, value = "", **args): + self.xdim = inch * 0.0075 + self.lquiet = None + self.rquiet = None + self.quiet = 1 + self.gap = None + self.height = None + self.ratio = 2.2 + self.checksum = 0 + self.bearers = 0.0 + + 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.xdim * 10.0) + self.rquiet = max(inch * 0.25, self.xdim * 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 + + +class Standard39(_Code39Base): + """ + 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. + + xdim (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 + xdim is greater than 20 mils (.02 inch)) + + gap (float or None, default None): + width of intercharacter gap. None means "use xdim". + + height (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): + Wether to compute and include the check digit + + bearers (float, in units of xdim. 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. + + 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) + 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) + return self.encoded diff --git a/bin/reportlab/extensions/barcode/code93.py b/bin/reportlab/extensions/barcode/code93.py new file mode 100644 index 00000000000..fc19ee3ee98 --- /dev/null +++ b/bin/reportlab/extensions/barcode/code93.py @@ -0,0 +1,232 @@ +# +# Copyright (c) 2000 Tyler C. Sarna +# 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): + def __init__(self, value='', **args): + self.xdim = inch * 0.0075 + self.lquiet = None + self.rquiet = None + self.quiet = 1 + self.height = None + + 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.xdim * 10.0) + self.rquiet = max(inch * 0.25, self.xdim * 10.0) + else: + self.lquiet = self.rquiet = 0.0 + + MultiWidthBarcode.__init__(self, value) + + def decompose(self): + dval = _patterns['start'][0] + for c in self.encoded: + dval = dval + _patterns[c][0] + self.decomposed = dval + _patterns['stop'][0] + 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. + + xdim (float, default .0075): + X-Dimension, or width of the smallest element + Minumum is .0075 inch (7.5 mils). + + height (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 xdim + + rquiet (float, defaults as above): + Quiet zone size to right left of code, if quiet is true. + + 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 + for c in self.value: + if not _patterns.has_key(c) and not _extended.has_key(c): + self.valid = 0 + continue + vval = vval + c + self.validated = vval + return vval + + 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 diff --git a/bin/reportlab/extensions/barcode/common.py b/bin/reportlab/extensions/barcode/common.py new file mode 100644 index 00000000000..a73ed7d73f5 --- /dev/null +++ b/bin/reportlab/extensions/barcode/common.py @@ -0,0 +1,705 @@ +# +# Copyright (c) 1996-2000 Tyler C. Sarna +# 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""" + + def __init__(self, value = ''): + self.value = value + + if not hasattr(self, 'gap'): + self.gap = None + + self.validate() + self.encode() + #print self.encoded + self.decompose() + #print self.decomposed + 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): + xdim = self.xdim + wx = xdim * self.ratio + + if self.gap == None: + self.gap = xdim + + w = 0.0 + + for c in self.decomposed: + if c in 'sb': + w = w + xdim + elif c in 'SB': + w = w + wx + else: # 'i' + w = w + self.gap + + if self.height is None: + self.height = w * 0.15 + self.height = max(0.25 * inch, self.height) + if self.bearers: + self.height = self.height + self.bearers * 2.0 * xdim + + if self.quiet: + w = w + self.lquiet + self.rquiet + self.xo = self.lquiet + else: + self.xo = 0.0 + + self.width = w + + def draw(self): + xdim = self.xdim + wx = xdim * self.ratio + + left = self.xo + b = self.bearers * xdim + bb = b * 0.5 + tb = self.height - (b * 1.5) + + for c in self.decomposed: + if c == 'i': + left = left + self.gap + elif c == 's': + left = left + xdim + elif c == 'S': + left = left + wx + elif c == 'b': + self.rect(left, bb, xdim, tb) + left = left + xdim + elif c == 'B': + self.rect(left, bb, wx, tb) + left = left + wx + + if self.bearers: + self.rect(self.lquiet, 0.0, \ + self.width - (self.lquiet + self.rquiet), b) + self.rect(self.lquiet, self.height - b, \ + self.width - (self.lquiet + self.rquiet), b) + + def rect(self, x, y, w, h): + self.canv.rect(x, y, w, h, stroke=0, fill=1) + + +class MultiWidthBarcode(Barcode): + """Base for variable-bar-width codes like Code93 and Code128""" + + def computeSize(self, *args): + xdim = self.xdim + 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 + xdim * (oc - oa) + elif c in string.uppercase: + w = w + xdim * (oc - oA) + + if self.height is None: + self.height = w * 0.15 + self.height = max(0.25 * inch, self.height) + + if self.quiet: + w = w + self.lquiet + self.rquiet + self.xo = self.lquiet + else: + self.xo = 0.0 + + self.width = w + + def draw(self): + oa, oA = ord('a') - 1, ord('A') - 1 + xdim = self.xdim + left = self.xo + + for c in self.decomposed: + oc = ord(c) + if c in string.lowercase: + left = left + (oc - oa) * xdim + elif c in string.uppercase: + w = (oc - oA) * xdim + self.rect(left, 0.0, w, self.height) + left = left + w + + +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. + + xdim (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 + xdim is greater than 20 mils (.02 inch)) + + gap (float or None, default None): + width of intercharacter gap. None means "use xdim". + + height (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 xdim. 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): + 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. + + 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' + } + + def __init__(self, value='', **args): + self.height = None + self.xdim = inch * 0.0075 + self.ratio = 2.2 + self.checksum = 1 + self.bearers = 3.0 + self.quiet = 1 + self.lquiet = self.rquiet = None + + 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.xdim * 10.0) + self.rquiet = min(inch * 0.25, self.xdim * 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.patterns['start'] + + for i in range(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)): + dval = dval + b[i] + s[i] + + self.decomposed = dval + self.patterns['stop'] + 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. + + xdim (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 xdim". + + height (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 xdim. 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 xdims. + + rquiet (float, defaults as above): + Quiet zone size to right left of code, if quiet is true. + + 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' + } + + def __init__(self, value="", **args): + self.height = None + self.xdim = inch * 0.0075 + self.ratio = 2.2 + self.checksum = 1 + self.bearers = 0.0 + self.quiet = 1 + self.lquiet = self.rquiet = None + + 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.xdim * 10.0) + self.rquiet = max(inch * 0.25, self.xdim * 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.patterns['start'] + + for c in self.encoded: + dval = dval + self.patterns[c] + + self.decomposed = dval + self.patterns['stop'] + 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. + + xdim (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 xdim". + + height (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): + Wether to compute and include the check digit + + bearers (float, in units of xdim. 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 xdim + + 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 + "-$:/.+" + + def __init__(self, value='', **args): + self.height = None + self.xdim = inch * 0.0065 + self.ratio = 2.0 # XXX ? + self.checksum = 0 + self.bearers = 0.0 + self.quiet = 1 + self.lquiet = self.rquiet = None + + 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.xdim * 10.0) + self.rquiet = min(inch * 0.25, self.xdim * 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 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 = 0 + for c in s: + v = v + self.values[v] + v = 16 - (v % 16) + s = s + self.chars[v] + + self.encoded = s + + def decompose(self): + dval = "" + for c in self.encoded: + dval = dval + self.patterns[c] + 'i' + 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. + + xdim (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 xdim". + + height (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 xdim. 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 xdim + + 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, + } + + def __init__(self, value='', **args): + self.height = None + self.xdim = inch * 0.0075 + self.ratio = 2.2 # XXX ? + self.checksum = -1 # Auto + self.bearers = 0.0 + self.quiet = 1 + self.lquiet = self.rquiet = None + + 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.xdim * 10.0) + self.rquiet = min(inch * 0.25, self.xdim * 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 = 'S' + s + 'S' + + def decompose(self): + dval = "" + for c in self.encoded: + dval = dval + self.patterns[c] + 'i' + self.decomposed = dval[:-1] + return self.decomposed diff --git a/bin/reportlab/extensions/barcode/fourstate.py b/bin/reportlab/extensions/barcode/fourstate.py new file mode 100644 index 00000000000..0751fba5c92 --- /dev/null +++ b/bin/reportlab/extensions/barcode/fourstate.py @@ -0,0 +1,81 @@ +# +# Copyright (c) 2000 Tyler C. Sarna +# 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/ diff --git a/bin/reportlab/extensions/barcode/out.pdf b/bin/reportlab/extensions/barcode/out.pdf new file mode 100644 index 0000000000000000000000000000000000000000..52fafaae499d8b1830e02197cf98444f41cd4034 GIT binary patch literal 7359 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 +# 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 + + 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 (single character string from the set A - D. required.): + The value to encode. + + quiet (bool, default 1): + Wether 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: + + height (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 + """ + + def __init__(self, value='', **args): + self.barwidth = inch * (1.0/32.0) + self.barspace = inch * (1.0/16.0) + self.height = inch * (5.0/8.0) + self.rquiet = inch * (0.25) + self.lquiet = inch * (15.0/32.0) + self.quiet = 0 + + 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.barspace + self.barwidth + if self.quiet: + self.xo = self.lquiet + self.width = self.lquiet + self.width + self.rquiet + else: + self.xo = 0.0 + + def draw(self): + left = self.xo + for c in self.decomposed: + if c == '|': + self.rect(left, 0.0, self.barwidth, self.height) + left = left + self.barspace + + +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 + """ + + def __init__(self, value='', **args): + self.sbarheight = inch * 0.050 + self.fbarheight = inch * 0.125 + self.barwide = inch * 0.018 + self.spacewide = inch * 0.0275 + + 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.barwide + self.width = self.width + (len(self.decomposed) - 1) * self.spacewide + self.height = self.fbarheight + self.xo = 0.0 + + def draw(self): + sdown = self.fbarheight - self.sbarheight + left = self.xo + + for c in self.decomposed: + if c == '.': + h = self.sbarheight + else: + h = self.fbarheight + self.rect(left, 0.0, self.barwide, h) + left = left + self.barwide + self.spacewide diff --git a/doc/tests/check_profile_l10n_all.py b/doc/tests/check_profile_l10n_all.py index ec01bb035c9..d7dd28c15e2 100755 --- a/doc/tests/check_profile_l10n_all.py +++ b/doc/tests/check_profile_l10n_all.py @@ -40,14 +40,14 @@ import base64 url = 'http://localhost:8069/xmlrpc' profiles = [ 'profile_accounting', - 'profile_manufacturing', - 'profile_service' + 'profile_service', + 'profile_manufacturing' ] l10n_charts = [ - 'l10n_be', - 'l10n_fr', 'l10n_chart_uk_minimal', - False + False, + 'l10n_be', + 'l10n_fr' ] dbname = 'test' admin_passwd = 'admin'