2587
|
1 |
#
|
|
2 |
# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
|
|
3 |
# All rights reserved.
|
|
4 |
#
|
|
5 |
# Redistribution and use in source and binary forms, with or without
|
|
6 |
# modification, are permitted provided that the following conditions
|
|
7 |
# are met:
|
|
8 |
# 1. Redistributions of source code must retain the above copyright
|
|
9 |
# notice, this list of conditions and the following disclaimer.
|
|
10 |
# 2. Redistributions in binary form must reproduce the above copyright
|
|
11 |
# notice, this list of conditions and the following disclaimer in the
|
|
12 |
# documentation and/or other materials provided with the distribution.
|
|
13 |
# 3. All advertising materials mentioning features or use of this software
|
|
14 |
# must display the following acknowledgement:
|
|
15 |
# This product includes software developed by Tyler C. Sarna.
|
|
16 |
# 4. Neither the name of the author nor the names of contributors
|
|
17 |
# may be used to endorse or promote products derived from this software
|
|
18 |
# without specific prior written permission.
|
|
19 |
#
|
|
20 |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
21 |
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22 |
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
23 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
|
24 |
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
25 |
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
26 |
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
27 |
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
28 |
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
29 |
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
30 |
# POSSIBILITY OF SUCH DAMAGE.
|
|
31 |
#
|
|
32 |
|
|
33 |
from reportlab.lib.units import inch
|
|
34 |
from common import MultiWidthBarcode
|
|
35 |
from string import digits
|
|
36 |
|
|
37 |
_patterns = {
|
|
38 |
0 : 'BaBbBb', 1 : 'BbBaBb', 2 : 'BbBbBa',
|
|
39 |
3 : 'AbAbBc', 4 : 'AbAcBb', 5 : 'AcAbBb',
|
|
40 |
6 : 'AbBbAc', 7 : 'AbBcAb', 8 : 'AcBbAb',
|
|
41 |
9 : 'BbAbAc', 10 : 'BbAcAb', 11 : 'BcAbAb',
|
|
42 |
12 : 'AaBbCb', 13 : 'AbBaCb', 14 : 'AbBbCa',
|
|
43 |
15 : 'AaCbBb', 16 : 'AbCaBb', 17 : 'AbCbBa',
|
|
44 |
18 : 'BbCbAa', 19 : 'BbAaCb', 20 : 'BbAbCa',
|
|
45 |
21 : 'BaCbAb', 22 : 'BbCaAb', 23 : 'CaBaCa',
|
|
46 |
24 : 'CaAbBb', 25 : 'CbAaBb', 26 : 'CbAbBa',
|
|
47 |
27 : 'CaBbAb', 28 : 'CbBaAb', 29 : 'CbBbAa',
|
|
48 |
30 : 'BaBaBc', 31 : 'BaBcBa', 32 : 'BcBaBa',
|
|
49 |
33 : 'AaAcBc', 34 : 'AcAaBc', 35 : 'AcAcBa',
|
|
50 |
36 : 'AaBcAc', 37 : 'AcBaAc', 38 : 'AcBcAa',
|
|
51 |
39 : 'BaAcAc', 40 : 'BcAaAc', 41 : 'BcAcAa',
|
|
52 |
42 : 'AaBaCc', 43 : 'AaBcCa', 44 : 'AcBaCa',
|
|
53 |
45 : 'AaCaBc', 46 : 'AaCcBa', 47 : 'AcCaBa',
|
|
54 |
48 : 'CaCaBa', 49 : 'BaAcCa', 50 : 'BcAaCa',
|
|
55 |
51 : 'BaCaAc', 52 : 'BaCcAa', 53 : 'BaCaCa',
|
|
56 |
54 : 'CaAaBc', 55 : 'CaAcBa', 56 : 'CcAaBa',
|
|
57 |
57 : 'CaBaAc', 58 : 'CaBcAa', 59 : 'CcBaAa',
|
|
58 |
60 : 'CaDaAa', 61 : 'BbAdAa', 62 : 'DcAaAa',
|
|
59 |
63 : 'AaAbBd', 64 : 'AaAdBb', 65 : 'AbAaBd',
|
|
60 |
66 : 'AbAdBa', 67 : 'AdAaBb', 68 : 'AdAbBa',
|
|
61 |
69 : 'AaBbAd', 70 : 'AaBdAb', 71 : 'AbBaAd',
|
|
62 |
72 : 'AbBdAa', 73 : 'AdBaAb', 74 : 'AdBbAa',
|
|
63 |
75 : 'BdAbAa', 76 : 'BbAaAd', 77 : 'DaCaAa',
|
|
64 |
78 : 'BdAaAb', 79 : 'AcDaAa', 80 : 'AaAbDb',
|
|
65 |
81 : 'AbAaDb', 82 : 'AbAbDa', 83 : 'AaDbAb',
|
|
66 |
84 : 'AbDaAb', 85 : 'AbDbAa', 86 : 'DaAbAb',
|
|
67 |
87 : 'DbAaAb', 88 : 'DbAbAa', 89 : 'BaBaDa',
|
|
68 |
90 : 'BaDaBa', 91 : 'DaBaBa', 92 : 'AaAaDc',
|
|
69 |
93 : 'AaAcDa', 94 : 'AcAaDa', 95 : 'AaDaAc',
|
|
70 |
96 : 'AaDcAa', 97 : 'DaAaAc', 98 : 'DaAcAa',
|
|
71 |
99 : 'AaCaDa', 100 : 'AaDaCa', 101 : 'CaAaDa',
|
|
72 |
102 : 'DaAaCa', 103 : 'BaAdAb', 104 : 'BaAbAd',
|
|
73 |
105 : 'BaAbCb', 106 : 'BcCaAaB'
|
|
74 |
}
|
|
75 |
|
|
76 |
starta, startb, startc, stop = 103, 104, 105, 106
|
|
77 |
|
|
78 |
seta = {
|
|
79 |
' ' : 0, '!' : 1, '"' : 2, '#' : 3,
|
|
80 |
'$' : 4, '%' : 5, '&' : 6, '\'' : 7,
|
|
81 |
'(' : 8, ')' : 9, '*' : 10, '+' : 11,
|
|
82 |
',' : 12, '-' : 13, '.' : 14, '/' : 15,
|
|
83 |
'0' : 16, '1' : 17, '2' : 18, '3' : 19,
|
|
84 |
'4' : 20, '5' : 21, '6' : 22, '7' : 23,
|
|
85 |
'8' : 24, '9' : 25, ':' : 26, ';' : 27,
|
|
86 |
'<' : 28, '=' : 29, '>' : 30, '?' : 31,
|
|
87 |
'@' : 32, 'A' : 33, 'B' : 34, 'C' : 35,
|
|
88 |
'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39,
|
|
89 |
'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43,
|
|
90 |
'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47,
|
|
91 |
'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51,
|
|
92 |
'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55,
|
|
93 |
'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59,
|
|
94 |
'\\' : 60, ']' : 61, '^' : 62, '_' : 63,
|
|
95 |
'\x00' : 64, '\x01' : 65, '\x02' : 66, '\x03' : 67,
|
|
96 |
'\x04' : 68, '\x05' : 69, '\x06' : 70, '\x07' : 71,
|
|
97 |
'\x08' : 72, '\x09' : 73, '\x0a' : 74, '\x0b' : 75,
|
|
98 |
'\x0c' : 76, '\x0d' : 77, '\x0e' : 78, '\x0f' : 79,
|
|
99 |
'\x10' : 80, '\x11' : 81, '\x12' : 82, '\x13' : 83,
|
|
100 |
'\x14' : 84, '\x15' : 85, '\x16' : 86, '\x17' : 87,
|
|
101 |
'\x18' : 88, '\x19' : 89, '\x1a' : 90, '\x1b' : 91,
|
|
102 |
'\x1c' : 92, '\x1d' : 93, '\x1e' : 94, '\x1f' : 95,
|
|
103 |
'\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99,
|
|
104 |
'TO_B' : 100, '\xf4' : 101, '\xf1' : 102
|
|
105 |
}
|
|
106 |
|
|
107 |
setb = {
|
|
108 |
' ' : 0, '!' : 1, '"' : 2, '#' : 3,
|
|
109 |
'$' : 4, '%' : 5, '&' : 6, '\'' : 7,
|
|
110 |
'(' : 8, ')' : 9, '*' : 10, '+' : 11,
|
|
111 |
',' : 12, '-' : 13, '.' : 14, '/' : 15,
|
|
112 |
'0' : 16, '1' : 17, '2' : 18, '3' : 19,
|
|
113 |
'4' : 20, '5' : 21, '6' : 22, '7' : 23,
|
|
114 |
'8' : 24, '9' : 25, ':' : 26, ';' : 27,
|
|
115 |
'<' : 28, '=' : 29, '>' : 30, '?' : 31,
|
|
116 |
'@' : 32, 'A' : 33, 'B' : 34, 'C' : 35,
|
|
117 |
'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39,
|
|
118 |
'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43,
|
|
119 |
'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47,
|
|
120 |
'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51,
|
|
121 |
'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55,
|
|
122 |
'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59,
|
|
123 |
'\\' : 60, ']' : 61, '^' : 62, '_' : 63,
|
|
124 |
'`' : 64, 'a' : 65, 'b' : 66, 'c' : 67,
|
|
125 |
'd' : 68, 'e' : 69, 'f' : 70, 'g' : 71,
|
|
126 |
'h' : 72, 'i' : 73, 'j' : 74, 'k' : 75,
|
|
127 |
'l' : 76, 'm' : 77, 'n' : 78, 'o' : 79,
|
|
128 |
'p' : 80, 'q' : 81, 'r' : 82, 's' : 83,
|
|
129 |
't' : 84, 'u' : 85, 'v' : 86, 'w' : 87,
|
|
130 |
'x' : 88, 'y' : 89, 'z' : 90, '{' : 91,
|
|
131 |
'|' : 92, '}' : 93, '~' : 94, '\x7f' : 95,
|
|
132 |
'\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99,
|
|
133 |
'\xf4' : 100, 'TO_A' : 101, '\xf1' : 102
|
|
134 |
}
|
|
135 |
|
|
136 |
setc = {
|
|
137 |
'00': 0, '01': 1, '02': 2, '03': 3, '04': 4,
|
|
138 |
'05': 5, '06': 6, '07': 7, '08': 8, '09': 9,
|
|
139 |
'10':10, '11':11, '12':12, '13':13, '14':14,
|
|
140 |
'15':15, '16':16, '17':17, '18':18, '19':19,
|
|
141 |
'20':20, '21':21, '22':22, '23':23, '24':24,
|
|
142 |
'25':25, '26':26, '27':27, '28':28, '29':29,
|
|
143 |
'30':30, '31':31, '32':32, '33':33, '34':34,
|
|
144 |
'35':35, '36':36, '37':37, '38':38, '39':39,
|
|
145 |
'40':40, '41':41, '42':42, '43':43, '44':44,
|
|
146 |
'45':45, '46':46, '47':47, '48':48, '49':49,
|
|
147 |
'50':50, '51':51, '52':52, '53':53, '54':54,
|
|
148 |
'55':55, '56':56, '57':57, '58':58, '59':59,
|
|
149 |
'60':60, '61':61, '62':62, '63':63, '64':64,
|
|
150 |
'65':65, '66':66, '67':67, '68':68, '69':69,
|
|
151 |
'70':70, '71':71, '72':72, '73':73, '74':74,
|
|
152 |
'75':75, '76':76, '77':77, '78':78, '79':79,
|
|
153 |
'80':80, '81':81, '82':82, '83':83, '84':84,
|
|
154 |
'85':85, '86':86, '87':87, '88':88, '89':89,
|
|
155 |
'90':90, '91':91, '92':92, '93':93, '94':94,
|
|
156 |
'95':95, '96':96, '97':97, '98':98, '99':99,
|
|
157 |
|
|
158 |
'TO_B' : 100, 'TO_A' : 101, '\xf1' : 102
|
|
159 |
}
|
|
160 |
|
|
161 |
setmap = {
|
|
162 |
'TO_A' : (seta, setb),
|
|
163 |
'TO_B' : (setb, seta),
|
|
164 |
'TO_C' : (setc, None),
|
|
165 |
'START_A' : (starta, seta, setb),
|
|
166 |
'START_B' : (startb, setb, seta),
|
|
167 |
'START_C' : (startc, setc, None),
|
|
168 |
}
|
|
169 |
tos = setmap.keys()
|
|
170 |
|
|
171 |
class Code128(MultiWidthBarcode):
|
|
172 |
"""
|
|
173 |
Code 128 is a very compact symbology that can encode the entire
|
|
174 |
128 character ASCII set, plus 4 special control codes,
|
|
175 |
(FNC1-FNC4, expressed in the input string as \xf1 to \xf4).
|
|
176 |
Code 128 can also encode digits at double density (2 per byte)
|
|
177 |
and has a mandatory checksum. Code 128 is well supported and
|
|
178 |
commonly used -- for example, by UPS for tracking labels.
|
|
179 |
|
|
180 |
Because of these qualities, Code 128 is probably the best choice
|
|
181 |
for a linear symbology today (assuming you have a choice).
|
|
182 |
|
|
183 |
Options that may be passed to constructor:
|
|
184 |
|
|
185 |
value (int, or numeric string. required.):
|
|
186 |
The value to encode.
|
|
187 |
|
|
188 |
barWidth (float, default .0075):
|
|
189 |
X-Dimension, or width of the smallest element
|
|
190 |
Minumum is .0075 inch (7.5 mils).
|
|
191 |
|
|
192 |
barHeight (float, see default below):
|
|
193 |
Height of the symbol. Default is the height of the two
|
|
194 |
bearer bars (if they exist) plus the greater of .25 inch
|
|
195 |
or .15 times the symbol's length.
|
|
196 |
|
|
197 |
quiet (bool, default 1):
|
|
198 |
Wether to include quiet zones in the symbol.
|
|
199 |
|
|
200 |
lquiet (float, see default below):
|
|
201 |
Quiet zone size to left of code, if quiet is true.
|
|
202 |
Default is the greater of .25 inch, or 10 barWidth
|
|
203 |
|
|
204 |
rquiet (float, defaults as above):
|
|
205 |
Quiet zone size to right left of code, if quiet is true.
|
|
206 |
|
|
207 |
Sources of Information on Code 128:
|
|
208 |
|
|
209 |
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_128.html
|
|
210 |
http://www.adams1.com/pub/russadam/128code.html
|
|
211 |
http://www.barcodeman.com/c128.html
|
|
212 |
|
|
213 |
Official Spec, "ANSI/AIM BC4-1999, ISS" is available for US$45 from
|
|
214 |
http://www.aimglobal.org/aimstore/
|
|
215 |
"""
|
|
216 |
barWidth = inch * 0.0075
|
|
217 |
lquiet = None
|
|
218 |
rquiet = None
|
|
219 |
quiet = 1
|
|
220 |
barHeight = None
|
|
221 |
def __init__(self, value='', **args):
|
|
222 |
|
|
223 |
if type(value) is type(1):
|
|
224 |
value = str(value)
|
|
225 |
|
|
226 |
for (k, v) in args.items():
|
|
227 |
setattr(self, k, v)
|
|
228 |
|
|
229 |
if self.quiet:
|
|
230 |
if self.lquiet is None:
|
|
231 |
self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
|
|
232 |
if self.rquiet is None:
|
|
233 |
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
|
234 |
else:
|
|
235 |
self.lquiet = self.rquiet = 0.0
|
|
236 |
|
|
237 |
MultiWidthBarcode.__init__(self, value)
|
|
238 |
|
|
239 |
def validate(self):
|
|
240 |
vval = ""
|
|
241 |
self.valid = 1
|
|
242 |
for c in self.value:
|
|
243 |
if ord(c) > 127 and c not in '\xf1\xf2\xf3\xf4':
|
|
244 |
self.valid = 0
|
|
245 |
continue
|
|
246 |
vval = vval + c
|
|
247 |
self.validated = vval
|
|
248 |
return vval
|
|
249 |
|
|
250 |
def _trailingDigitsToC(self, l):
|
|
251 |
# Optimization: trailing digits -> set C double-digits
|
|
252 |
c = 1
|
|
253 |
savings = -1 # the TO_C costs one character
|
|
254 |
rl = ['STOP']
|
|
255 |
while c < len(l):
|
|
256 |
i = (-c - 1)
|
|
257 |
if l[i] == '\xf1':
|
2660
|
258 |
c += 1
|
2587
|
259 |
rl.insert(0, '\xf1')
|
|
260 |
continue
|
|
261 |
elif len(l[i]) == 1 and l[i] in digits \
|
|
262 |
and len(l[i-1]) == 1 and l[i-1] in digits:
|
|
263 |
c += 2
|
|
264 |
savings += 1
|
|
265 |
rl.insert(0, l[i-1] + l[i])
|
|
266 |
continue
|
|
267 |
else:
|
|
268 |
break
|
|
269 |
if savings > 0:
|
|
270 |
return l[:-c] + ['TO_C'] + rl
|
|
271 |
else:
|
|
272 |
return l
|
|
273 |
|
|
274 |
def encode(self):
|
|
275 |
# First, encode using only B
|
|
276 |
s = self.validated
|
|
277 |
l = ['START_B']
|
|
278 |
for c in s:
|
|
279 |
if not setb.has_key(c):
|
|
280 |
l = l + ['TO_A', c, 'TO_B']
|
|
281 |
else:
|
|
282 |
l.append(c)
|
|
283 |
l.append('STOP')
|
|
284 |
|
|
285 |
l = self._trailingDigitsToC(l)
|
|
286 |
|
|
287 |
# Finally, replace START_X,TO_Y with START_Y
|
|
288 |
if l[1] in tos:
|
|
289 |
l[:2] = ['START_' + l[1][-1]]
|
|
290 |
|
|
291 |
# print `l`
|
|
292 |
|
|
293 |
# encode into numbers
|
|
294 |
start, set, shset = setmap[l[0]]
|
|
295 |
e = [start]
|
|
296 |
|
|
297 |
l = l[1:-1]
|
|
298 |
while l:
|
|
299 |
c = l[0]
|
|
300 |
if c == 'SHIFT':
|
|
301 |
e = e + [set[c], shset[l[1]]]
|
|
302 |
l = l[2:]
|
|
303 |
elif c in tos:
|
|
304 |
e.append(set[c])
|
|
305 |
set, shset = setmap[c]
|
|
306 |
l = l[1:]
|
|
307 |
else:
|
|
308 |
e.append(set[c])
|
|
309 |
l = l[1:]
|
|
310 |
|
|
311 |
c = e[0]
|
|
312 |
for i in range(1, len(e)):
|
|
313 |
c = c + i * e[i]
|
|
314 |
self.encoded = e + [c % 103, stop]
|
|
315 |
return self.encoded
|
|
316 |
|
|
317 |
def decompose(self):
|
|
318 |
self.decomposed = ''.join([_patterns[c] for c in self.encoded])
|
|
319 |
return self.decomposed
|
|
320 |
|
|
321 |
def _humanText(self):
|
|
322 |
return self.value
|