123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- #
- # Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
- # 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 reportlab.lib.utils import asNative
- from reportlab.graphics.barcode.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),
- }
- cStarts = ('START_B','TO_A','TO_B')
- tos = list(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.
-
- barWidth (float, default .0075):
- X-Dimension, or width of the smallest element
- Minumum is .0075 inch (7.5 mils).
-
- barHeight (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 barWidth
-
- 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/
- """
- barWidth = inch * 0.0075
- lquiet = None
- rquiet = None
- quiet = 1
- barHeight = None
- def __init__(self, value='', **args):
- value = str(value) if isinstance(value,int) else asNative(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.barWidth * 10.0)
- if self.rquiet is None:
- self.rquiet = max(inch * 0.25, self.barWidth * 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 _try_TO_C(self, l):
- '''Improved version of old _trailingDigitsToC(self, l) inspired by'''
- i = 0
- nl = []
- while i < len(l):
- startpos = i
- rl = []
- savings = -1 # the TO_C costs one character
- while i < len(l):
- if l[i] in cStarts:
- j = i
- break
- elif l[i] == '\xf1':
- rl.append(l[i])
- i += 1
- continue
- elif l[i] in digits \
- and l[i+1] in digits:
- rl.append(l[i] + l[i+1])
- i += 2
- savings += 1
- continue
- else:
- if l[i] in digits and l[i+1]=='STOP':
- rrl = []
- rsavings = -1 #we need a TO_C
- k = i
- while k>startpos:
- if l[k]=='\xf1':
- rrl.append(l[i])
- k -= 1
- elif l[k] in digits and l[k-1] in digits:
- rrl.append(l[k-1]+l[k])
- rsavings += 1
- k -= 2
- else:
- break
- rrl.reverse()
- if rsavings>savings+int(savings>=0 and (startpos and nl[-1] in cStarts))-1:
- nl += l[startpos]
- startpos += 1
- rl = rrl
- del rrl
- i += 1
- break
- ta = not (l[i]=='STOP' or j==i)
- xs = savings>=0 and (startpos and nl[-1] in cStarts)
- if savings+int(xs) > int(ta):
- if xs:
- toc = nl[-1][:-1]+'C'
- del nl[-1]
- else:
- toc = 'TO_C'
- nl += [toc]+rl
- if ta:
- nl.append('TO'+l[j][-2:])
- nl.append(l[i])
- else:
- nl += l[startpos:i+1]
- i += 1
- return nl
- def encode(self):
- # First, encode using only B
- s = self.validated
- l = ['START_B']
- for c in s:
- if c not in setb:
- l = l + ['TO_A', c, 'TO_B']
- else:
- l.append(c)
- l.append('STOP')
- l = self._try_TO_C(l)
- # Finally, replace START_X,TO_Y with START_Y
- if l[1] in tos:
- l[:2] = ['START_' + l[1][-1]]
- # print repr(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):
- self.decomposed = ''.join([_patterns[c] for c in self.encoded])
- return self.decomposed
- def _humanText(self):
- return self.value
- class Code128Auto(Code128):
- '''contributed by https://bitbucket.org/kylemacfarlane/
- see https://bitbucket.org/rptlab/reportlab/issues/69/implementations-of-code-128-auto-and-data
- '''
- def encode(self):
- s = self.validated
- current_set = None
- l = []
- value = list(s)
- while value:
- c = value.pop(0)
- if c in digits and value and value[0] in digits:
- c += value.pop(0)
- if c in setc:
- set_ = 'C'
- elif c in setb:
- set_ = 'B'
- else:
- set_ = 'A'
- if current_set != set_:
- if current_set:
- l.append('TO_' + set_)
- else:
- l.append('START_' + set_)
- current_set = set_
- l.append(c)
- l.append('STOP')
- 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
- if __name__=='__main__':
- def main():
- from reportlab.graphics.barcode.code128 import Code128
- from reportlab.platypus import Spacer, SimpleDocTemplate
- from reportlab.lib.units import inch, cm
- from reportlab.lib.styles import getSampleStyleSheet
- from reportlab.platypus.paragraph import Paragraph
- from reportlab.platypus.flowables import KeepTogether
- import os
- styles = getSampleStyleSheet()
- styleN = styles['Normal']
- styleH = styles['Heading1']
- story = []
- storyAdd = story.append
- for s in (
- 'BBBB123456BBB',
- 'BBBB12345BBB',
- 'BBBB1234BBB',
- 'BBBB123BBB',
- 'BBBB12BBB',
- 'BBBB1BBB',
- 'BBBB123456aa',
- 'BBBB1234aa',
- 'BBBB123aa',
- 'BBBB12aa',
- 'BBBB1aa',
- 'BBBB123456',
- 'BBBB12345',
- 'BBBB1234',
- 'BBBB123',
- 'BBBB12',
- 'BBBB1',
- '\xf11234B',
- 'Ba\xf11234B',
- 'Ba12',
- 'Ba123B',
- 'Ba1234B',
- 'BBBB1234567',
- 'BBBB1234567aa',
- ):
- storyAdd(KeepTogether([Paragraph('Code 128 %r' % s, styleN),Code128(s)]))
- storyAdd(Spacer(inch,inch))
- SimpleDocTemplate('code128-out.pdf').build(story)
- main()
|