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: