Code

Extensions. Barcode extension refactoring (see https://code.launchpad.net/~doctormo...
[inkscape.git] / share / extensions / Barcode / BaseEan.py
1 #
2 # Copyright (C) 2010 Martin Owens
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 #
18 """
19 Some basic common code shared between EAN and UCP generators.
20 """
22 from Base import Barcode
23 import sys
25 MAPPING = [
26     # Left side of barcode Family '0'
27     [ "0001101", "0011001", "0010011", "0111101", "0100011",
28       "0110001", "0101111", "0111011", "0110111", "0001011" ],
29     # Left side of barcode Family '1' and flipped to right side.
30     [ "0100111", "0110011", "0011011", "0100001", "0011101",
31       "0111001", "0000101", "0010001", "0001001", "0010111" ],
32 ]
33 # This chooses which of the two encodings above to use.
34 FAMILIES  = [ '000000', '001011', '001101', '001110', '010011',
35               '011001', '011100', '010101', '010110', '011010' ]
37 GUARD_BAR  = '202'
38 CENTER_BAR = '02020'
40 class EanBarcode(Barcode):
41     """Simple base class for all EAN type barcodes"""
42     length  = None
43     lengths = None
44     checks  = []
46     def intarray(self, number):
47         """Convert a string of digits into an array of ints"""
48         return [ int(i) for i in number ]
51     def encode_interleaved(self, family, number, fams=FAMILIES):
52         """Encode any side of the barcode, interleaved"""
53         result = []
54         encset = self.intarray(fams[family])
55         for i in range(len(number)):
56             thismap = MAPPING[encset[i]]
57             result.append( thismap[number[i]] )
58         return result
61     def encode_right(self, number):
62         """Encode the right side of the barcode, non-interleaved"""
63         result = []
64         for n in number:
65             # The right side is always the reverse of the left's family '1'
66             result.append( MAPPING[1][n][::-1] )
67         return result
70     def encode_left(self, number):
71         """Encode the left side of the barcode, non-interleaved"""
72         result = []
73         for n in number:
74             result.append( MAPPING[0][n] )
75         return result
78     def space(self, *spacing):
79         """Space out an array of numbers"""
80         result = ''
81         for space in spacing:
82             if isinstance(space, list):
83                 for i in space:
84                     result += str(i)
85             elif isinstance(space, int):
86                 result += ' ' * space
87         return result
90     def getLengths(self):
91         """Return a list of acceptable lengths"""
92         if self.length:
93             return [ self.length ]
94         return self.lengths[:]
97     def encode(self, code):
98         """Encode any EAN barcode"""
99         if not code.isdigit():
100             return self.error(code, 'Not a Number, must be digits 0-9 only')
101         lengths = self.getLengths() + self.checks
103         if len(code) not in lengths:
104             return self.error(code, 'Wrong size, must be %s digits' % 
105                 (', '.join(self.space(lengths))))
107         if self.checks:
108             if len(code) not in self.checks:
109                 code = self.appendChecksum(code)
110             elif not self.verifyChecksum(code):
111                 return self.error(code, 'Checksum failed, omit for new sum')
112         return self._encode(self.intarray(code))
115     def _encode(self, n):
116         raise NotImplementedError("_encode should be provided by parent EAN")
118     def enclose(self, left, right=[], guard=GUARD_BAR, center=CENTER_BAR):
119         """Standard Enclosure"""
120         parts = [ guard ] + left + [ center ] + right + [ guard ]
121         return ''.join( parts )
123     def getChecksum(self, number, magic=10):
124         """Generate a UPCA/EAN13/EAN8 Checksum"""
125         weight = [3,1] * len(number)
126         result = 0
127         # We need to work from left to right so reverse
128         number = number[::-1]
129         # checksum based on first digits.
130         for i in range(len(number)):
131            result += int(number[i]) * weight[i]
132         # Modulous result to a single digit checksum
133         checksum = magic - (result % magic)
134         if checksum < 0 or checksum >= magic:
135            return '0'
136         return str(checksum)
138     def appendChecksum(self, number):
139         """Apply the checksum to a short number"""
140         return number + self.getChecksum(number)
142     def verifyChecksum(self, number):
143         """Verify any checksum"""
144         return self.getChecksum(number[:-1]) == number[-1]