1
# -*- coding: utf-8 -*-
3
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
9
# 1. Redistributions of source code must retain the above copyright
10
# notice, this list of conditions and the following disclaimer.
11
# 2. Redistributions in binary form must reproduce the above copyright
12
# notice, this list of conditions and the following disclaimer in the
13
# documentation and/or other materials provided with the distribution.
14
# 3. All advertising materials mentioning features or use of this software
15
# must display the following acknowledgement:
16
# This product includes software developed by Tyler C. Sarna.
17
# 4. Neither the name of the author nor the names of contributors
18
# may be used to endorse or promote products derived from this software
19
# without specific prior written permission.
21
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
25
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
# POSSIBILITY OF SUCH DAMAGE.
34
from reportlab.platypus.flowables import Flowable
35
from reportlab.lib.units import inch
38
class Barcode(Flowable):
39
"""Abstract Base for barcodes. Includes implementations of
40
some methods suitable for the more primitive barcode types"""
42
def __init__(self, value = ''):
45
if not hasattr(self, 'gap'):
52
#print self.decomposed
57
self.validated = self.value
60
self.encoded = self.validated
63
self.decomposed = self.encoded
65
def computeSize(self, *args):
67
wx = xdim * self.ratio
74
for c in self.decomposed:
82
if self.height is None:
83
self.height = w * 0.15
84
self.height = max(0.25 * inch, self.height)
86
self.height = self.height + self.bearers * 2.0 * xdim
89
w = w + self.lquiet + self.rquiet
98
wx = xdim * self.ratio
101
b = self.bearers * xdim
103
tb = self.height - (b * 1.5)
105
for c in self.decomposed:
107
left = left + self.gap
113
self.rect(left, bb, xdim, tb)
116
self.rect(left, bb, wx, tb)
120
self.rect(self.lquiet, 0.0, \
121
self.width - (self.lquiet + self.rquiet), b)
122
self.rect(self.lquiet, self.height - b, \
123
self.width - (self.lquiet + self.rquiet), b)
125
def rect(self, x, y, w, h):
126
self.canv.rect(x, y, w, h, stroke=0, fill=1)
129
class MultiWidthBarcode(Barcode):
130
"""Base for variable-bar-width codes like Code93 and Code128"""
132
def computeSize(self, *args):
134
oa, oA = ord('a') - 1, ord('A') - 1
138
for c in self.decomposed:
140
if c in string.lowercase:
141
w = w + xdim * (oc - oa)
142
elif c in string.uppercase:
143
w = w + xdim * (oc - oA)
145
if self.height is None:
146
self.height = w * 0.15
147
self.height = max(0.25 * inch, self.height)
150
w = w + self.lquiet + self.rquiet
151
self.xo = self.lquiet
158
oa, oA = ord('a') - 1, ord('A') - 1
162
for c in self.decomposed:
164
if c in string.lowercase:
165
left = left + (oc - oa) * xdim
166
elif c in string.uppercase:
168
self.rect(left, 0.0, w, self.height)
172
class I2of5(Barcode):
174
Interleaved 2 of 5 is a numeric-only barcode. It encodes an even
175
number of digits; if an odd number is given, a 0 is prepended.
177
Options that may be passed to constructor:
179
value (int, or numeric string. required.):
182
xdim (float, default .0075):
183
X-Dimension, or width of the smallest element
184
Minumum is .0075 inch (7.5 mils).
186
ratio (float, default 2.2):
187
The ratio of wide elements to narrow elements.
188
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
189
xdim is greater than 20 mils (.02 inch))
191
gap (float or None, default None):
192
width of intercharacter gap. None means "use xdim".
194
height (float, see default below):
195
Height of the symbol. Default is the height of the two
196
bearer bars (if they exist) plus the greater of .25 inch
197
or .15 times the symbol's length.
199
checksum (bool, default 1):
200
Wether to compute and include the check digit
202
bearers (float, in units of xdim. default 3.0):
203
Height of bearer bars (horizontal bars along the top and
204
bottom of the barcode). Default is 3 x-dimensions.
205
Set to zero for no bearer bars. (Bearer bars help detect
206
misscans, so it is suggested to leave them on).
208
quiet (bool, default 1):
209
Wether to include quiet zones in the symbol.
211
lquiet (float, see default below):
212
Quiet zone size to left of code, if quiet is true.
213
Default is the greater of .25 inch, or .15 times the symbol's
216
rquiet (float, defaults as above):
217
Quiet zone size to right left of code, if quiet is true.
219
Sources of Information on Interleaved 2 of 5:
221
http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html
222
http://www.adams1.com/pub/russadam/i25code.html
224
Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from
225
http://www.aimglobal.org/aimstore/
232
'B0' : 'bbBBb', 'S0' : 'ssSSs',
233
'B1' : 'BbbbB', 'S1' : 'SsssS',
234
'B2' : 'bBbbB', 'S2' : 'sSssS',
235
'B3' : 'BBbbb', 'S3' : 'SSsss',
236
'B4' : 'bbBbB', 'S4' : 'ssSsS',
237
'B5' : 'BbBbb', 'S5' : 'SsSss',
238
'B6' : 'bBBbb', 'S6' : 'sSSss',
239
'B7' : 'bbbBB', 'S7' : 'sssSS',
240
'B8' : 'BbbBb', 'S8' : 'SssSs',
241
'B9' : 'bBbBb', 'S9' : 'sSsSs'
244
def __init__(self, value='', **args):
246
self.xdim = inch * 0.0075
251
self.lquiet = self.rquiet = None
253
if type(value) == type(1):
256
for (k, v) in args.items():
260
if self.lquiet is None:
261
self.lquiet = min(inch * 0.25, self.xdim * 10.0)
262
self.rquiet = min(inch * 0.25, self.xdim * 10.0)
264
self.lquiet = self.rquiet = 0.0
266
Barcode.__init__(self, value)
271
for c in string.strip(self.value):
272
if c not in string.digits:
276
self.validated = vval
282
# make sure result will be a multiple of 2 digits long,
284
if ((len(self.validated) % 2 == 0) and self.checksum) \
285
or ((len(self.validated) % 2 == 1) and not self.checksum):
299
d = 10 - (int(d) % 10)
305
dval = self.patterns['start']
307
for i in range(0, len(self.encoded), 2):
308
b = self.patterns['B' + self.encoded[i]]
309
s = self.patterns['S' + self.encoded[i+1]]
311
for i in range(0, len(b)):
312
dval = dval + b[i] + s[i]
314
self.decomposed = dval + self.patterns['stop']
315
return self.decomposed
321
MSI is a numeric-only barcode.
323
Options that may be passed to constructor:
325
value (int, or numeric string. required.):
328
xdim (float, default .0075):
329
X-Dimension, or width of the smallest element
331
ratio (float, default 2.2):
332
The ratio of wide elements to narrow elements.
334
gap (float or None, default None):
335
width of intercharacter gap. None means "use xdim".
337
height (float, see default below):
338
Height of the symbol. Default is the height of the two
339
bearer bars (if they exist) plus the greater of .25 inch
340
or .15 times the symbol's length.
342
checksum (bool, default 1):
343
Wether to compute and include the check digit
345
bearers (float, in units of xdim. default 0):
346
Height of bearer bars (horizontal bars along the top and
347
bottom of the barcode). Default is 0 (no bearers).
349
lquiet (float, see default below):
350
Quiet zone size to left of code, if quiet is true.
351
Default is the greater of .25 inch, or 10 xdims.
353
rquiet (float, defaults as above):
354
Quiet zone size to right left of code, if quiet is true.
356
Sources of Information on MSI Bar Code:
358
http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html
359
http://www.adams1.com/pub/russadam/plessy.html
363
'start' : 'Bs', 'stop' : 'bSb',
365
'0' : 'bSbSbSbS', '1' : 'bSbSbSBs',
366
'2' : 'bSbSBsbS', '3' : 'bSbSBsBs',
367
'4' : 'bSBsbSbS', '5' : 'bSBsbSBs',
368
'6' : 'bSBsBsbS', '7' : 'bSBsBsBs',
369
'8' : 'BsbSbSbS', '9' : 'BsbSbSBs'
372
def __init__(self, value="", **args):
374
self.xdim = inch * 0.0075
379
self.lquiet = self.rquiet = None
381
if type(value) == type(1):
384
for (k, v) in args.items():
388
if self.lquiet is None:
389
self.lquiet = max(inch * 0.25, self.xdim * 10.0)
390
self.rquiet = max(inch * 0.25, self.xdim * 10.0)
392
self.lquiet = self.rquiet = 0.0
394
Barcode.__init__(self, value)
399
for c in string.strip(self.value):
400
if c not in string.digits:
404
self.validated = vval
412
for i in range(1, len(s), 2):
418
for i in range(0, len(s), 2):
427
dval = self.patterns['start']
429
for c in self.encoded:
430
dval = dval + self.patterns[c]
432
self.decomposed = dval + self.patterns['stop']
433
return self.decomposed
437
class Codabar(Barcode):
439
Codabar is a numeric plus some puntuation ("-$:/.+") barcode
440
with four start/stop characters (A, B, C, and D).
442
Options that may be passed to constructor:
444
value (string. required.):
447
xdim (float, default .0065):
448
X-Dimension, or width of the smallest element
449
minimum is 6.5 mils (.0065 inch)
451
ratio (float, default 2.0):
452
The ratio of wide elements to narrow elements.
454
gap (float or None, default None):
455
width of intercharacter gap. None means "use xdim".
457
height (float, see default below):
458
Height of the symbol. Default is the height of the two
459
bearer bars (if they exist) plus the greater of .25 inch
460
or .15 times the symbol's length.
462
checksum (bool, default 0):
463
Wether to compute and include the check digit
465
bearers (float, in units of xdim. default 0):
466
Height of bearer bars (horizontal bars along the top and
467
bottom of the barcode). Default is 0 (no bearers).
469
quiet (bool, default 1):
470
Wether to include quiet zones in the symbol.
472
lquiet (float, see default below):
473
Quiet zone size to left of code, if quiet is true.
474
Default is the greater of .25 inch, or 10 xdim
476
rquiet (float, defaults as above):
477
Quiet zone size to right left of code, if quiet is true.
479
Sources of Information on Codabar
481
http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html
482
http://www.barcodeman.com/codabar.html
484
Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from
485
http://www.aimglobal.org/aimstore/
489
'0': 'bsbsbSB', '1': 'bsbsBSb', '2': 'bsbSbsB',
490
'3': 'BSbsbsb', '4': 'bsBsbSb', '5': 'BsbsbSb',
491
'6': 'bSbsbsB', '7': 'bSbsBsb', '8': 'bSBsbsb',
492
'9': 'BsbSbsb', '-': 'bsbSBsb', '$': 'bsBSbsb',
493
':': 'BsbsBsB', '/': 'BsBsbsB', '.': 'BsBsBsb',
494
'+': 'bsBsBsB', 'A': 'bsBSbSb', 'B': 'bSbSbsB',
495
'C': 'bsbSbSB', 'D': 'bsbSBSb'
499
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
500
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
501
'-' : 10, '$' : 11, ':' : 12, '/' : 13, '.' : 14,
502
'+' : 15, 'A' : 16, 'B' : 17, 'C' : 18, 'D' : 19
505
chars = string.digits + "-$:/.+"
507
def __init__(self, value='', **args):
509
self.xdim = inch * 0.0065
510
self.ratio = 2.0 # XXX ?
514
self.lquiet = self.rquiet = None
516
if type(value) == type(1):
519
for (k, v) in args.items():
523
if self.lquiet is None:
524
self.lquiet = min(inch * 0.25, self.xdim * 10.0)
525
self.rquiet = min(inch * 0.25, self.xdim * 10.0)
527
self.lquiet = self.rquiet = 0.0
529
Barcode.__init__(self, value)
534
s = string.strip(self.value)
535
for i in range(0, len(s)):
537
if c not in self.chars:
538
if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'):
543
if vval[0] not in 'ABCD':
545
if vval[-1] not in 'ABCD':
546
vval = vval + vval[0]
548
self.validated = vval
557
v = v + self.values[v]
559
s = s + self.chars[v]
565
for c in self.encoded:
566
dval = dval + self.patterns[c] + 'i'
567
self.decomposed = dval[:-1]
568
return self.decomposed
572
class Code11(Barcode):
574
Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus
575
dash ("-"). 11 characters total, hence the name.
577
value (int or string. required.):
580
xdim (float, default .0075):
581
X-Dimension, or width of the smallest element
583
ratio (float, default 2.2):
584
The ratio of wide elements to narrow elements.
586
gap (float or None, default None):
587
width of intercharacter gap. None means "use xdim".
589
height (float, see default below):
590
Height of the symbol. Default is the height of the two
591
bearer bars (if they exist) plus the greater of .25 inch
592
or .15 times the symbol's length.
594
checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
595
How many checksum digits to include. -1 ("auto") means
596
1 if the number of digits is 10 or less, else 2.
598
bearers (float, in units of xdim. default 0):
599
Height of bearer bars (horizontal bars along the top and
600
bottom of the barcode). Default is 0 (no bearers).
602
quiet (bool, default 1):
603
Wether to include quiet zones in the symbol.
605
lquiet (float, see default below):
606
Quiet zone size to left of code, if quiet is true.
607
Default is the greater of .25 inch, or 10 xdim
609
rquiet (float, defaults as above):
610
Quiet zone size to right left of code, if quiet is true.
612
Sources of Information on Code 11:
614
http://www.cwi.nl/people/dik/english/codes/barcodes.html
617
chars = string.digits + '-'
620
'0' : 'bsbsB', '1' : 'BsbsB', '2' : 'bSbsB',
621
'3' : 'BSbsb', '4' : 'bsBsB', '5' : 'BsBsb',
622
'6' : 'bSBsb', '7' : 'bsbSB', '8' : 'BsbSb',
623
'9' : 'Bsbsb', '-' : 'bsBsb', 'S' : 'bsBSb' # Start/Stop
627
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
628
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
632
def __init__(self, value='', **args):
634
self.xdim = inch * 0.0075
635
self.ratio = 2.2 # XXX ?
636
self.checksum = -1 # Auto
639
self.lquiet = self.rquiet = None
641
if type(value) == type(1):
644
for (k, v) in args.items():
648
if self.lquiet is None:
649
self.lquiet = min(inch * 0.25, self.xdim * 10.0)
650
self.rquiet = min(inch * 0.25, self.xdim * 10.0)
652
self.lquiet = self.rquiet = 0.0
654
Barcode.__init__(self, value)
659
s = string.strip(self.value)
660
for i in range(0, len(s)):
662
if c not in self.chars:
667
self.validated = vval
673
if self.checksum == -1:
679
if self.checksum > 0:
680
# compute first checksum
683
c = c + v * string.index(self.chars, s[-(i+1)])
687
s = s + self.chars[c % 11]
689
if self.checksum > 1:
690
# compute second checksum
693
c = c + v * string.index(self.chars, s[-(i+1)])
697
s = s + self.chars[c % 10]
699
self.encoded = 'S' + s + 'S'
703
for c in self.encoded:
704
dval = dval + self.patterns[c] + 'i'
705
self.decomposed = dval[:-1]
706
return self.decomposed
707
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: