mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-19 22:42:17 +00:00
Added printing requirements
This commit is contained in:
59
reportlab/graphics/barcode/README
Normal file
59
reportlab/graphics/barcode/README
Normal file
@@ -0,0 +1,59 @@
|
||||
Symbologies Currently Supported
|
||||
===============================
|
||||
|
||||
The following have, at a minimum, been verified to scan with a WASP
|
||||
CCD barcode scanner (found one bug in my code, two in the scanner!).
|
||||
Some have had more extensive testing:
|
||||
|
||||
Interleaved 2 of 5
|
||||
MSI
|
||||
Codabar
|
||||
Code 39 (Standard Character Set)
|
||||
Code 39 (Extended Character Set)
|
||||
Code 93 (Standard Character Set)
|
||||
Code 93 (Extended Character Set)
|
||||
Code 128 (Automatic use of A, B, C, with some optimizations --
|
||||
more coming)
|
||||
|
||||
The following have been tested by sending a fair number of mailpieces
|
||||
with them:
|
||||
|
||||
USPS FIM
|
||||
USPS POSTNET
|
||||
|
||||
The following have not been tested, as none of the scanners I have
|
||||
access to support them:
|
||||
|
||||
Code 11
|
||||
|
||||
|
||||
Future Plans, Consulting
|
||||
========================
|
||||
|
||||
Soon:
|
||||
|
||||
I plan to implement the following linear codes soon:
|
||||
|
||||
UPC/EAN(/JAN)
|
||||
|
||||
The following are in progress, but I lack a way to verify them
|
||||
(scanners I have access to don't read them), and I don't have complete
|
||||
specs for the UK style.
|
||||
|
||||
Royal Mail 4-State (UK/NL/etc style, and Australian style)
|
||||
|
||||
Down the road, I'd like to do some 2D symbologies. Likely first candidate
|
||||
is PDF417. MaxiCode, Aztec Code, and some of the stacked symbologies are
|
||||
also good candidates.
|
||||
|
||||
I am available to do implementation of additional symbologies for hire.
|
||||
Because I enjoy hacking barcodes, my rates for work in this particular
|
||||
area are very low and are mainly to help offset costs associated with
|
||||
obtaining related documents and/or to buy or gain access to scanning
|
||||
equipment for symbologies if I don't already have a scanner that
|
||||
supports them. Loans of equipment are also accepted.
|
||||
|
||||
For more information, contact:
|
||||
|
||||
Ty Sarna
|
||||
tsarna@sarna.org
|
||||
24
reportlab/graphics/barcode/TODO
Normal file
24
reportlab/graphics/barcode/TODO
Normal file
@@ -0,0 +1,24 @@
|
||||
See also README for some plans and info on consulting.
|
||||
|
||||
- Overall framework docs
|
||||
|
||||
- Finish Aussie Rules 4-State, for which I have complete docs now (yay
|
||||
USPS and aupost.com.au for putting specs online. Too bad UKPost doesn't.)
|
||||
|
||||
- Investigate USPS PLANET stuff
|
||||
|
||||
- Higher-level objects that handle barcoded address blocks with correct
|
||||
spacings and such (US, AU, UK/etc?)
|
||||
|
||||
- Even higher-level objects that represent mailpieces and place the
|
||||
above-style address block objects, FIM codes, "place stamp here" blocks,
|
||||
etc, correctly?
|
||||
|
||||
- Framework for laying out labels on various styles of n-up label
|
||||
sheets, like Avery labels, etc?
|
||||
|
||||
- Decide if Plessey is worth doing. MSI-like (MSI is actually derived from
|
||||
it), but specs were never formalized. Probably only useful for legacy
|
||||
applications. If you need it, mail me.
|
||||
|
||||
- Get someone to test Code 11, or find a scanner that handles it
|
||||
1
reportlab/graphics/barcode/VERSION
Normal file
1
reportlab/graphics/barcode/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
0.9
|
||||
136
reportlab/graphics/barcode/__init__.py
Normal file
136
reportlab/graphics/barcode/__init__.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#
|
||||
# Copyright (c) 1996-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.
|
||||
#
|
||||
|
||||
__version__ = '0.9'
|
||||
__doc__='''Popular barcodes available as reusable widgets'''
|
||||
|
||||
def getCodes():
|
||||
"""Returns a dict mapping code names to widgets"""
|
||||
|
||||
from reportlab.graphics.barcode.widgets import BarcodeI2of5, BarcodeCode128, BarcodeStandard93,\
|
||||
BarcodeExtended93, BarcodeStandard39, BarcodeExtended39,\
|
||||
BarcodeMSI, BarcodeCodabar, BarcodeCode11, BarcodeFIM,\
|
||||
BarcodePOSTNET, BarcodeUSPS_4State
|
||||
|
||||
#newer codes will typically get their own module
|
||||
from reportlab.graphics.barcode.eanbc import Ean13BarcodeWidget, Ean8BarcodeWidget, UPCA
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
|
||||
|
||||
#the module exports a dictionary of names to widgets, to make it easy for
|
||||
#apps and doc tools to display information about them.
|
||||
codes = {}
|
||||
for widget in (
|
||||
BarcodeI2of5,
|
||||
BarcodeCode128,
|
||||
BarcodeStandard93,
|
||||
BarcodeExtended93,
|
||||
BarcodeStandard39,
|
||||
BarcodeExtended39,
|
||||
BarcodeMSI,
|
||||
BarcodeCodabar,
|
||||
BarcodeCode11,
|
||||
BarcodeFIM,
|
||||
BarcodePOSTNET,
|
||||
BarcodeUSPS_4State,
|
||||
Ean13BarcodeWidget,
|
||||
Ean8BarcodeWidget,
|
||||
UPCA,
|
||||
QrCodeWidget,
|
||||
):
|
||||
codeName = widget.codeName
|
||||
codes[codeName] = widget
|
||||
|
||||
return codes
|
||||
|
||||
def getCodeNames():
|
||||
"""Returns sorted list of supported bar code names"""
|
||||
return sorted(getCodes().keys())
|
||||
|
||||
def createBarcodeDrawing(codeName, **options):
|
||||
"""This creates and returns a drawing with a barcode.
|
||||
"""
|
||||
from reportlab.graphics.shapes import Drawing, Group
|
||||
|
||||
codes = getCodes()
|
||||
bcc = codes[codeName]
|
||||
width = options.pop('width',None)
|
||||
height = options.pop('height',None)
|
||||
isoScale = options.pop('isoScale',0)
|
||||
kw = {}
|
||||
for k,v in options.items():
|
||||
if k.startswith('_') or k in bcc._attrMap: kw[k] = v
|
||||
bc = bcc(**kw)
|
||||
|
||||
|
||||
#Robin's new ones validate when setting the value property.
|
||||
#Ty Sarna's old ones do not. We need to test.
|
||||
if hasattr(bc, 'validate'):
|
||||
bc.validate() #raise exception if bad value
|
||||
if not bc.valid:
|
||||
raise ValueError("Illegal barcode with value '%s' in code '%s'" % (options.get('value',None), codeName))
|
||||
|
||||
#size it after setting the data
|
||||
x1, y1, x2, y2 = bc.getBounds()
|
||||
w = float(x2 - x1)
|
||||
h = float(y2 - y1)
|
||||
sx = width not in ('auto',None)
|
||||
sy = height not in ('auto',None)
|
||||
if sx or sy:
|
||||
sx = sx and width/w or 1.0
|
||||
sy = sy and height/h or 1.0
|
||||
if isoScale:
|
||||
if sx<1.0 and sy<1.0:
|
||||
sx = sy = max(sx,sy)
|
||||
else:
|
||||
sx = sy = min(sx,sy)
|
||||
|
||||
w *= sx
|
||||
h *= sy
|
||||
else:
|
||||
sx = sy = 1
|
||||
|
||||
#bc.x = -sx*x1
|
||||
#bc.y = -sy*y1
|
||||
d = Drawing(width=w,height=h,transform=[sx,0,0,sy,-sx*x1,-sy*y1])
|
||||
d.add(bc, "_bc")
|
||||
return d
|
||||
|
||||
def createBarcodeImageInMemory(codeName,**options):
|
||||
"""This creates and returns barcode as an image in memory.
|
||||
Takes same arguments as createBarcodeDrawing and also an
|
||||
optional format keyword which can be anything acceptable
|
||||
to Drawing.asString eg gif, pdf, tiff, py ......
|
||||
"""
|
||||
format = options.pop('format','png')
|
||||
d = createBarcodeDrawing(codeName, **options)
|
||||
return d.asString(format)
|
||||
321
reportlab/graphics/barcode/code128.py
Normal file
321
reportlab/graphics/barcode/code128.py
Normal file
@@ -0,0 +1,321 @@
|
||||
#
|
||||
# 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),
|
||||
}
|
||||
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 _trailingDigitsToC(self, l):
|
||||
# Optimization: trailing digits -> set C double-digits
|
||||
c = 1
|
||||
savings = -1 # the TO_C costs one character
|
||||
rl = ['STOP']
|
||||
while c < len(l):
|
||||
i = (-c - 1)
|
||||
if l[i] == '\xf1':
|
||||
c += 1
|
||||
rl.insert(0, '\xf1')
|
||||
continue
|
||||
elif len(l[i]) == 1 and l[i] in digits \
|
||||
and len(l[i-1]) == 1 and l[i-1] in digits:
|
||||
c += 2
|
||||
savings += 1
|
||||
rl.insert(0, l[i-1] + l[i])
|
||||
continue
|
||||
else:
|
||||
break
|
||||
if savings > 0:
|
||||
return l[:-c] + ['TO_C'] + rl
|
||||
else:
|
||||
return l
|
||||
|
||||
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._trailingDigitsToC(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
|
||||
245
reportlab/graphics/barcode/code39.py
Normal file
245
reportlab/graphics/barcode/code39.py
Normal file
@@ -0,0 +1,245 @@
|
||||
#
|
||||
# Copyright (c) 1996-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 Barcode
|
||||
from string import digits as string_digits
|
||||
|
||||
_patterns = {
|
||||
'0': ("bsbSBsBsb", 0), '1': ("BsbSbsbsB", 1),
|
||||
'2': ("bsBSbsbsB", 2), '3': ("BsBSbsbsb", 3),
|
||||
'4': ("bsbSBsbsB", 4), '5': ("BsbSBsbsb", 5),
|
||||
'6': ("bsBSBsbsb", 6), '7': ("bsbSbsBsB", 7),
|
||||
'8': ("BsbSbsBsb", 8), '9': ("bsBSbsBsb", 9),
|
||||
'A': ("BsbsbSbsB", 10), 'B': ("bsBsbSbsB", 11),
|
||||
'C': ("BsBsbSbsb", 12), 'D': ("bsbsBSbsB", 13),
|
||||
'E': ("BsbsBSbsb", 14), 'F': ("bsBsBSbsb", 15),
|
||||
'G': ("bsbsbSBsB", 16), 'H': ("BsbsbSBsb", 17),
|
||||
'I': ("bsBsbSBsb", 18), 'J': ("bsbsBSBsb", 19),
|
||||
'K': ("BsbsbsbSB", 20), 'L': ("bsBsbsbSB", 21),
|
||||
'M': ("BsBsbsbSb", 22), 'N': ("bsbsBsbSB", 23),
|
||||
'O': ("BsbsBsbSb", 24), 'P': ("bsBsBsbSb", 25),
|
||||
'Q': ("bsbsbsBSB", 26), 'R': ("BsbsbsBSb", 27),
|
||||
'S': ("bsBsbsBSb", 28), 'T': ("bsbsBsBSb", 29),
|
||||
'U': ("BSbsbsbsB", 30), 'V': ("bSBsbsbsB", 31),
|
||||
'W': ("BSBsbsbsb", 32), 'X': ("bSbsBsbsB", 33),
|
||||
'Y': ("BSbsBsbsb", 34), 'Z': ("bSBsBsbsb", 35),
|
||||
'-': ("bSbsbsBsB", 36), '.': ("BSbsbsBsb", 37),
|
||||
' ': ("bSBsbsBsb", 38), '*': ("bSbsBsBsb", None),
|
||||
'$': ("bSbSbSbsb", 39), '/': ("bSbSbsbSb", 40),
|
||||
'+': ("bSbsbSbSb", 41), '%': ("bsbSbSbSb", 42)
|
||||
}
|
||||
|
||||
from reportlab.lib.utils import ascii_uppercase, ascii_lowercase
|
||||
_stdchrs = string_digits + ascii_uppercase + "-. $/+%"
|
||||
|
||||
_extended = {
|
||||
'\0': "%U", '\01': "$A", '\02': "$B", '\03': "$C",
|
||||
'\04': "$D", '\05': "$E", '\06': "$F", '\07': "$G",
|
||||
'\010': "$H", '\011': "$I", '\012': "$J", '\013': "$K",
|
||||
'\014': "$L", '\015': "$M", '\016': "$N", '\017': "$O",
|
||||
'\020': "$P", '\021': "$Q", '\022': "$R", '\023': "$S",
|
||||
'\024': "$T", '\025': "$U", '\026': "$V", '\027': "$W",
|
||||
'\030': "$X", '\031': "$Y", '\032': "$Z", '\033': "%A",
|
||||
'\034': "%B", '\035': "%C", '\036': "%D", '\037': "%E",
|
||||
'!': "/A", '"': "/B", '#': "/C", '$': "/D",
|
||||
'%': "/E", '&': "/F", '\'': "/G", '(': "/H",
|
||||
')': "/I", '*': "/J", '+': "/K", ',': "/L",
|
||||
'/': "/O", ':': "/Z", ';': "%F", '<': "%G",
|
||||
'=': "%H", '>': "%I", '?': "%J", '@': "%V",
|
||||
'[': "%K", '\\': "%L", ']': "%M", '^': "%N",
|
||||
'_': "%O", '`': "%W", 'a': "+A", 'b': "+B",
|
||||
'c': "+C", 'd': "+D", 'e': "+E", 'f': "+F",
|
||||
'g': "+G", 'h': "+H", 'i': "+I", 'j': "+J",
|
||||
'k': "+K", 'l': "+L", 'm': "+M", 'n': "+N",
|
||||
'o': "+O", 'p': "+P", 'q': "+Q", 'r': "+R",
|
||||
's': "+S", 't': "+T", 'u': "+U", 'v': "+V",
|
||||
'w': "+W", 'x': "+X", 'y': "+Y", 'z': "+Z",
|
||||
'{': "%P", '|': "%Q", '}': "%R", '~': "%S",
|
||||
'\177': "%T"
|
||||
}
|
||||
|
||||
|
||||
_extchrs = _stdchrs + ascii_lowercase + \
|
||||
"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" + \
|
||||
"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" + \
|
||||
"*!'#&\"(),:;<=>?@[\\]^_`{|}~\177"
|
||||
|
||||
def _encode39(value, cksum, stop):
|
||||
v = sum([_patterns[c][1] for c in value]) % 43
|
||||
if cksum:
|
||||
value += _stdchrs[v]
|
||||
if stop: value = '*'+value+'*'
|
||||
return value
|
||||
|
||||
class _Code39Base(Barcode):
|
||||
barWidth = inch * 0.0075
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
quiet = 1
|
||||
gap = None
|
||||
barHeight = None
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 0.0
|
||||
stop = 1
|
||||
def __init__(self, value = "", **args):
|
||||
value = 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)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def decompose(self):
|
||||
dval = ""
|
||||
for c in self.encoded:
|
||||
dval = dval + _patterns[c][0] + 'i'
|
||||
self.decomposed = dval[:-1]
|
||||
return self.decomposed
|
||||
|
||||
def _humanText(self):
|
||||
return self.stop and self.encoded[1:-1] or self.encoded
|
||||
|
||||
class Standard39(_Code39Base):
|
||||
"""
|
||||
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).
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
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.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Wether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
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 .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Code 39:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_39.html
|
||||
http://www.adams1.com/pub/russadam/39code.html
|
||||
http://www.barcodeman.com/c39_1.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC1-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
def validate(self):
|
||||
vval = [].append
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if c in ascii_lowercase:
|
||||
c = c.upper()
|
||||
if c not in _stdchrs:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval(c)
|
||||
self.validated = ''.join(vval.__self__)
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = _encode39(self.validated, self.checksum, self.stop)
|
||||
return self.encoded
|
||||
|
||||
class Extended39(_Code39Base):
|
||||
"""
|
||||
Extended Code 39 is a convention for encoding additional characters
|
||||
not present in stanmdard Code 39 by using pairs of characters to
|
||||
represent the characters missing in Standard Code 39.
|
||||
|
||||
See Standard39 for arguments.
|
||||
|
||||
Sources of Information on Extended Code 39:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/xcode_39.html
|
||||
http://www.barcodeman.com/c39_ext.html
|
||||
"""
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if c not in _extchrs:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
self.encoded = ""
|
||||
for c in self.validated:
|
||||
if c in _extended:
|
||||
self.encoded = self.encoded + _extended[c]
|
||||
elif c in _stdchrs:
|
||||
self.encoded = self.encoded + c
|
||||
else:
|
||||
raise ValueError
|
||||
self.encoded = _encode39(self.encoded, self.checksum,self.stop)
|
||||
return self.encoded
|
||||
234
reportlab/graphics/barcode/code93.py
Normal file
234
reportlab/graphics/barcode/code93.py
Normal file
@@ -0,0 +1,234 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
_patterns = {
|
||||
'0' : ('AcAaAb', 0), '1' : ('AaAbAc', 1), '2' : ('AaAcAb', 2),
|
||||
'3' : ('AaAdAa', 3), '4' : ('AbAaAc', 4), '5' : ('AbAbAb', 5),
|
||||
'6' : ('AbAcAa', 6), '7' : ('AaAaAd', 7), '8' : ('AcAbAa', 8),
|
||||
'9' : ('AdAaAa', 9), 'A' : ('BaAaAc', 10), 'B' : ('BaAbAb', 11),
|
||||
'C' : ('BaAcAa', 12), 'D' : ('BbAaAb', 13), 'E' : ('BbAbAa', 14),
|
||||
'F' : ('BcAaAa', 15), 'G' : ('AaBaAc', 16), 'H' : ('AaBbAb', 17),
|
||||
'I' : ('AaBcAa', 18), 'J' : ('AbBaAb', 19), 'K' : ('AcBaAa', 20),
|
||||
'L' : ('AaAaBc', 21), 'M' : ('AaAbBb', 22), 'N' : ('AaAcBa', 23),
|
||||
'O' : ('AbAaBb', 24), 'P' : ('AcAaBa', 25), 'Q' : ('BaBaAb', 26),
|
||||
'R' : ('BaBbAa', 27), 'S' : ('BaAaBb', 28), 'T' : ('BaAbBa', 29),
|
||||
'U' : ('BbAaBa', 30), 'V' : ('BbBaAa', 31), 'W' : ('AaBaBb', 32),
|
||||
'X' : ('AaBbBa', 33), 'Y' : ('AbBaBa', 34), 'Z' : ('AbCaAa', 35),
|
||||
'-' : ('AbAaCa', 36), '.' : ('CaAaAb', 37), ' ' : ('CaAbAa', 38),
|
||||
'$' : ('CbAaAa', 39), '/' : ('AaBaCa', 40), '+' : ('AaCaBa', 41),
|
||||
'%' : ('BaAaCa', 42), '#' : ('AbAbBa', 43), '!' : ('CaBaAa', 44),
|
||||
'=' : ('CaAaBa', 45), '&' : ('AbBbAa', 46),
|
||||
'start' : ('AaAaDa', -1), 'stop' : ('AaAaDaA', -2)
|
||||
}
|
||||
|
||||
_charsbyval = {}
|
||||
for k, v in _patterns.items():
|
||||
_charsbyval[v[1]] = k
|
||||
|
||||
_extended = {
|
||||
'\x00' : '!U', '\x01' : '#A', '\x02' : '#B', '\x03' : '#C',
|
||||
'\x04' : '#D', '\x05' : '#E', '\x06' : '#F', '\x07' : '#G',
|
||||
'\x08' : '#H', '\x09' : '#I', '\x0a' : '#J', '\x0b' : '#K',
|
||||
'\x0c' : '#L', '\x0d' : '#M', '\x0e' : '#N', '\x0f' : '#O',
|
||||
'\x10' : '#P', '\x11' : '#Q', '\x12' : '#R', '\x13' : '#S',
|
||||
'\x14' : '#T', '\x15' : '#U', '\x16' : '#V', '\x17' : '#W',
|
||||
'\x18' : '#X', '\x19' : '#Y', '\x1a' : '#Z', '\x1b' : '!A',
|
||||
'\x1c' : '!B', '\x1d' : '!C', '\x1e' : '!D', '\x1f' : '!E',
|
||||
'!' : '=A', '"' : '=B', '#' : '=C', '$' : '=D',
|
||||
'%' : '=E', '&' : '=F', '\'' : '=G', '(' : '=H',
|
||||
')' : '=I', '*' : '=J', '+' : '=K', ',' : '=L',
|
||||
'/' : '=O', ':' : '=Z', ';' : '!F', '<' : '!G',
|
||||
'=' : '!H', '>' : '!I', '?' : '!J', '@' : '!V',
|
||||
'[' : '!K', '\\' : '!L', ']' : '!M', '^' : '!N',
|
||||
'_' : '!O', '`' : '!W', 'a' : '&A', 'b' : '&B',
|
||||
'c' : '&C', 'd' : '&D', 'e' : '&E', 'f' : '&F',
|
||||
'g' : '&G', 'h' : '&H', 'i' : '&I', 'j' : '&J',
|
||||
'k' : '&K', 'l' : '&L', 'm' : '&M', 'n' : '&N',
|
||||
'o' : '&O', 'p' : '&P', 'q' : '&Q', 'r' : '&R',
|
||||
's' : '&S', 't' : '&T', 'u' : '&U', 'v' : '&V',
|
||||
'w' : '&W', 'x' : '&X', 'y' : '&Y', 'z' : '&Z',
|
||||
'{' : '!P', '|' : '!Q', '}' : '!R', '~' : '!S',
|
||||
'\x7f' : '!T'
|
||||
}
|
||||
|
||||
def _encode93(str):
|
||||
s = list(str)
|
||||
s.reverse()
|
||||
|
||||
# compute 'C' checksum
|
||||
i = 0; v = 1; c = 0
|
||||
while i < len(s):
|
||||
c = c + v * _patterns[s[i]][1]
|
||||
i = i + 1; v = v + 1
|
||||
if v > 20:
|
||||
v = 1
|
||||
s.insert(0, _charsbyval[c % 47])
|
||||
|
||||
# compute 'K' checksum
|
||||
i = 0; v = 1; c = 0
|
||||
while i < len(s):
|
||||
c = c + v * _patterns[s[i]][1]
|
||||
i = i + 1; v = v + 1
|
||||
if v > 15:
|
||||
v = 1
|
||||
s.insert(0, _charsbyval[c % 47])
|
||||
|
||||
s.reverse()
|
||||
|
||||
return ''.join(s)
|
||||
|
||||
class _Code93Base(MultiWidthBarcode):
|
||||
barWidth = inch * 0.0075
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
quiet = 1
|
||||
barHeight = None
|
||||
stop = 1
|
||||
def __init__(self, value='', **args):
|
||||
|
||||
if type(value) is type(1):
|
||||
value = 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)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
MultiWidthBarcode.__init__(self, value)
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [_patterns['start'][0]] or []
|
||||
dval += [_patterns[c][0] for c in self.encoded]
|
||||
if self.stop: dval.append(_patterns['stop'][0])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class Standard93(_Code93Base):
|
||||
"""
|
||||
Code 93 is a Uppercase alphanumeric symbology with some punctuation.
|
||||
See Extended Code 93 for a variant that can represent the entire
|
||||
128 characrter ASCII set.
|
||||
|
||||
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.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Code 93:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_93.html
|
||||
|
||||
Official Spec, "NSI/AIM BC5-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.upper():
|
||||
if c not in _patterns:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
self.encoded = _encode93(self.validated)
|
||||
return self.encoded
|
||||
|
||||
|
||||
class Extended93(_Code93Base):
|
||||
"""
|
||||
Extended Code 93 is a convention for encoding the entire 128 character
|
||||
set using pairs of characters to represent the characters missing in
|
||||
Standard Code 93. It is very much like Extended Code 39 in that way.
|
||||
|
||||
See Standard93 for arguments.
|
||||
"""
|
||||
|
||||
def validate(self):
|
||||
vval = []
|
||||
self.valid = 1
|
||||
a = vval.append
|
||||
for c in self.value:
|
||||
if c not in _patterns and c not in _extended:
|
||||
self.valid = 0
|
||||
continue
|
||||
a(c)
|
||||
self.validated = ''.join(vval)
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = ""
|
||||
for c in self.validated:
|
||||
if c in _patterns:
|
||||
self.encoded = self.encoded + c
|
||||
elif c in _extended:
|
||||
self.encoded = self.encoded + _extended[c]
|
||||
else:
|
||||
raise ValueError
|
||||
self.encoded = _encode93(self.encoded)
|
||||
return self.encoded
|
||||
|
||||
def _humanText(self):
|
||||
return self.validated+self.encoded[-2:]
|
||||
749
reportlab/graphics/barcode/common.py
Normal file
749
reportlab/graphics/barcode/common.py
Normal file
@@ -0,0 +1,749 @@
|
||||
#
|
||||
# Copyright (c) 1996-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.platypus.flowables import Flowable
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.utils import ascii_uppercase, ascii_lowercase
|
||||
from string import digits as string_digits
|
||||
|
||||
class Barcode(Flowable):
|
||||
"""Abstract Base for barcodes. Includes implementations of
|
||||
some methods suitable for the more primitive barcode types"""
|
||||
|
||||
fontName = 'Courier'
|
||||
fontSize = 12
|
||||
humanReadable = 0
|
||||
|
||||
def _humanText(self):
|
||||
return self.encoded
|
||||
|
||||
def __init__(self, value='',**kwd):
|
||||
self.value = str(value)
|
||||
|
||||
self._setKeywords(**kwd)
|
||||
if not hasattr(self, 'gap'):
|
||||
self.gap = None
|
||||
|
||||
|
||||
def _calculate(self):
|
||||
self.validate()
|
||||
self.encode()
|
||||
self.decompose()
|
||||
self.computeSize()
|
||||
|
||||
def _setKeywords(self,**kwd):
|
||||
for (k, v) in kwd.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def validate(self):
|
||||
self.valid = 1
|
||||
self.validated = self.value
|
||||
|
||||
def encode(self):
|
||||
self.encoded = self.validated
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = self.encoded
|
||||
|
||||
def computeSize(self, *args):
|
||||
barWidth = self.barWidth
|
||||
wx = barWidth * self.ratio
|
||||
|
||||
if self.gap == None:
|
||||
self.gap = barWidth
|
||||
|
||||
w = 0.0
|
||||
|
||||
for c in self.decomposed:
|
||||
if c in 'sb':
|
||||
w = w + barWidth
|
||||
elif c in 'SB':
|
||||
w = w + wx
|
||||
else: # 'i'
|
||||
w = w + self.gap
|
||||
|
||||
if self.barHeight is None:
|
||||
self.barHeight = w * 0.15
|
||||
self.barHeight = max(0.25 * inch, self.barHeight)
|
||||
if self.bearers:
|
||||
self.barHeight = self.barHeight + self.bearers * 2.0 * barWidth
|
||||
|
||||
if self.quiet:
|
||||
w += self.lquiet + self.rquiet
|
||||
|
||||
|
||||
self._height = self.barHeight
|
||||
self._width = w
|
||||
|
||||
def width(self):
|
||||
self._calculate()
|
||||
return self._width
|
||||
width = property(width)
|
||||
|
||||
def height(self):
|
||||
self._calculate()
|
||||
return self._height
|
||||
height = property(height)
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
barWidth = self.barWidth
|
||||
wx = barWidth * self.ratio
|
||||
|
||||
left = self.quiet and self.lquiet or 0
|
||||
b = self.bearers * barWidth
|
||||
bb = b * 0.5
|
||||
tb = self.barHeight - (b * 1.5)
|
||||
|
||||
for c in self.decomposed:
|
||||
if c == 'i':
|
||||
left = left + self.gap
|
||||
elif c == 's':
|
||||
left = left + barWidth
|
||||
elif c == 'S':
|
||||
left = left + wx
|
||||
elif c == 'b':
|
||||
self.rect(left, bb, barWidth, tb)
|
||||
left = left + barWidth
|
||||
elif c == 'B':
|
||||
self.rect(left, bb, wx, tb)
|
||||
left = left + wx
|
||||
|
||||
if self.bearers:
|
||||
self.rect(self.lquiet, 0, \
|
||||
self._width - (self.lquiet + self.rquiet), b)
|
||||
self.rect(self.lquiet, self.barHeight - b, \
|
||||
self._width - (self.lquiet + self.rquiet), b)
|
||||
|
||||
self.drawHumanReadable()
|
||||
|
||||
def drawHumanReadable(self):
|
||||
if self.humanReadable:
|
||||
#we have text
|
||||
from reportlab.pdfbase.pdfmetrics import getAscent, stringWidth
|
||||
s = str(self._humanText())
|
||||
fontSize = self.fontSize
|
||||
fontName = self.fontName
|
||||
w = stringWidth(s,fontName,fontSize)
|
||||
width = self._width
|
||||
if self.quiet:
|
||||
width -= self.lquiet+self.rquiet
|
||||
x = self.lquiet
|
||||
else:
|
||||
x = 0
|
||||
if w>width: fontSize *= width/float(w)
|
||||
y = 1.07*getAscent(fontName)*fontSize/1000.
|
||||
self.annotate(x+width/2.,-y,s,fontName,fontSize)
|
||||
|
||||
def rect(self, x, y, w, h):
|
||||
self.canv.rect(x, y, w, h, stroke=0, fill=1)
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
canv = self.canv
|
||||
canv.saveState()
|
||||
canv.setFont(self.fontName,fontSize)
|
||||
if anchor=='middle': func = 'drawCentredString'
|
||||
elif anchor=='end': func = 'drawRightString'
|
||||
else: func = 'drawString'
|
||||
getattr(canv,func)(x,y,text)
|
||||
canv.restoreState()
|
||||
|
||||
class MultiWidthBarcode(Barcode):
|
||||
"""Base for variable-bar-width codes like Code93 and Code128"""
|
||||
|
||||
def computeSize(self, *args):
|
||||
barWidth = self.barWidth
|
||||
oa, oA = ord('a') - 1, ord('A') - 1
|
||||
|
||||
w = 0.0
|
||||
|
||||
for c in self.decomposed:
|
||||
oc = ord(c)
|
||||
if c in ascii_lowercase:
|
||||
w = w + barWidth * (oc - oa)
|
||||
elif c in ascii_uppercase:
|
||||
w = w + barWidth * (oc - oA)
|
||||
|
||||
if self.barHeight is None:
|
||||
self.barHeight = w * 0.15
|
||||
self.barHeight = max(0.25 * inch, self.barHeight)
|
||||
|
||||
if self.quiet:
|
||||
w += self.lquiet + self.rquiet
|
||||
|
||||
self._height = self.barHeight
|
||||
self._width = w
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
oa, oA = ord('a') - 1, ord('A') - 1
|
||||
barWidth = self.barWidth
|
||||
left = self.quiet and self.lquiet or 0
|
||||
|
||||
for c in self.decomposed:
|
||||
oc = ord(c)
|
||||
if c in ascii_lowercase:
|
||||
left = left + (oc - oa) * barWidth
|
||||
elif c in ascii_uppercase:
|
||||
w = (oc - oA) * barWidth
|
||||
self.rect(left, 0, w, self.barHeight)
|
||||
left += w
|
||||
self.drawHumanReadable()
|
||||
|
||||
class I2of5(Barcode):
|
||||
"""
|
||||
Interleaved 2 of 5 is a numeric-only barcode. It encodes an even
|
||||
number of digits; if an odd number is given, a 0 is prepended.
|
||||
|
||||
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).
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
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.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Whether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 3.0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 3 x-dimensions.
|
||||
Set to zero for no bearer bars. (Bearer bars help detect
|
||||
misscans, so it is suggested to leave them on).
|
||||
|
||||
quiet (bool, default 1):
|
||||
Whether 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 .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Interleaved 2 of 5:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html
|
||||
http://www.adams1.com/pub/russadam/i25code.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'start' : 'bsbs',
|
||||
'stop' : 'Bsb',
|
||||
|
||||
'B0' : 'bbBBb', 'S0' : 'ssSSs',
|
||||
'B1' : 'BbbbB', 'S1' : 'SsssS',
|
||||
'B2' : 'bBbbB', 'S2' : 'sSssS',
|
||||
'B3' : 'BBbbb', 'S3' : 'SSsss',
|
||||
'B4' : 'bbBbB', 'S4' : 'ssSsS',
|
||||
'B5' : 'BbBbb', 'S5' : 'SsSss',
|
||||
'B6' : 'bBBbb', 'S6' : 'sSSss',
|
||||
'B7' : 'bbbBB', 'S7' : 'sssSS',
|
||||
'B8' : 'BbbBb', 'S8' : 'SssSs',
|
||||
'B9' : 'bBbBb', 'S9' : 'sSsSs'
|
||||
}
|
||||
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 3.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
stop = 1
|
||||
|
||||
def __init__(self, value='', **args):
|
||||
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.strip():
|
||||
if c not in string_digits:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
cs = self.checksum
|
||||
c = len(s)
|
||||
|
||||
#ensure len(result)%2 == 0, checksum included
|
||||
if ((c % 2 == 0) and cs) or ((c % 2 == 1) and not cs):
|
||||
s = '0' + s
|
||||
c += 1
|
||||
|
||||
if cs:
|
||||
c = 3*sum([int(s[i]) for i in range(0,c,2)])+sum([int(s[i]) for i in range(1,c,2)])
|
||||
s += str((10 - c) % 10)
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [self.patterns['start']] or []
|
||||
a = dval.append
|
||||
|
||||
for i in range(0, len(self.encoded), 2):
|
||||
b = self.patterns['B' + self.encoded[i]]
|
||||
s = self.patterns['S' + self.encoded[i+1]]
|
||||
|
||||
for i in range(0, len(b)):
|
||||
a(b[i] + s[i])
|
||||
|
||||
if self.stop: a(self.patterns['stop'])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class MSI(Barcode):
|
||||
"""
|
||||
MSI is a numeric-only barcode.
|
||||
|
||||
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
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
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.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Wether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
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 barWidths.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on MSI Bar Code:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html
|
||||
http://www.adams1.com/pub/russadam/plessy.html
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'start' : 'Bs', 'stop' : 'bSb',
|
||||
|
||||
'0' : 'bSbSbSbS', '1' : 'bSbSbSBs',
|
||||
'2' : 'bSbSBsbS', '3' : 'bSbSBsBs',
|
||||
'4' : 'bSBsbSbS', '5' : 'bSBsbSBs',
|
||||
'6' : 'bSBsBsbS', '7' : 'bSBsBsBs',
|
||||
'8' : 'BsbSbSbS', '9' : 'BsbSbSBs'
|
||||
}
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
|
||||
def __init__(self, value="", **args):
|
||||
|
||||
if type(value) == type(1):
|
||||
value = str(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)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.strip():
|
||||
if c not in string_digits:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
if self.checksum:
|
||||
c = ''
|
||||
for i in range(1, len(s), 2):
|
||||
c = c + s[i]
|
||||
d = str(int(c) * 2)
|
||||
t = 0
|
||||
for c in d:
|
||||
t = t + int(c)
|
||||
for i in range(0, len(s), 2):
|
||||
t = t + int(s[i])
|
||||
c = 10 - (t % 10)
|
||||
|
||||
s = s + str(c)
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [self.patterns['start']] or []
|
||||
dval += [self.patterns[c] for c in self.encoded]
|
||||
if self.stop: dval.append(self.patterns['stop'])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class Codabar(Barcode):
|
||||
"""
|
||||
Codabar is a numeric plus some puntuation ("-$:/.+") barcode
|
||||
with four start/stop characters (A, B, C, and D).
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0065):
|
||||
X-Dimension, or width of the smallest element
|
||||
minimum is 6.5 mils (.0065 inch)
|
||||
|
||||
ratio (float, default 2.0):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
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.
|
||||
|
||||
checksum (bool, default 0):
|
||||
Whether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
quiet (bool, default 1):
|
||||
Whether to include quiet zones in the symbol.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
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 Codabar
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html
|
||||
http://www.barcodeman.com/codabar.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'0': 'bsbsbSB', '1': 'bsbsBSb', '2': 'bsbSbsB',
|
||||
'3': 'BSbsbsb', '4': 'bsBsbSb', '5': 'BsbsbSb',
|
||||
'6': 'bSbsbsB', '7': 'bSbsBsb', '8': 'bSBsbsb',
|
||||
'9': 'BsbSbsb', '-': 'bsbSBsb', '$': 'bsBSbsb',
|
||||
':': 'BsbsBsB', '/': 'BsBsbsB', '.': 'BsBsBsb',
|
||||
'+': 'bsBsBsB', 'A': 'bsBSbSb', 'B': 'bSbSbsB',
|
||||
'C': 'bsbSbSB', 'D': 'bsbSBSb'
|
||||
}
|
||||
|
||||
values = {
|
||||
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
|
||||
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
|
||||
'-' : 10, '$' : 11, ':' : 12, '/' : 13, '.' : 14,
|
||||
'+' : 15, 'A' : 16, 'B' : 17, 'C' : 18, 'D' : 19
|
||||
}
|
||||
|
||||
chars = string_digits + "-$:/.+"
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0065
|
||||
ratio = 2.0 # XXX ?
|
||||
checksum = 0
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
|
||||
def __init__(self, value='', **args):
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
s = self.value.strip()
|
||||
for i in range(0, len(s)):
|
||||
c = s[i]
|
||||
if c not in self.chars:
|
||||
if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'):
|
||||
self.Valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
|
||||
if self.stop:
|
||||
if vval[0] not in 'ABCD':
|
||||
vval = 'A' + vval
|
||||
if vval[-1] not in 'ABCD':
|
||||
vval = vval + vval[0]
|
||||
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
if self.checksum:
|
||||
v = sum([self.values[c] for c in s])
|
||||
s += self.chars[v % 16]
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = ''.join([self.patterns[c]+'i' for c in self.encoded])
|
||||
self.decomposed = dval[:-1]
|
||||
return self.decomposed
|
||||
|
||||
class Code11(Barcode):
|
||||
"""
|
||||
Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus
|
||||
dash ("-"). 11 characters total, hence the name.
|
||||
|
||||
value (int or string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
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.
|
||||
|
||||
checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
|
||||
How many checksum digits to include. -1 ("auto") means
|
||||
1 if the number of digits is 10 or less, else 2.
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
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 11:
|
||||
|
||||
http://www.cwi.nl/people/dik/english/codes/barcodes.html
|
||||
"""
|
||||
|
||||
chars = '0123456789-'
|
||||
|
||||
patterns = {
|
||||
'0' : 'bsbsB', '1' : 'BsbsB', '2' : 'bSbsB',
|
||||
'3' : 'BSbsb', '4' : 'bsBsB', '5' : 'BsBsb',
|
||||
'6' : 'bSBsb', '7' : 'bsbSB', '8' : 'BsbSb',
|
||||
'9' : 'Bsbsb', '-' : 'bsBsb', 'S' : 'bsBSb' # Start/Stop
|
||||
}
|
||||
|
||||
values = {
|
||||
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
|
||||
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
|
||||
'-' : 10,
|
||||
}
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2 # XXX ?
|
||||
checksum = -1 # Auto
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
def __init__(self, value='', **args):
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
s = self.value.strip()
|
||||
for i in range(0, len(s)):
|
||||
c = s[i]
|
||||
if c not in self.chars:
|
||||
self.Valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def _addCSD(self,s,m):
|
||||
# compute first checksum
|
||||
i = c = 0
|
||||
v = 1
|
||||
V = self.values
|
||||
while i < len(s):
|
||||
c += v * V[s[-(i+1)]]
|
||||
i += 1
|
||||
v += 1
|
||||
if v==m:
|
||||
v = 1
|
||||
return s+self.chars[c % 11]
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
tcs = self.checksum
|
||||
if tcs<0:
|
||||
self.checksum = tcs = 1+int(len(s)>10)
|
||||
|
||||
if tcs > 0: s = self._addCSD(s,11)
|
||||
if tcs > 1: s = self._addCSD(s,10)
|
||||
|
||||
self.encoded = self.stop and ('S' + s + 'S') or s
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''.join([(self.patterns[c]+'i') for c in self.encoded])[:-1]
|
||||
return self.decomposed
|
||||
|
||||
def _humanText(self):
|
||||
return self.stop and self.encoded[1:-1] or self.encoded
|
||||
350
reportlab/graphics/barcode/eanbc.py
Normal file
350
reportlab/graphics/barcode/eanbc.py
Normal file
@@ -0,0 +1,350 @@
|
||||
__all__=(
|
||||
'Ean13BarcodeWidget','isEanString',
|
||||
)
|
||||
from reportlab.graphics.shapes import Group, String, Rect
|
||||
from reportlab.lib import colors
|
||||
from reportlab.pdfbase.pdfmetrics import stringWidth
|
||||
from reportlab.lib.validators import isNumber, isColor, isString, Validator, isBoolean
|
||||
from reportlab.lib.attrmap import *
|
||||
from reportlab.graphics.charts.areas import PlotArea
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
#work out a list of manufacturer codes....
|
||||
_eanNumberSystems = [
|
||||
('00-13', 'USA & Canada'),
|
||||
('20-29', 'In-Store Functions'),
|
||||
('30-37', 'France'),
|
||||
('40-44', 'Germany'),
|
||||
('45', 'Japan (also 49)'),
|
||||
('46', 'Russian Federation'),
|
||||
('471', 'Taiwan'),
|
||||
('474', 'Estonia'),
|
||||
('475', 'Latvia'),
|
||||
('477', 'Lithuania'),
|
||||
('479', 'Sri Lanka'),
|
||||
('480', 'Philippines'),
|
||||
('482', 'Ukraine'),
|
||||
('484', 'Moldova'),
|
||||
('485', 'Armenia'),
|
||||
('486', 'Georgia'),
|
||||
('487', 'Kazakhstan'),
|
||||
('489', 'Hong Kong'),
|
||||
('49', 'Japan (JAN-13)'),
|
||||
('50', 'United Kingdom'),
|
||||
('520', 'Greece'),
|
||||
('528', 'Lebanon'),
|
||||
('529', 'Cyprus'),
|
||||
('531', 'Macedonia'),
|
||||
('535', 'Malta'),
|
||||
('539', 'Ireland'),
|
||||
('54', 'Belgium & Luxembourg'),
|
||||
('560', 'Portugal'),
|
||||
('569', 'Iceland'),
|
||||
('57', 'Denmark'),
|
||||
('590', 'Poland'),
|
||||
('594', 'Romania'),
|
||||
('599', 'Hungary'),
|
||||
('600-601', 'South Africa'),
|
||||
('609', 'Mauritius'),
|
||||
('611', 'Morocco'),
|
||||
('613', 'Algeria'),
|
||||
('619', 'Tunisia'),
|
||||
('622', 'Egypt'),
|
||||
('625', 'Jordan'),
|
||||
('626', 'Iran'),
|
||||
('64', 'Finland'),
|
||||
('690-692', 'China'),
|
||||
('70', 'Norway'),
|
||||
('729', 'Israel'),
|
||||
('73', 'Sweden'),
|
||||
('740', 'Guatemala'),
|
||||
('741', 'El Salvador'),
|
||||
('742', 'Honduras'),
|
||||
('743', 'Nicaragua'),
|
||||
('744', 'Costa Rica'),
|
||||
('746', 'Dominican Republic'),
|
||||
('750', 'Mexico'),
|
||||
('759', 'Venezuela'),
|
||||
('76', 'Switzerland'),
|
||||
('770', 'Colombia'),
|
||||
('773', 'Uruguay'),
|
||||
('775', 'Peru'),
|
||||
('777', 'Bolivia'),
|
||||
('779', 'Argentina'),
|
||||
('780', 'Chile'),
|
||||
('784', 'Paraguay'),
|
||||
('785', 'Peru'),
|
||||
('786', 'Ecuador'),
|
||||
('789', 'Brazil'),
|
||||
('80-83', 'Italy'),
|
||||
('84', 'Spain'),
|
||||
('850', 'Cuba'),
|
||||
('858', 'Slovakia'),
|
||||
('859', 'Czech Republic'),
|
||||
('860', 'Yugloslavia'),
|
||||
('869', 'Turkey'),
|
||||
('87', 'Netherlands'),
|
||||
('880', 'South Korea'),
|
||||
('885', 'Thailand'),
|
||||
('888', 'Singapore'),
|
||||
('890', 'India'),
|
||||
('893', 'Vietnam'),
|
||||
('899', 'Indonesia'),
|
||||
('90-91', 'Austria'),
|
||||
('93', 'Australia'),
|
||||
('94', 'New Zealand'),
|
||||
('955', 'Malaysia'),
|
||||
('977', 'International Standard Serial Number for Periodicals (ISSN)'),
|
||||
('978', 'International Standard Book Numbering (ISBN)'),
|
||||
('979', 'International Standard Music Number (ISMN)'),
|
||||
('980', 'Refund receipts'),
|
||||
('981-982', 'Common Currency Coupons'),
|
||||
('99', 'Coupons')
|
||||
]
|
||||
|
||||
manufacturerCodes = {}
|
||||
for (k, v) in _eanNumberSystems:
|
||||
words = k.split('-')
|
||||
if len(words)==2:
|
||||
fromCode = int(words[0])
|
||||
toCode = int(words[1])
|
||||
for code in range(fromCode, toCode+1):
|
||||
manufacturerCodes[code] = v
|
||||
else:
|
||||
manufacturerCodes[int(k)] = v
|
||||
|
||||
def nDigits(n):
|
||||
class _ndigits(Validator):
|
||||
def test(self,x):
|
||||
return type(x) is str and len(x)<=n and len([c for c in x if c in "0123456789"])==n
|
||||
return _ndigits()
|
||||
|
||||
class Ean13BarcodeWidget(PlotArea):
|
||||
codeName = "EAN13"
|
||||
_attrMap = AttrMap(BASE=PlotArea,
|
||||
value = AttrMapValue(nDigits(12), desc='the number'),
|
||||
fontName = AttrMapValue(isString, desc='fontName'),
|
||||
fontSize = AttrMapValue(isNumber, desc='font size'),
|
||||
x = AttrMapValue(isNumber, desc='x-coord'),
|
||||
y = AttrMapValue(isNumber, desc='y-coord'),
|
||||
barFillColor = AttrMapValue(isColor, desc='bar color'),
|
||||
barHeight = AttrMapValue(isNumber, desc='Height of bars.'),
|
||||
barWidth = AttrMapValue(isNumber, desc='Width of bars.'),
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'),
|
||||
textColor = AttrMapValue(isColor, desc='human readable text color'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
quiet = AttrMapValue(isBoolean, desc='if quiet zone to be used'),
|
||||
lquiet = AttrMapValue(isBoolean, desc='left quiet zone length'),
|
||||
rquiet = AttrMapValue(isBoolean, desc='right quiet zone length'),
|
||||
)
|
||||
_digits=12
|
||||
_start_right = 7 #for ean-13 left = [0:7] right=[7:13]
|
||||
_nbars = 113
|
||||
barHeight = 25.93*mm #millimeters
|
||||
barWidth = (37.29/_nbars)*mm
|
||||
humanReadable = 1
|
||||
_0csw = 1
|
||||
_1csw = 3
|
||||
|
||||
#Left Hand Digits.
|
||||
_left = ( ("0001101", "0011001", "0010011", "0111101",
|
||||
"0100011", "0110001", "0101111", "0111011",
|
||||
"0110111", "0001011",
|
||||
), #odd left hand digits
|
||||
("0100111", "0110011", "0011011", "0100001",
|
||||
"0011101", "0111001", "0000101", "0010001",
|
||||
"0001001", "0010111"), #even left hand digits
|
||||
)
|
||||
|
||||
_right = ("1110010", "1100110", "1101100", "1000010",
|
||||
"1011100", "1001110", "1010000", "1000100",
|
||||
"1001000", "1110100")
|
||||
|
||||
quiet = 1
|
||||
rquiet = lquiet = None
|
||||
_tail = "101"
|
||||
_sep = "01010"
|
||||
|
||||
_lhconvert={
|
||||
"0": (0,0,0,0,0,0),
|
||||
"1": (0,0,1,0,1,1),
|
||||
"2": (0,0,1,1,0,1),
|
||||
"3": (0,0,1,1,1,0),
|
||||
"4": (0,1,0,0,1,1),
|
||||
"5": (0,1,1,0,0,1),
|
||||
"6": (0,1,1,1,0,0),
|
||||
"7": (0,1,0,1,0,1),
|
||||
"8": (0,1,0,1,1,0),
|
||||
"9": (0,1,1,0,1,0)
|
||||
}
|
||||
fontSize = 8 #millimeters
|
||||
fontName = 'Helvetica'
|
||||
textColor = barFillColor = colors.black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
x = 0
|
||||
y = 0
|
||||
def __init__(self,value='123456789012',**kw):
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
self.value=max(self._digits-len(value),0)*'0'+value[:self._digits]
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
width = property(lambda self: self.barWidth*(self._nbars-18+self._calc_quiet(self.lquiet)+self._calc_quiet(self.rquiet)))
|
||||
|
||||
def wrap(self,aW,aH):
|
||||
return self.width,self.barHeight
|
||||
|
||||
def _encode_left(self,s,a):
|
||||
cp = self._lhconvert[s[0]] #convert the left hand numbers
|
||||
_left = self._left
|
||||
z = ord('0')
|
||||
for i,c in enumerate(s[1:self._start_right]):
|
||||
a(_left[cp[i]][ord(c)-z])
|
||||
|
||||
def _short_bar(self,i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((12<i<55) or (57<i<101))
|
||||
|
||||
def _calc_quiet(self,v):
|
||||
if self.quiet:
|
||||
if v is None:
|
||||
v = 9
|
||||
else:
|
||||
x = float(max(v,0))/self.barWidth
|
||||
v = int(x)
|
||||
if v-x>0: v += 1
|
||||
else:
|
||||
v = 0
|
||||
return v
|
||||
|
||||
def draw(self):
|
||||
g = Group()
|
||||
gAdd = g.add
|
||||
barWidth = self.barWidth
|
||||
width = self.width
|
||||
barHeight = self.barHeight
|
||||
x = self.x
|
||||
y = self.y
|
||||
gAdd(Rect(x,y,width,barHeight,fillColor=None,strokeColor=None,strokeWidth=0))
|
||||
s = self.value+self._checkdigit(self.value)
|
||||
self._lquiet = lquiet = self._calc_quiet(self.lquiet)
|
||||
rquiet = self._calc_quiet(self.rquiet)
|
||||
b = [lquiet*'0',self._tail] #the signal string
|
||||
a = b.append
|
||||
self._encode_left(s,a)
|
||||
a(self._sep)
|
||||
|
||||
z = ord('0')
|
||||
_right = self._right
|
||||
for c in s[self._start_right:]:
|
||||
a(_right[ord(c)-z])
|
||||
a(self._tail)
|
||||
a(rquiet*'0')
|
||||
|
||||
fontSize = self.fontSize
|
||||
barFillColor = self.barFillColor
|
||||
barStrokeWidth = self.barStrokeWidth
|
||||
barStrokeColor = self.barStrokeColor
|
||||
|
||||
fth = fontSize*1.2
|
||||
b = ''.join(b)
|
||||
|
||||
lrect = None
|
||||
for i,c in enumerate(b):
|
||||
if c=="1":
|
||||
dh = self._short_bar(i) and fth or 0
|
||||
yh = y+dh
|
||||
if lrect and lrect.y==yh:
|
||||
lrect.width += barWidth
|
||||
else:
|
||||
lrect = Rect(x,yh,barWidth,barHeight-dh,fillColor=barFillColor,strokeWidth=barStrokeWidth,strokeColor=barStrokeColor)
|
||||
gAdd(lrect)
|
||||
else:
|
||||
lrect = None
|
||||
x += barWidth
|
||||
|
||||
if self.humanReadable: self._add_human_readable(s,gAdd)
|
||||
return g
|
||||
|
||||
def _add_human_readable(self,s,gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize*1.2
|
||||
# draw the num below the line.
|
||||
c = s[0]
|
||||
w = stringWidth(c,fontName,fontSize)
|
||||
x = self.x+barWidth*(self._lquiet-8)
|
||||
y = self.y + 0.2*fth
|
||||
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor))
|
||||
x = self.x + (33-9+self._lquiet)*barWidth
|
||||
|
||||
c = s[1:7]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x += 47*barWidth
|
||||
c = s[7:]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
def _checkdigit(cls,num):
|
||||
z = ord('0')
|
||||
iSum = cls._0csw*sum([(ord(x)-z) for x in num[::2]]) \
|
||||
+ cls._1csw*sum([(ord(x)-z) for x in num[1::2]])
|
||||
return chr(z+((10-(iSum%10))%10))
|
||||
_checkdigit=classmethod(_checkdigit)
|
||||
|
||||
class Ean8BarcodeWidget(Ean13BarcodeWidget):
|
||||
codeName = "EAN8"
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
value = AttrMapValue(nDigits(7), desc='the number'),
|
||||
)
|
||||
_start_right = 4 #for ean-13 left = [0:7] right=[7:13]
|
||||
_nbars = 85
|
||||
_digits=7
|
||||
_0csw = 3
|
||||
_1csw = 1
|
||||
|
||||
def _encode_left(self,s,a):
|
||||
cp = self._lhconvert[s[0]] #convert the left hand numbers
|
||||
_left = self._left[0]
|
||||
z = ord('0')
|
||||
for i,c in enumerate(s[0:self._start_right]):
|
||||
a(_left[ord(c)-z])
|
||||
|
||||
def _short_bar(self,i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((12<i<41) or (43<i<73))
|
||||
|
||||
def _add_human_readable(self,s,gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize*1.2
|
||||
# draw the num below the line.
|
||||
y = self.y + 0.2*fth
|
||||
|
||||
x = (26.5-9+self._lquiet)*barWidth
|
||||
|
||||
c = s[0:4]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x = (59.5-9+self._lquiet)*barWidth
|
||||
c = s[4:]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
class UPCA(Ean13BarcodeWidget):
|
||||
codeName = "UPCA"
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
value = AttrMapValue(nDigits(11), desc='the number'),
|
||||
)
|
||||
_start_right = 6
|
||||
_digits = 11
|
||||
_0csw = 3
|
||||
_1csw = 1
|
||||
_nbars = 1+7*11+2*3+5
|
||||
81
reportlab/graphics/barcode/fourstate.py
Normal file
81
reportlab/graphics/barcode/fourstate.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# 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.graphics.barcode.common import Barcode
|
||||
import string
|
||||
|
||||
# . 3 T Tracker
|
||||
# , 2 D Descender
|
||||
# ' 1 A Ascender
|
||||
# | 0 H Ascender/Descender
|
||||
|
||||
_rm_patterns = {
|
||||
"0" : "--||", "1" : "-',|", "2" : "-'|,", "3" : "'-,|",
|
||||
"4" : "'-|,", "5" : "'',,", "6" : "-,'|", "7" : "-|-|",
|
||||
"8" : "-|',", "9" : "',-|", "A" : "',',", "B" : "'|-,",
|
||||
"C" : "-,|'", "D" : "-|,'", "E" : "-||-", "F" : "',,'",
|
||||
"G" : "',|-", "H" : "'|,-", "I" : ",-'|", "J" : ",'-|",
|
||||
"K" : ",'',", "L" : "|--|", "M" : "|-',", "N" : "|'-,",
|
||||
"O" : ",-|'", "P" : ",','", "Q" : ",'|-", "R" : "|-,'",
|
||||
"S" : "|-|-", "T" : "|',-", "U" : ",,''", "V" : ",|-'",
|
||||
"W" : ",|'-", "X" : "|,-'", "Y" : "|,'-", "Z" : "||--",
|
||||
|
||||
# start, stop
|
||||
"(" : "'-,'", ")" : "'|,|"
|
||||
}
|
||||
|
||||
_ozN_patterns = {
|
||||
"0" : "||", "1" : "|'", "2" : "|,", "3" : "'|", "4" : "''",
|
||||
"5" : "',", "6" : ",|", "7" : ",'", "8" : ",,", "9" : ".|"
|
||||
}
|
||||
|
||||
_ozC_patterns = {
|
||||
"A" : "|||", "B" : "||'", "C" : "||,", "D" : "|'|",
|
||||
"E" : "|''", "F" : "|',", "G" : "|,|", "H" : "|,'",
|
||||
"I" : "|,,", "J" : "'||", "K" : "'|'", "L" : "'|,",
|
||||
"M" : "''|", "N" : "'''", "O" : "'',", "P" : "',|",
|
||||
"Q" : "','", "R" : "',,", "S" : ",||", "T" : ",|'",
|
||||
"U" : ",|,", "V" : ",'|", "W" : ",''", "X" : ",',",
|
||||
"Y" : ",,|", "Z" : ",,'", "a" : "|,.", "b" : "|.|",
|
||||
"c" : "|.'", "d" : "|.,", "e" : "|..", "f" : "'|.",
|
||||
"g" : "''.", "h" : "',.", "i" : "'.|", "j" : "'.'",
|
||||
"k" : "'.,", "l" : "'..", "m" : ",|.", "n" : ",'.",
|
||||
"o" : ",,.", "p" : ",.|", "q" : ",.'", "r" : ",.,",
|
||||
"s" : ",..", "t" : ".|.", "u" : ".'.", "v" : ".,.",
|
||||
"w" : "..|", "x" : "..'", "y" : "..,", "z" : "...",
|
||||
"0" : ",,,", "1" : ".||", "2" : ".|'", "3" : ".|,",
|
||||
"4" : ".'|", "5" : ".''", "6" : ".',", "7" : ".,|",
|
||||
"8" : ".,'", "9" : ".,,", " " : "||.", "#" : "|'.",
|
||||
}
|
||||
|
||||
#http://www.auspost.com.au/futurepost/
|
||||
196
reportlab/graphics/barcode/lto.py
Normal file
196
reportlab/graphics/barcode/lto.py
Normal file
@@ -0,0 +1,196 @@
|
||||
# (c) 2008 Jerome Alet - <alet@librelogiciel.com>
|
||||
# Licensing terms : ReportLab's license.
|
||||
|
||||
from reportlab.graphics.barcode.code39 import Standard39
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.units import cm
|
||||
from string import digits as string_digits
|
||||
from reportlab.lib.utils import ascii_uppercase
|
||||
|
||||
class BaseLTOLabel(Standard39) :
|
||||
"""
|
||||
Base class for LTO labels.
|
||||
|
||||
Specification taken from "IBM LTO Ultrium Cartridge Label Specification, Revision 3"
|
||||
available on May 14th 2008 from :
|
||||
http://www-1.ibm.com/support/docview.wss?rs=543&context=STCVQ6R&q1=ssg1*&uid=ssg1S7000429&loc=en_US&cs=utf-8&lang=en+en
|
||||
"""
|
||||
LABELWIDTH = 7.9 * cm
|
||||
LABELHEIGHT = 1.7 * cm
|
||||
LABELROUND = 0.15 * cm
|
||||
CODERATIO = 2.75
|
||||
CODENOMINALWIDTH = 7.4088 * cm
|
||||
CODEBARHEIGHT = 1.11 * cm
|
||||
CODEBARWIDTH = 0.0432 * cm
|
||||
CODEGAP = CODEBARWIDTH
|
||||
CODELQUIET = 10 * CODEBARWIDTH
|
||||
CODERQUIET = 10 * CODEBARWIDTH
|
||||
def __init__(self, prefix="",
|
||||
number=None,
|
||||
subtype="1",
|
||||
border=None,
|
||||
checksum=False,
|
||||
availheight=None) :
|
||||
"""
|
||||
Initializes an LTO label.
|
||||
|
||||
prefix : Up to six characters from [A-Z][0-9]. Defaults to "".
|
||||
number : Label's number or None. Defaults to None.
|
||||
subtype : LTO subtype string , e.g. "1" for LTO1. Defaults to "1".
|
||||
border : None, or the width of the label's border. Defaults to None.
|
||||
checksum : Boolean indicates if checksum char has to be printed. Defaults to False.
|
||||
availheight : Available height on the label, or None for automatic. Defaults to None.
|
||||
"""
|
||||
self.height = max(availheight, self.CODEBARHEIGHT)
|
||||
self.border = border
|
||||
if (len(subtype) != 1) \
|
||||
or (subtype not in ascii_uppercase + string_digits) :
|
||||
raise ValueError("Invalid subtype '%s'" % subtype)
|
||||
if ((not number) and (len(prefix) > 6)) \
|
||||
or not prefix.isalnum() :
|
||||
raise ValueError("Invalid prefix '%s'" % prefix)
|
||||
label = "%sL%s" % ((prefix + str(number or 0).zfill(6 - len(prefix)))[:6],
|
||||
subtype)
|
||||
if len(label) != 8 :
|
||||
raise ValueError("Invalid set of parameters (%s, %s, %s)" \
|
||||
% (prefix, number, subtype))
|
||||
self.label = label
|
||||
Standard39.__init__(self,
|
||||
label,
|
||||
ratio=self.CODERATIO,
|
||||
barHeight=self.height,
|
||||
barWidth=self.CODEBARWIDTH,
|
||||
gap=self.CODEGAP,
|
||||
lquiet=self.CODELQUIET,
|
||||
rquiet=self.CODERQUIET,
|
||||
quiet=True,
|
||||
checksum=checksum)
|
||||
|
||||
def drawOn(self, canvas, x, y) :
|
||||
"""Draws the LTO label onto the canvas."""
|
||||
canvas.saveState()
|
||||
canvas.translate(x, y)
|
||||
if self.border :
|
||||
canvas.setLineWidth(self.border)
|
||||
canvas.roundRect(0, 0,
|
||||
self.LABELWIDTH,
|
||||
self.LABELHEIGHT,
|
||||
self.LABELROUND)
|
||||
Standard39.drawOn(self,
|
||||
canvas,
|
||||
(self.LABELWIDTH-self.CODENOMINALWIDTH)/2.0,
|
||||
self.LABELHEIGHT-self.height)
|
||||
canvas.restoreState()
|
||||
|
||||
class VerticalLTOLabel(BaseLTOLabel) :
|
||||
"""
|
||||
A class for LTO labels with rectangular blocks around the tape identifier.
|
||||
"""
|
||||
LABELFONT = ("Helvetica-Bold", 14)
|
||||
BLOCKWIDTH = 1*cm
|
||||
BLOCKHEIGHT = 0.45*cm
|
||||
LINEWIDTH = 0.0125
|
||||
NBBLOCKS = 7
|
||||
COLORSCHEME = ("red",
|
||||
"yellow",
|
||||
"lightgreen",
|
||||
"lightblue",
|
||||
"grey",
|
||||
"orangered",
|
||||
"pink",
|
||||
"darkgreen",
|
||||
"orange",
|
||||
"purple")
|
||||
|
||||
def __init__(self, *args, **kwargs) :
|
||||
"""
|
||||
Initializes the label.
|
||||
|
||||
colored : boolean to determine if blocks have to be colorized.
|
||||
"""
|
||||
if "colored" in kwargs:
|
||||
self.colored = kwargs["colored"]
|
||||
del kwargs["colored"]
|
||||
else :
|
||||
self.colored = False
|
||||
kwargs["availheight"] = self.LABELHEIGHT-self.BLOCKHEIGHT
|
||||
BaseLTOLabel.__init__(self, *args, **kwargs)
|
||||
|
||||
def drawOn(self, canvas, x, y) :
|
||||
"""Draws some blocks around the identifier's characters."""
|
||||
BaseLTOLabel.drawOn(self,
|
||||
canvas,
|
||||
x,
|
||||
y)
|
||||
canvas.saveState()
|
||||
canvas.setLineWidth(self.LINEWIDTH)
|
||||
canvas.setStrokeColorRGB(0, 0, 0)
|
||||
canvas.translate(x, y)
|
||||
xblocks = (self.LABELWIDTH-(self.NBBLOCKS*self.BLOCKWIDTH))/2.0
|
||||
for i in range(self.NBBLOCKS) :
|
||||
(font, size) = self.LABELFONT
|
||||
newfont = self.LABELFONT
|
||||
if i == (self.NBBLOCKS - 1) :
|
||||
part = self.label[i:]
|
||||
(font, size) = newfont
|
||||
size /= 2.0
|
||||
newfont = (font, size)
|
||||
else :
|
||||
part = self.label[i]
|
||||
canvas.saveState()
|
||||
canvas.translate(xblocks+(i*self.BLOCKWIDTH), 0)
|
||||
if self.colored and part.isdigit() :
|
||||
canvas.setFillColorRGB(*getattr(colors,
|
||||
self.COLORSCHEME[int(part)],
|
||||
colors.Color(1, 1, 1)).rgb())
|
||||
else:
|
||||
canvas.setFillColorRGB(1, 1, 1)
|
||||
canvas.rect(0, 0, self.BLOCKWIDTH, self.BLOCKHEIGHT, fill=True)
|
||||
canvas.translate((self.BLOCKWIDTH+canvas.stringWidth(part, *newfont))/2.0,
|
||||
(self.BLOCKHEIGHT/2.0))
|
||||
canvas.rotate(90.0)
|
||||
canvas.setFont(*newfont)
|
||||
canvas.setFillColorRGB(0, 0, 0)
|
||||
canvas.drawCentredString(0, 0, part)
|
||||
canvas.restoreState()
|
||||
canvas.restoreState()
|
||||
|
||||
def test() :
|
||||
"""Test this."""
|
||||
from reportlab.pdfgen.canvas import Canvas
|
||||
from reportlab.lib import pagesizes
|
||||
|
||||
canvas = Canvas("labels.pdf", pagesize=pagesizes.A4)
|
||||
canvas.setFont("Helvetica", 30)
|
||||
(width, height) = pagesizes.A4
|
||||
canvas.drawCentredString(width/2.0, height-4*cm, "Sample LTO labels")
|
||||
xpos = xorig = 2 * cm
|
||||
ypos = yorig = 2 * cm
|
||||
colwidth = 10 * cm
|
||||
lineheight = 3.9 * cm
|
||||
count = 1234
|
||||
BaseLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
BaseLTOLabel("RL", count, "3",
|
||||
border=0.0125).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
border=0.0125).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
colored=True).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
border=0.0125, colored=True).drawOn(canvas, xpos, ypos)
|
||||
canvas.showPage()
|
||||
canvas.save()
|
||||
|
||||
if __name__ == "__main__" :
|
||||
test()
|
||||
209
reportlab/graphics/barcode/qr.py
Normal file
209
reportlab/graphics/barcode/qr.py
Normal file
@@ -0,0 +1,209 @@
|
||||
#
|
||||
# ReportLab QRCode widget
|
||||
#
|
||||
# Ported from the Javascript library QRCode for Javascript by Sam Curren
|
||||
#
|
||||
# URL: http://www.d-project.com/
|
||||
# http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js
|
||||
# qrcode.js is copyright (c) 2009 Kazuhiko Arase
|
||||
#
|
||||
# Original ReportLab module by German M. Bravo
|
||||
#
|
||||
# modified and improved by Anders Hammarquist <iko@openend.se>
|
||||
# and used with permission under the ReportLab License
|
||||
#
|
||||
# The word "QR Code" is registered trademark of
|
||||
# DENSO WAVE INCORPORATED
|
||||
# http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
|
||||
__all__ = ('QrCodeWidget')
|
||||
|
||||
import itertools
|
||||
|
||||
from reportlab.platypus.flowables import Flowable
|
||||
from reportlab.graphics.shapes import Group, Rect
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import isNumber, isNumberOrNone, isColor, isString, Validator
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.lib.units import mm
|
||||
try:
|
||||
from reportlab.lib.utils import asUnicodeEx, isUnicode
|
||||
except ImportError:
|
||||
# ReportLab 2.x compatibility
|
||||
def asUnicodeEx(v, enc='utf8'):
|
||||
if isinstance(v, unicode):
|
||||
return v
|
||||
if isinstance(v, str):
|
||||
return v.decode(enc)
|
||||
return str(v).decode(enc)
|
||||
|
||||
def isUnicode(v):
|
||||
return isinstance(v, unicode)
|
||||
|
||||
from reportlab.graphics.barcode import qrencoder
|
||||
|
||||
class isLevel(Validator):
|
||||
def test(self, x):
|
||||
return x in ['L', 'M', 'Q', 'H']
|
||||
isLevel = isLevel()
|
||||
|
||||
class isUnicodeOrQRList(Validator):
|
||||
def _test(self, x):
|
||||
if isUnicode(x):
|
||||
return True
|
||||
if all(isinstance(v, qrencoder.QR) for v in x):
|
||||
return True
|
||||
return False
|
||||
|
||||
def test(self, x):
|
||||
return self._test(x) or self.normalizeTest(x)
|
||||
|
||||
def normalize(self, x):
|
||||
if self._test(x):
|
||||
return x
|
||||
try:
|
||||
return asUnicodeEx(x)
|
||||
except UnicodeError:
|
||||
raise ValueError("Can't convert to unicode: %r" % x)
|
||||
isUnicodeOrQRList = isUnicodeOrQRList()
|
||||
|
||||
class SRect(Rect):
|
||||
def __init__(self, x, y, width, height, fillColor=colors.black):
|
||||
Rect.__init__(self, x, y, width, height, fillColor=fillColor,
|
||||
strokeColor=None, strokeWidth=0)
|
||||
|
||||
class QrCodeWidget(Widget):
|
||||
codeName = "QR"
|
||||
_attrMap = AttrMap(
|
||||
BASE = Widget,
|
||||
value = AttrMapValue(isUnicodeOrQRList, desc='QRCode data'),
|
||||
x = AttrMapValue(isNumber, desc='x-coord'),
|
||||
y = AttrMapValue(isNumber, desc='y-coord'),
|
||||
barFillColor = AttrMapValue(isColor, desc='bar color'),
|
||||
barWidth = AttrMapValue(isNumber, desc='Width of bars.'), # maybe should be named just width?
|
||||
barHeight = AttrMapValue(isNumber, desc='Height of bars.'), # maybe should be named just height?
|
||||
barBorder = AttrMapValue(isNumber, desc='Width of QR border.'), # maybe should be named qrBorder?
|
||||
barLevel = AttrMapValue(isLevel, desc='QR Code level.'), # maybe should be named qrLevel
|
||||
qrVersion = AttrMapValue(isNumberOrNone, desc='QR Code version. None for auto'),
|
||||
# Below are ignored, they make no sense
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'),
|
||||
)
|
||||
x = 0
|
||||
y = 0
|
||||
barFillColor = colors.black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
barHeight = 32*mm
|
||||
barWidth = 32*mm
|
||||
barBorder = 4
|
||||
barLevel = 'L'
|
||||
qrVersion = None
|
||||
value = None
|
||||
|
||||
def __init__(self, value='Hello World', **kw):
|
||||
self.value = isUnicodeOrQRList.normalize(value)
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.barLevel)
|
||||
|
||||
self.__dict__['qr'] = qrencoder.QRCode(self.qrVersion, ec_level)
|
||||
|
||||
if isUnicode(self.value):
|
||||
self.addData(self.value)
|
||||
elif self.value:
|
||||
for v in self.value:
|
||||
self.addData(v)
|
||||
|
||||
def addData(self, value):
|
||||
self.qr.addData(value)
|
||||
|
||||
def draw(self):
|
||||
self.qr.make()
|
||||
|
||||
g = Group()
|
||||
|
||||
color = self.barFillColor
|
||||
border = self.barBorder
|
||||
width = self.barWidth
|
||||
height = self.barHeight
|
||||
x = self.x
|
||||
y = self.y
|
||||
|
||||
g.add(SRect(x, y, width, height, fillColor=None))
|
||||
|
||||
moduleCount = self.qr.getModuleCount()
|
||||
minwh = float(min(width, height))
|
||||
boxsize = minwh / (moduleCount + border * 2.0)
|
||||
offsetX = (width - minwh) / 2.0
|
||||
offsetY = (minwh - height) / 2.0
|
||||
|
||||
for r, row in enumerate(self.qr.modules):
|
||||
row = map(bool, row)
|
||||
c = 0
|
||||
for t, tt in itertools.groupby(row):
|
||||
isDark = t
|
||||
count = len(list(tt))
|
||||
if isDark:
|
||||
x = (c + border) * boxsize
|
||||
y = (r + border + 1) * boxsize
|
||||
s = SRect(offsetX + x, offsetY + height - y, count * boxsize, boxsize)
|
||||
g.add(s)
|
||||
c += count
|
||||
|
||||
return g
|
||||
|
||||
|
||||
# Flowable version
|
||||
|
||||
class QrCode(Flowable):
|
||||
height = 32*mm
|
||||
width = 32*mm
|
||||
qrBorder = 4
|
||||
qrLevel = 'L'
|
||||
qrVersion = None
|
||||
value = None
|
||||
|
||||
def __init__(self, value=None, **kw):
|
||||
self.value = isUnicodeOrQRList.normalize(value)
|
||||
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.qrLevel)
|
||||
|
||||
self.qr = qrencoder.QRCode(self.qrVersion, ec_level)
|
||||
|
||||
if isUnicode(self.value):
|
||||
self.addData(self.value)
|
||||
elif self.value:
|
||||
for v in self.value:
|
||||
self.addData(v)
|
||||
|
||||
def addData(self, value):
|
||||
self.qr.addData(value)
|
||||
|
||||
def draw(self):
|
||||
self.qr.make()
|
||||
|
||||
moduleCount = self.qr.getModuleCount()
|
||||
border = self.qrBorder
|
||||
xsize = self.width / (moduleCount + border * 2.0)
|
||||
ysize = self.height / (moduleCount + border * 2.0)
|
||||
|
||||
for r, row in enumerate(self.qr.modules):
|
||||
row = map(bool, row)
|
||||
c = 0
|
||||
for t, tt in itertools.groupby(row):
|
||||
isDark = t
|
||||
count = len(list(tt))
|
||||
if isDark:
|
||||
x = (c + border) * xsize
|
||||
y = self.height - (r + border + 1) * ysize
|
||||
self.rect(x, y, count * xsize, ysize * 1.05)
|
||||
c += count
|
||||
|
||||
def rect(self, x, y, w, h):
|
||||
self.canv.rect(x, y, w, h, stroke=0, fill=1)
|
||||
1130
reportlab/graphics/barcode/qrencoder.py
Normal file
1130
reportlab/graphics/barcode/qrencoder.py
Normal file
File diff suppressed because it is too large
Load Diff
200
reportlab/graphics/barcode/test.py
Normal file
200
reportlab/graphics/barcode/test.py
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/usr/pkg/bin/python
|
||||
|
||||
import os, sys, time
|
||||
|
||||
from reportlab.graphics.barcode.common import *
|
||||
from reportlab.graphics.barcode.code39 import *
|
||||
from reportlab.graphics.barcode.code93 import *
|
||||
from reportlab.graphics.barcode.code128 import *
|
||||
from reportlab.graphics.barcode.usps import *
|
||||
from reportlab.graphics.barcode.usps4s import USPS_4State
|
||||
|
||||
|
||||
from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, Preformatted, PageBreak
|
||||
from reportlab.lib.units import inch, cm
|
||||
from reportlab.lib import colors
|
||||
|
||||
from reportlab.pdfgen.canvas import Canvas
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.platypus.paragraph import Paragraph
|
||||
from reportlab.platypus.frames import Frame
|
||||
from reportlab.platypus.flowables import XBox, KeepTogether
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
|
||||
from reportlab.graphics.barcode import getCodes, getCodeNames, createBarcodeDrawing, createBarcodeImageInMemory
|
||||
def run():
|
||||
styles = getSampleStyleSheet()
|
||||
styleN = styles['Normal']
|
||||
styleH = styles['Heading1']
|
||||
story = []
|
||||
|
||||
#for codeNames in code
|
||||
story.append(Paragraph('I2of5', styleN))
|
||||
story.append(I2of5(1234, barWidth = inch*0.02, checksum=0))
|
||||
story.append(Paragraph('MSI', styleN))
|
||||
story.append(MSI(1234))
|
||||
story.append(Paragraph('Codabar', styleN))
|
||||
story.append(Codabar("A012345B", barWidth = inch*0.02))
|
||||
story.append(Paragraph('Code 11', styleN))
|
||||
story.append(Code11("01234545634563"))
|
||||
story.append(Paragraph('Code 39', styleN))
|
||||
story.append(Standard39("A012345B%R"))
|
||||
story.append(Paragraph('Extended Code 39', styleN))
|
||||
story.append(Extended39("A012345B}"))
|
||||
story.append(Paragraph('Code93', styleN))
|
||||
story.append(Standard93("CODE 93"))
|
||||
story.append(Paragraph('Extended Code93', styleN))
|
||||
story.append(Extended93("L@@K! Code 93 :-)")) #, barWidth=0.005 * inch))
|
||||
story.append(Paragraph('Code 128', styleN))
|
||||
c=Code128("AB-12345678") #, barWidth=0.005 * inch)
|
||||
#print 'WIDTH =', (c.width / inch), 'barWidth =', (c.barWidth / inch)
|
||||
#print 'LQ =', (c.lquiet / inch), 'RQ =', (c.rquiet / inch)
|
||||
story.append(c)
|
||||
story.append(Paragraph('USPS FIM', styleN))
|
||||
story.append(FIM("A"))
|
||||
story.append(Paragraph('USPS POSTNET', styleN))
|
||||
story.append(POSTNET('78247-1043'))
|
||||
story.append(Paragraph('USPS 4 State', styleN))
|
||||
story.append(USPS_4State('01234567094987654321','01234567891'))
|
||||
|
||||
from reportlab.graphics.barcode import createBarcodeDrawing
|
||||
story.append(Paragraph('EAN13', styleN))
|
||||
bcd = createBarcodeDrawing('EAN13', value='123456789012')
|
||||
story.append(bcd)
|
||||
story.append(Paragraph('EAN8', styleN))
|
||||
bcd = createBarcodeDrawing('EAN8', value='1234567')
|
||||
story.append(bcd)
|
||||
story.append(Paragraph('UPCA', styleN))
|
||||
bcd = createBarcodeDrawing('UPCA', value='03600029145')
|
||||
story.append(bcd)
|
||||
story.append(Paragraph('USPS_4State', styleN))
|
||||
bcd = createBarcodeDrawing('USPS_4State', value='01234567094987654321',routing='01234567891')
|
||||
story.append(bcd)
|
||||
|
||||
story.append(Paragraph('Label Size', styleN))
|
||||
story.append(XBox((2.0 + 5.0/8.0)*inch, 1 * inch, '1x2-5/8"'))
|
||||
story.append(Paragraph('Label Size', styleN))
|
||||
story.append(XBox((1.75)*inch, .5 * inch, '1/2x1-3/4"'))
|
||||
c = Canvas('out.pdf')
|
||||
f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1)
|
||||
f.addFromList(story, c)
|
||||
c.save()
|
||||
print('saved out.pdf')
|
||||
|
||||
def fullTest(fileName="test_full.pdf"):
|
||||
"""Creates large-ish test document with a variety of parameters"""
|
||||
|
||||
story = []
|
||||
|
||||
styles = getSampleStyleSheet()
|
||||
styleN = styles['Normal']
|
||||
styleH = styles['Heading1']
|
||||
styleH2 = styles['Heading2']
|
||||
story = []
|
||||
|
||||
story.append(Paragraph('ReportLab Barcode Test Suite - full output', styleH))
|
||||
story.append(Paragraph('Generated on %s' % time.ctime(time.time()), styleN))
|
||||
|
||||
story.append(Paragraph('', styleN))
|
||||
story.append(Paragraph('Repository information for this build:', styleN))
|
||||
#see if we can figure out where it was built, if we're running in source
|
||||
if os.path.split(os.getcwd())[-1] == 'barcode' and os.path.isdir('.svn'):
|
||||
#runnning in a filesystem svn copy
|
||||
infoLines = os.popen('svn info').read()
|
||||
story.append(Preformatted(infoLines, styles["Code"]))
|
||||
|
||||
story.append(Paragraph('About this document', styleH2))
|
||||
story.append(Paragraph('History and Status', styleH2))
|
||||
|
||||
story.append(Paragraph("""
|
||||
This is the test suite and docoumentation for the ReportLab open source barcode API,
|
||||
being re-released as part of the forthcoming ReportLab 2.0 release.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
Several years ago Ty Sarna contributed a barcode module to the ReportLab community.
|
||||
Several of the codes were used by him in hiw work and to the best of our knowledge
|
||||
this was correct. These were written as flowable objects and were available in PDFs,
|
||||
but not in our graphics framework. However, we had no knowledge of barcodes ourselves
|
||||
and did not advertise or extend the package.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
We "wrapped" the barcodes to be usable within our graphics framework; they are now available
|
||||
as Drawing objects which can be rendered to EPS files or bitmaps. For the last 2 years this
|
||||
has been available in our Diagra and Report Markup Language products. However, we did not
|
||||
charge separately and use was on an "as is" basis.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
A major licensee of our technology has kindly agreed to part-fund proper productisation
|
||||
of this code on an open source basis in Q1 2006. This has involved addition of EAN codes
|
||||
as well as a proper testing program. Henceforth we intend to publicise the code more widely,
|
||||
gather feedback, accept contributions of code and treat it as "supported".
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
This involved making available both downloads and testing resources. This PDF document
|
||||
is the output of the current test suite. It contains codes you can scan (if you use a nice sharp
|
||||
laser printer!), and will be extended over coming weeks to include usage examples and notes on
|
||||
each barcode and how widely tested they are. This is being done through documentation strings in
|
||||
the barcode objects themselves so should always be up to date.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph('Usage examples', styleH2))
|
||||
story.append(Paragraph("""
|
||||
To be completed
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph('The codes', styleH2))
|
||||
story.append(Paragraph("""
|
||||
Below we show a scannable code from each barcode, with and without human-readable text.
|
||||
These are magnified about 2x from the natural size done by the original author to aid
|
||||
inspection. This will be expanded to include several test cases per code, and to add
|
||||
explanations of checksums. Be aware that (a) if you enter numeric codes which are too
|
||||
short they may be prefixed for you (e.g. "123" for an 8-digit code becomes "00000123"),
|
||||
and that the scanned results and readable text will generally include extra checksums
|
||||
at the end.
|
||||
""", styleN))
|
||||
|
||||
codeNames = getCodeNames()
|
||||
from reportlab.lib.utils import flatten
|
||||
width = [float(x[8:]) for x in sys.argv if x.startswith('--width=')]
|
||||
height = [float(x[9:]) for x in sys.argv if x.startswith('--height=')]
|
||||
isoScale = [int(x[11:]) for x in sys.argv if x.startswith('--isoscale=')]
|
||||
options = {}
|
||||
if width: options['width'] = width[0]
|
||||
if height: options['height'] = height[0]
|
||||
if isoScale: options['isoScale'] = isoScale[0]
|
||||
scales = [x[8:].split(',') for x in sys.argv if x.startswith('--scale=')]
|
||||
scales = list(map(float,scales and flatten(scales) or [1]))
|
||||
scales = list(map(float,scales and flatten(scales) or [1]))
|
||||
for scale in scales:
|
||||
story.append(PageBreak())
|
||||
story.append(Paragraph('Scale = %.1f'%scale, styleH2))
|
||||
story.append(Spacer(36, 12))
|
||||
for codeName in codeNames:
|
||||
s = [Paragraph('Code: ' + codeName, styleH2)]
|
||||
for hr in (0,1):
|
||||
s.append(Spacer(36, 12))
|
||||
dr = createBarcodeDrawing(codeName, humanReadable=hr,**options)
|
||||
dr.renderScale = scale
|
||||
s.append(dr)
|
||||
s.append(Spacer(36, 12))
|
||||
s.append(Paragraph('Barcode should say: ' + dr._bc.value, styleN))
|
||||
story.append(KeepTogether(s))
|
||||
|
||||
SimpleDocTemplate(fileName).build(story)
|
||||
print('created', fileName)
|
||||
|
||||
if __name__=='__main__':
|
||||
run()
|
||||
fullTest()
|
||||
def createSample(name,memory):
|
||||
f = open(name,'wb')
|
||||
f.write(memory)
|
||||
f.close()
|
||||
createSample('test_cbcim.png',createBarcodeImageInMemory('EAN13', value='123456789012'))
|
||||
createSample('test_cbcim.gif',createBarcodeImageInMemory('EAN8', value='1234567', format='gif'))
|
||||
createSample('test_cbcim.pdf',createBarcodeImageInMemory('UPCA', value='03600029145',format='pdf'))
|
||||
createSample('test_cbcim.tiff',createBarcodeImageInMemory('USPS_4State', value='01234567094987654321',routing='01234567891',format='tiff'))
|
||||
232
reportlab/graphics/barcode/usps.py
Normal file
232
reportlab/graphics/barcode/usps.py
Normal file
@@ -0,0 +1,232 @@
|
||||
#
|
||||
# Copyright (c) 1996-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.graphics.barcode.common import Barcode
|
||||
from string import digits as string_digits, whitespace as string_whitespace
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
_fim_patterns = {
|
||||
'A' : "|| | ||",
|
||||
'B' : "| || || |",
|
||||
'C' : "|| | | ||",
|
||||
'D' : "||| | |||",
|
||||
# XXX There is an E.
|
||||
# The below has been seen, but dunno if it is E or not:
|
||||
# 'E' : '|||| ||||'
|
||||
}
|
||||
|
||||
_postnet_patterns = {
|
||||
'1' : "...||", '2' : "..|.|", '3' : "..||.", '4' : ".|..|",
|
||||
'5' : ".|.|.", '6' : ".||..", '7' : "|...|", '8' : "|..|.",
|
||||
'9' : "|.|..", '0' : "||...", 'S' : "|",
|
||||
}
|
||||
|
||||
class FIM(Barcode):
|
||||
"""
|
||||
FIM (Facing ID Marks) encode only one letter.
|
||||
There are currently four defined:
|
||||
|
||||
A Courtesy reply mail with pre-printed POSTNET
|
||||
B Business reply mail without pre-printed POSTNET
|
||||
C Business reply mail with pre-printed POSTNET
|
||||
D OCR Readable mail without pre-printed POSTNET
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (single character string from the set A - D. required.):
|
||||
The value to encode.
|
||||
|
||||
quiet (bool, default 0):
|
||||
Whether to include quiet zones in the symbol.
|
||||
|
||||
The following may also be passed, but doing so will generate nonstandard
|
||||
symbols which should not be used. This is mainly documented here to
|
||||
show the defaults:
|
||||
|
||||
barHeight (float, default 5/8 inch):
|
||||
Height of the code. This might legitimately be overriden to make
|
||||
a taller symbol that will 'bleed' off the edge of the paper,
|
||||
leaving 5/8 inch remaining.
|
||||
|
||||
lquiet (float, default 1/4 inch):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, default 15/32 inch):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
Sources of information on FIM:
|
||||
|
||||
USPS Publication 25, A Guide to Business Mail Preparation
|
||||
http://new.usps.com/cpim/ftp/pubs/pub25.pdf
|
||||
"""
|
||||
barWidth = inch * (1.0/32.0)
|
||||
spaceWidth = inch * (1.0/16.0)
|
||||
barHeight = inch * (5.0/8.0)
|
||||
rquiet = inch * (0.25)
|
||||
lquiet = inch * (15.0/32.0)
|
||||
quiet = 0
|
||||
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)
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
self.valid = 1
|
||||
self.validated = ''
|
||||
for c in self.value:
|
||||
if c in string_whitespace:
|
||||
continue
|
||||
elif c in "abcdABCD":
|
||||
self.validated = self.validated + c.upper()
|
||||
else:
|
||||
self.valid = 0
|
||||
|
||||
if len(self.validated) != 1:
|
||||
raise ValueError("Input must be exactly one character")
|
||||
|
||||
return self.validated
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''
|
||||
for c in self.encoded:
|
||||
self.decomposed = self.decomposed + _fim_patterns[c]
|
||||
|
||||
return self.decomposed
|
||||
|
||||
def computeSize(self):
|
||||
self._width = (len(self.decomposed) - 1) * self.spaceWidth + self.barWidth
|
||||
if self.quiet:
|
||||
self._width += self.lquiet + self.rquiet
|
||||
self._height = self.barHeight
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
left = self.quiet and self.lquiet or 0
|
||||
for c in self.decomposed:
|
||||
if c == '|':
|
||||
self.rect(left, 0.0, self.barWidth, self.barHeight)
|
||||
left += self.spaceWidth
|
||||
self.drawHumanReadable()
|
||||
|
||||
def _humanText(self):
|
||||
return self.value
|
||||
|
||||
class POSTNET(Barcode):
|
||||
"""
|
||||
POSTNET is used in the US to encode "zip codes" (postal codes) on
|
||||
mail. It can encode 5, 9, or 11 digit codes. I've read that it's
|
||||
pointless to do 5 digits, since USPS will just have to re-print
|
||||
them with 9 or 11 digits.
|
||||
|
||||
Sources of information on POSTNET:
|
||||
|
||||
USPS Publication 25, A Guide to Business Mail Preparation
|
||||
http://new.usps.com/cpim/ftp/pubs/pub25.pdf
|
||||
"""
|
||||
quiet = 0
|
||||
shortHeight = inch * 0.050
|
||||
barHeight = inch * 0.125
|
||||
barWidth = inch * 0.018
|
||||
spaceWidth = inch * 0.0275
|
||||
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)
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
self.validated = ''
|
||||
self.valid = 1
|
||||
count = 0
|
||||
for c in self.value:
|
||||
if c in (string_whitespace + '-'):
|
||||
pass
|
||||
elif c in string_digits:
|
||||
count = count + 1
|
||||
if count == 6:
|
||||
self.validated = self.validated + '-'
|
||||
self.validated = self.validated + c
|
||||
else:
|
||||
self.valid = 0
|
||||
|
||||
if len(self.validated) not in [5, 10, 12]:
|
||||
self.valid = 0
|
||||
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = "S"
|
||||
check = 0
|
||||
for c in self.validated:
|
||||
if c in string_digits:
|
||||
self.encoded = self.encoded + c
|
||||
check = check + int(c)
|
||||
elif c == '-':
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Invalid character in input")
|
||||
check = (10 - check) % 10
|
||||
self.encoded = self.encoded + repr(check) + 'S'
|
||||
return self.encoded
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''
|
||||
for c in self.encoded:
|
||||
self.decomposed = self.decomposed + _postnet_patterns[c]
|
||||
return self.decomposed
|
||||
|
||||
def computeSize(self):
|
||||
self._width = len(self.decomposed) * self.barWidth + (len(self.decomposed) - 1) * self.spaceWidth
|
||||
self._height = self.barHeight
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
sdown = self.barHeight - self.shortHeight
|
||||
left = 0
|
||||
|
||||
for c in self.decomposed:
|
||||
if c == '.':
|
||||
h = self.shortHeight
|
||||
else:
|
||||
h = self.barHeight
|
||||
self.rect(left, 0.0, self.barWidth, h)
|
||||
left = left + self.barWidth + self.spaceWidth
|
||||
self.drawHumanReadable()
|
||||
|
||||
def _humanText(self):
|
||||
return self.encoded[1:-1]
|
||||
386
reportlab/graphics/barcode/usps4s.py
Normal file
386
reportlab/graphics/barcode/usps4s.py
Normal file
@@ -0,0 +1,386 @@
|
||||
#copyright ReportLab Inc. 2000-2012
|
||||
#see license.txt for license details
|
||||
__version__=''' $Id$ '''
|
||||
__all__ = ('USPS_4State',)
|
||||
|
||||
from reportlab.lib.colors import black
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
class USPS_4State(Barcode):
|
||||
''' USPS 4-State OneView (TM) barcode. All info from USPS-B-3200A
|
||||
'''
|
||||
_widthSize = 1
|
||||
_heightSize = 1
|
||||
_fontSize = 11
|
||||
_humanReadable = 0
|
||||
tops = dict(
|
||||
F = (0.067,0.115),
|
||||
T = (0.021,0.040),
|
||||
A = (0.067,0.115),
|
||||
D = (0.021,0.040),
|
||||
)
|
||||
bottoms = dict(
|
||||
F = (-0.067,-0.115),
|
||||
D = (-0.067,-0.115),
|
||||
T = (-0.021,-0.040),
|
||||
A = (-0.021,-0.040),
|
||||
)
|
||||
dimensions = dict(
|
||||
width = (0.015, 0.025),
|
||||
pitch = (0.0416,0.050),
|
||||
hcz = (0.125,0.125),
|
||||
vcz = (0.040,0.040),
|
||||
)
|
||||
|
||||
def __init__(self,value='01234567094987654321',routing='',**kwd):
|
||||
self._init()
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
self._tracking = value
|
||||
self._routing = routing
|
||||
self._setKeywords(**kwd)
|
||||
|
||||
def _init(self):
|
||||
self._bvalue = None
|
||||
self._codewords = None
|
||||
self._characters = None
|
||||
self._barcodes = None
|
||||
|
||||
def scale(kind,D,s):
|
||||
V = D[kind]
|
||||
return 72*(V[0]*(1-s)+s*V[1])
|
||||
scale = staticmethod(scale)
|
||||
|
||||
def tracking(self,tracking):
|
||||
self._init()
|
||||
self._tracking = tracking
|
||||
tracking = property(lambda self: self._tracking,tracking)
|
||||
|
||||
def routing(self,routing):
|
||||
self._init()
|
||||
self._routing = routing
|
||||
routing = property(lambda self: self._routing,routing)
|
||||
|
||||
def widthSize(self,value):
|
||||
self._sized = None
|
||||
self._widthSize = value
|
||||
widthSize = property(lambda self: self._widthSize,widthSize)
|
||||
|
||||
def heightSize(self,value):
|
||||
self._sized = None
|
||||
self._heightSize = value
|
||||
heightSize = property(lambda self: self._heightSize,heightSize)
|
||||
|
||||
def fontSize(self,value):
|
||||
self._sized = None
|
||||
self._fontSize = value
|
||||
fontSize = property(lambda self: self._fontSize,fontSize)
|
||||
|
||||
def humanReadable(self,value):
|
||||
self._sized = None
|
||||
self._humanReadable = value
|
||||
humanReadable = property(lambda self: self._humanReadable,humanReadable)
|
||||
|
||||
def binary(self):
|
||||
'''convert the 4 state string values to binary
|
||||
>>> print hex(USPS_4State('01234567094987654321','').binary)
|
||||
0x1122103B5C2004B1L
|
||||
>>> print hex(USPS_4State('01234567094987654321','01234').binary)
|
||||
0xD138A87BAB5CF3804B1L
|
||||
>>> print hex(USPS_4State('01234567094987654321','012345678').binary)
|
||||
0x202BDC097711204D21804B1L
|
||||
>>> print hex(USPS_4State('01234567094987654321','01234567891').binary)
|
||||
0x16907B2A24ABC16A2E5C004B1L
|
||||
'''
|
||||
value = self._bvalue
|
||||
if not value:
|
||||
routing = self.routing
|
||||
n = len(routing)
|
||||
try:
|
||||
if n==0:
|
||||
value = 0
|
||||
elif n==5:
|
||||
value = int(routing)+1
|
||||
elif n==9:
|
||||
value = int(routing)+100001
|
||||
elif n==11:
|
||||
value = int(routing)+1000100001
|
||||
else:
|
||||
raise ValueError
|
||||
except:
|
||||
raise ValueError('Problem converting %s, routing code must be 0, 5, 9 or 11 digits' % routing)
|
||||
|
||||
tracking = self.tracking
|
||||
svalue = tracking[0:2]
|
||||
try:
|
||||
value *= 10
|
||||
value += int(svalue[0])
|
||||
value *= 5
|
||||
value += int(svalue[1])
|
||||
except:
|
||||
raise ValueError('Problem converting %s, barcode identifier must be 2 digits' % svalue)
|
||||
|
||||
i = 2
|
||||
for name,nd in (('special services',3), ('customer identifier',6), ('sequence number',9)):
|
||||
j = i
|
||||
i += nd
|
||||
svalue = tracking[j:i]
|
||||
try:
|
||||
if len(svalue)!=nd: raise ValueError
|
||||
for j in range(nd):
|
||||
value *= 10
|
||||
value += int(svalue[j])
|
||||
except:
|
||||
raise ValueError('Problem converting %s, %s must be %d digits' % (svalue,name,nd))
|
||||
self._bvalue = value
|
||||
return value
|
||||
binary = property(binary)
|
||||
|
||||
def codewords(self):
|
||||
'''convert binary value into codewords
|
||||
>>> print USPS_4State('01234567094987654321','01234567891').codewords)
|
||||
(673, 787, 607, 1022, 861, 19, 816, 1294, 35, 602)
|
||||
'''
|
||||
if not self._codewords:
|
||||
value = self.binary
|
||||
A, J = divmod(value,636)
|
||||
A, I = divmod(A,1365)
|
||||
A, H = divmod(A,1365)
|
||||
A, G = divmod(A,1365)
|
||||
A, F = divmod(A,1365)
|
||||
A, E = divmod(A,1365)
|
||||
A, D = divmod(A,1365)
|
||||
A, C = divmod(A,1365)
|
||||
A, B = divmod(A,1365)
|
||||
assert 0<=A<=658, 'improper value %s passed to _2codewords A-->%s' % (hex(int(value)),A)
|
||||
self._fcs = _crc11(value)
|
||||
if self._fcs&1024: A += 659
|
||||
J *= 2
|
||||
self._codewords = tuple(map(int,(A,B,C,D,E,F,G,H,I,J)))
|
||||
return self._codewords
|
||||
codewords = property(codewords)
|
||||
|
||||
|
||||
def table1(self):
|
||||
self.__class__.table1 = _initNof13Table(5,1287)
|
||||
return self.__class__.table1
|
||||
table1 = property(table1)
|
||||
|
||||
def table2(self):
|
||||
self.__class__.table2 = _initNof13Table(2,78)
|
||||
return self.__class__.table2
|
||||
table2 = property(table2)
|
||||
|
||||
def characters(self):
|
||||
''' convert own codewords to characters
|
||||
>>> print ' '.join(hex(c)[2:] for c in USPS_4State('01234567094987654321','01234567891').characters)
|
||||
dcb 85c 8e4 b06 6dd 1740 17c6 1200 123f 1b2b
|
||||
'''
|
||||
if not self._characters:
|
||||
codewords = self.codewords
|
||||
fcs = self._fcs
|
||||
C = []
|
||||
aC = C.append
|
||||
table1 = self.table1
|
||||
table2 = self.table2
|
||||
for i in range(10):
|
||||
cw = codewords[i]
|
||||
if cw<=1286:
|
||||
c = table1[cw]
|
||||
else:
|
||||
c = table2[cw-1287]
|
||||
if (fcs>>i)&1:
|
||||
c = ~c & 0x1fff
|
||||
aC(c)
|
||||
self._characters = tuple(C)
|
||||
return self._characters
|
||||
characters = property(characters)
|
||||
|
||||
def barcodes(self):
|
||||
'''Get 4 state bar codes for current routing and tracking
|
||||
>>> print USPS_4State('01234567094987654321','01234567891').barcodes
|
||||
AADTFFDFTDADTAADAATFDTDDAAADDTDTTDAFADADDDTFFFDDTTTADFAAADFTDAADA
|
||||
'''
|
||||
if not self._barcodes:
|
||||
C = self.characters
|
||||
B = []
|
||||
aB = B.append
|
||||
bits2bars = self._bits2bars
|
||||
for dc,db,ac,ab in self.table4:
|
||||
aB(bits2bars[((C[dc]>>db)&1)+2*((C[ac]>>ab)&1)])
|
||||
self._barcodes = ''.join(B)
|
||||
return self._barcodes
|
||||
barcodes = property(barcodes)
|
||||
|
||||
table4 = ((7, 2, 4, 3), (1, 10, 0, 0), (9, 12, 2, 8), (5, 5, 6, 11),
|
||||
(8, 9, 3, 1), (0, 1, 5, 12), (2, 5, 1, 8), (4, 4, 9, 11),
|
||||
(6, 3, 8, 10), (3, 9, 7, 6), (5, 11, 1, 4), (8, 5, 2, 12),
|
||||
(9, 10, 0, 2), (7, 1, 6, 7), (3, 6, 4, 9), (0, 3, 8, 6),
|
||||
(6, 4, 2, 7), (1, 1, 9, 9), (7, 10, 5, 2), (4, 0, 3, 8),
|
||||
(6, 2, 0, 4), (8, 11, 1, 0), (9, 8, 3, 12), (2, 6, 7, 7),
|
||||
(5, 1, 4, 10), (1, 12, 6, 9), (7, 3, 8, 0), (5, 8, 9, 7),
|
||||
(4, 6, 2, 10), (3, 4, 0, 5), (8, 4, 5, 7), (7, 11, 1, 9),
|
||||
(6, 0, 9, 6), (0, 6, 4, 8), (2, 1, 3, 2), (5, 9, 8, 12),
|
||||
(4, 11, 6, 1), (9, 5, 7, 4), (3, 3, 1, 2), (0, 7, 2, 0),
|
||||
(1, 3, 4, 1), (6, 10, 3, 5), (8, 7, 9, 4), (2, 11, 5, 6),
|
||||
(0, 8, 7, 12), (4, 2, 8, 1), (5, 10, 3, 0), (9, 3, 0, 9),
|
||||
(6, 5, 2, 4), (7, 8, 1, 7), (5, 0, 4, 5), (2, 3, 0, 10),
|
||||
(6, 12, 9, 2), (3, 11, 1, 6), (8, 8, 7, 9), (5, 4, 0, 11),
|
||||
(1, 5, 2, 2), (9, 1, 4, 12), (8, 3, 6, 6), (7, 0, 3, 7),
|
||||
(4, 7, 7, 5), (0, 12, 1, 11), (2, 9, 9, 0), (6, 8, 5, 3),
|
||||
(3, 10, 8, 2))
|
||||
|
||||
_bits2bars = 'T','D','A','F'
|
||||
horizontalClearZone = property(lambda self: self.scale('hcz',self.dimensions,self.widthScale))
|
||||
verticalClearZone = property(lambda self: self.scale('vcz',self.dimensions,self.heightScale))
|
||||
pitch = property(lambda self: self.scale('pitch',self.dimensions,self.widthScale))
|
||||
barWidth = property(lambda self: self.scale('width',self.dimensions,self.widthScale))
|
||||
barHeight = property(lambda self: self.scale('F',self.tops,self.heightScale) - self.scale('F',self.bottoms,self.heightScale))
|
||||
widthScale = property(lambda self: min(1,max(0,self.widthSize)))
|
||||
heightScale = property(lambda self: min(1,max(0,self.heightSize)))
|
||||
|
||||
def width(self):
|
||||
self.computeSize()
|
||||
return self._width
|
||||
width = property(width)
|
||||
|
||||
def height(self):
|
||||
self.computeSize()
|
||||
return self._height
|
||||
height = property(height)
|
||||
|
||||
def computeSize(self):
|
||||
if not getattr(self,'_sized',None):
|
||||
ws = self.widthScale
|
||||
hs = self.heightScale
|
||||
barHeight = self.barHeight
|
||||
barWidth = self.barWidth
|
||||
pitch = self.pitch
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
self._width = 2*hcz + barWidth + 64*pitch
|
||||
self._height = 2*vcz+barHeight
|
||||
if self.humanReadable:
|
||||
self._height += self.fontSize*1.2+vcz
|
||||
self._sized = True
|
||||
|
||||
def wrap(self,aW,aH):
|
||||
self.computeSize()
|
||||
return self.width, self.height
|
||||
|
||||
def _getBarVInfo(self,y0=0):
|
||||
vInfo = {}
|
||||
hs = self.heightScale
|
||||
for b in ('T','D','A','F'):
|
||||
y = self.scale(b,self.bottoms,hs)+y0
|
||||
vInfo[b] = y,self.scale(b,self.tops,hs)+y0 - y
|
||||
return vInfo
|
||||
|
||||
def draw(self):
|
||||
self.computeSize()
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
bw = self.barWidth
|
||||
x = hcz
|
||||
y0 = vcz+self.barHeight*0.5
|
||||
dw = self.pitch
|
||||
vInfo = self._getBarVInfo(y0)
|
||||
for b in self.barcodes:
|
||||
yb, hb = vInfo[b]
|
||||
self.rect(x,yb,bw,hb)
|
||||
x += dw
|
||||
self.drawHumanReadable()
|
||||
|
||||
def value(self):
|
||||
tracking = self.tracking
|
||||
routing = self.routing
|
||||
routing = routing and (routing,) or ()
|
||||
return ' '.join((tracking[0:2],tracking[2:5],tracking[5:11],tracking[11:])+routing)
|
||||
value = property(value,lambda self,value: self.__dict__.__setitem__('tracking',value))
|
||||
|
||||
def drawHumanReadable(self):
|
||||
if self.humanReadable:
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
fontName = self.fontName
|
||||
fontSize = self.fontSize
|
||||
y = self.barHeight+2*vcz+0.2*fontSize
|
||||
self.annotate(hcz,y,self.value,fontName,fontSize)
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
Barcode.annotate(self,x,y,text,fontName,fontSize,anchor='start')
|
||||
|
||||
def _crc11(value):
|
||||
'''
|
||||
>>> print ' '.join(hex(_crc11(USPS_4State('01234567094987654321',x).binary)) for x in ('','01234','012345678','01234567891'))
|
||||
0x51 0x65 0x606 0x751
|
||||
'''
|
||||
bytes = hex(int(value))[2:-1]
|
||||
bytes = '0'*(26-len(bytes))+bytes
|
||||
gp = 0x0F35
|
||||
fcs = 0x07FF
|
||||
data = int(bytes[:2],16)<<5
|
||||
for b in range(2,8):
|
||||
if (fcs ^ data)&0x400:
|
||||
fcs = (fcs<<1)^gp
|
||||
else:
|
||||
fcs = fcs<<1
|
||||
fcs &= 0x7ff
|
||||
data <<= 1
|
||||
|
||||
for x in range(2,2*13,2):
|
||||
data = int(bytes[x:x+2],16)<<3
|
||||
for b in range(8):
|
||||
if (fcs ^ data)&0x400:
|
||||
fcs = (fcs<<1)^gp
|
||||
else:
|
||||
fcs = fcs<<1
|
||||
fcs &= 0x7ff
|
||||
data <<= 1
|
||||
return fcs
|
||||
|
||||
def _ru13(i):
|
||||
'''reverse unsigned 13 bit number
|
||||
>>> print _ru13(7936), _ru13(31), _ru13(47), _ru13(7808)
|
||||
31 7936 7808 47
|
||||
'''
|
||||
r = 0
|
||||
for x in range(13):
|
||||
r <<= 1
|
||||
r |= i & 1
|
||||
i >>= 1
|
||||
return r
|
||||
|
||||
def _initNof13Table(N,lenT):
|
||||
'''create and return table of 13 bit values with N bits on
|
||||
>>> T = _initNof13Table(5,1287)
|
||||
>>> print ' '.join('T[%d]=%d' % (i, T[i]) for i in (0,1,2,3,4,1271,1272,1284,1285,1286))
|
||||
T[0]=31 T[1]=7936 T[2]=47 T[3]=7808 T[4]=55 T[1271]=6275 T[1272]=6211 T[1284]=856 T[1285]=744 T[1286]=496
|
||||
'''
|
||||
T = lenT*[None]
|
||||
l = 0
|
||||
u = lenT-1
|
||||
for c in range(8192):
|
||||
bc = 0
|
||||
for b in range(13):
|
||||
bc += (c&(1<<b))!=0
|
||||
if bc!=N: continue
|
||||
r = _ru13(c)
|
||||
if r<c: continue #we already looked at this pair
|
||||
if r==c:
|
||||
T[u] = c
|
||||
u -= 1
|
||||
else:
|
||||
T[l] = c
|
||||
l += 1
|
||||
T[l] = r
|
||||
l += 1
|
||||
assert l==(u+1), 'u+1(%d)!=l(%d) for %d of 13 table' % (u+1,l,N)
|
||||
return T
|
||||
|
||||
def _test():
|
||||
import doctest
|
||||
return doctest.testmod()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
307
reportlab/graphics/barcode/widgets.py
Normal file
307
reportlab/graphics/barcode/widgets.py
Normal file
@@ -0,0 +1,307 @@
|
||||
#copyright ReportLab Europe Limited. 2000-2012
|
||||
#see license.txt for license details
|
||||
__version__=''' $Id$ '''
|
||||
__all__= (
|
||||
'BarcodeI2of5',
|
||||
'BarcodeCode128',
|
||||
'BarcodeStandard93',
|
||||
'BarcodeExtended93',
|
||||
'BarcodeStandard39',
|
||||
'BarcodeExtended39',
|
||||
'BarcodeMSI',
|
||||
'BarcodeCodabar',
|
||||
'BarcodeCode11',
|
||||
'BarcodeFIM',
|
||||
'BarcodePOSTNET',
|
||||
'BarcodeUSPS_4State',
|
||||
)
|
||||
|
||||
from reportlab.lib.validators import isInt, isNumber, isColor, isString, isColorOrNone, OneOf, isBoolean, EitherOr, isNumberOrNone
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.lib.colors import black
|
||||
from reportlab.lib.utils import rl_exec
|
||||
from reportlab.graphics.shapes import Line, Rect, Group, NotImplementedError, String
|
||||
from reportlab.graphics.charts.areas import PlotArea
|
||||
|
||||
'''
|
||||
#snippet
|
||||
|
||||
#first make your Drawing
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
d= Drawing(100,50)
|
||||
|
||||
#create and set up the widget
|
||||
from reportlab.graphics.barcode.widgets import BarcodeStandard93
|
||||
bc = BarcodeStandard93()
|
||||
bc.value = 'RGB-123456'
|
||||
|
||||
#add to the drawing and save
|
||||
d.add(bc)
|
||||
# d.save(formats=['gif','pict'],fnRoot='bc_sample')
|
||||
'''
|
||||
|
||||
class _BarcodeWidget(PlotArea):
|
||||
_attrMap = AttrMap(BASE=PlotArea,
|
||||
barStrokeColor = AttrMapValue(isColorOrNone, desc='Color of bar borders.'),
|
||||
barFillColor = AttrMapValue(isColorOrNone, desc='Color of bar interior areas.'),
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
value = AttrMapValue(EitherOr((isString,isNumber)), desc='Value.'),
|
||||
textColor = AttrMapValue(isColorOrNone, desc='Color of human readable text.'),
|
||||
valid = AttrMapValue(isBoolean),
|
||||
validated = AttrMapValue(isString,desc="validated form of input"),
|
||||
encoded = AttrMapValue(None,desc="encoded form of input"),
|
||||
decomposed = AttrMapValue(isString,desc="decomposed form of input"),
|
||||
canv = AttrMapValue(None,desc="temporarily used for internal methods"),
|
||||
gap = AttrMapValue(isNumberOrNone, desc='Width of inter character gaps.'),
|
||||
)
|
||||
|
||||
textColor = barFillColor = black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
_BCC = None
|
||||
def __init__(self,_value='',**kw):
|
||||
PlotArea.__init__(self)
|
||||
del self.__dict__['width']
|
||||
del self.__dict__['height']
|
||||
self.x = self.y = 0
|
||||
kw.setdefault('value',_value)
|
||||
self._BCC.__init__(self,**kw)
|
||||
|
||||
def rect(self,x,y,w,h,**kw):
|
||||
self._Gadd(Rect(self.x+x,self.y+y,w,h,
|
||||
strokeColor=self.barStrokeColor,strokeWidth=self.barStrokeWidth, fillColor=self.barFillColor))
|
||||
|
||||
def draw(self):
|
||||
if not self._BCC: raise NotImplementedError("Abstract class %s cannot be drawn" % self.__class__.__name__)
|
||||
self.canv = self
|
||||
G = Group()
|
||||
self._Gadd = G.add
|
||||
self._Gadd(Rect(self.x,self.y,self.width,self.height,fillColor=None,strokeColor=None,strokeWidth=0.0001))
|
||||
self._BCC.draw(self)
|
||||
del self.canv, self._Gadd
|
||||
return G
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
self._Gadd(String(self.x+x,self.y+y,text,fontName=fontName,fontSize=fontSize,
|
||||
textAnchor=anchor,fillColor=self.textColor))
|
||||
|
||||
def _BCW(doc,codeName,attrMap,mod,value,**kwds):
|
||||
"""factory for Barcode Widgets"""
|
||||
_pre_init = kwds.pop('_pre_init','')
|
||||
_methods = kwds.pop('_methods','')
|
||||
name = 'Barcode'+codeName
|
||||
ns = vars().copy()
|
||||
code = 'from %s import %s' % (mod,codeName)
|
||||
rl_exec(code,ns)
|
||||
ns['_BarcodeWidget'] = _BarcodeWidget
|
||||
code = '''class %(name)s(_BarcodeWidget,%(codeName)s):
|
||||
\t_BCC = %(codeName)s
|
||||
\tcodeName = %(codeName)r
|
||||
\tdef __init__(self,**kw):%(_pre_init)s
|
||||
\t\t_BarcodeWidget.__init__(self,%(value)r,**kw)%(_methods)s''' % ns
|
||||
rl_exec(code,ns)
|
||||
Klass = ns[name]
|
||||
if attrMap: Klass._attrMap = attrMap
|
||||
if doc: Klass.__doc__ = doc
|
||||
for k, v in kwds.items():
|
||||
setattr(Klass,k,v)
|
||||
return Klass
|
||||
|
||||
BarcodeI2of5 = _BCW(
|
||||
"""Interleaved 2 of 5 is used in distribution and warehouse industries.
|
||||
|
||||
It encodes an even-numbered sequence of numeric digits. There is an optional
|
||||
module 10 check digit; if including this, the total length must be odd so that
|
||||
it becomes even after including the check digit. Otherwise the length must be
|
||||
even. Since the check digit is optional, our library does not check it.
|
||||
""",
|
||||
"I2of5",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).'''),
|
||||
ratio = AttrMapValue(isNumber,'''(float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))'''),
|
||||
gap = AttrMapValue(isNumberOrNone,'''(float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(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.'''),
|
||||
checksum = AttrMapValue(isBoolean,'''(bool, default 1):
|
||||
Whether to compute and include the check digit'''),
|
||||
bearers = AttrMapValue(isNumber,'''(float, in units of barWidth. default 3.0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 3 x-dimensions.
|
||||
Set to zero for no bearer bars. (Bearer bars help detect
|
||||
misscans, so it is suggested to leave them on).'''),
|
||||
quiet = AttrMapValue(isBoolean,'''(bool, default 1):
|
||||
Whether to include quiet zones in the symbol.'''),
|
||||
|
||||
lquiet = AttrMapValue(isNumber,'''(float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.'''),
|
||||
|
||||
rquiet = AttrMapValue(isNumber,'''(float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.common',
|
||||
1234,
|
||||
_tests = [
|
||||
'12',
|
||||
'1234',
|
||||
'123456',
|
||||
'12345678',
|
||||
'1234567890'
|
||||
],
|
||||
)
|
||||
|
||||
BarcodeCode128 = _BCW("""Code 128 encodes any number of characters in the ASCII character set.""",
|
||||
"Code128",
|
||||
AttrMap(BASE=BarcodeI2of5,UNWANTED=('bearers','checksum','ratio','checksum','stop')),
|
||||
'reportlab.graphics.barcode.code128',
|
||||
"AB-12345678",
|
||||
_tests = ['ReportLab Rocks!', 'PFWZF'],
|
||||
)
|
||||
|
||||
BarcodeStandard93=_BCW("""This is a compressed form of Code 39""",
|
||||
"Standard93",
|
||||
AttrMap(BASE=BarcodeCode128,
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.code93',
|
||||
"CODE 93",
|
||||
)
|
||||
|
||||
BarcodeExtended93=_BCW("""This is a compressed form of Code 39, allowing the full ASCII charset""",
|
||||
"Extended93",
|
||||
AttrMap(BASE=BarcodeCode128,
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.code93',
|
||||
"L@@K! Code 93 ;-)",
|
||||
)
|
||||
|
||||
BarcodeStandard39=_BCW("""Code39 is widely used in non-retail, especially US defence and health.
|
||||
Allowed characters are 0-9, A-Z (caps only), space, and -.$/+%*.""",
|
||||
"Standard39",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.code39',
|
||||
"A012345B%R",
|
||||
)
|
||||
|
||||
BarcodeExtended39=_BCW("""Extended 39 encodes the full ASCII character set by encoding
|
||||
characters as pairs of Code 39 characters; $, /, % and + are used as
|
||||
shift characters.""",
|
||||
"Extended39",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.code39',
|
||||
"A012345B}",
|
||||
)
|
||||
|
||||
BarcodeMSI=_BCW("""MSI is used for inventory control in retail applications.
|
||||
|
||||
There are several methods for calculating check digits so we
|
||||
do not implement one.
|
||||
""",
|
||||
"MSI",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.common',
|
||||
1234,
|
||||
)
|
||||
|
||||
BarcodeCodabar=_BCW("""Used in blood banks, photo labs and FedEx labels.
|
||||
Encodes 0-9, -$:/.+, and four start/stop characters A-D.""",
|
||||
"Codabar",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.common',
|
||||
"A012345B",
|
||||
)
|
||||
|
||||
BarcodeCode11=_BCW("""Used mostly for labelling telecommunications equipment.
|
||||
It encodes numeric digits.""",
|
||||
'Code11',
|
||||
AttrMap(BASE=BarcodeI2of5,
|
||||
checksum = AttrMapValue(isInt,'''(integer, default 2):
|
||||
Whether to compute and include the check digit(s).
|
||||
(0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
|
||||
How many checksum digits to include. -1 ("auto") means
|
||||
1 if the number of digits is 10 or less, else 2.'''),
|
||||
),
|
||||
'reportlab.graphics.barcode.common',
|
||||
"01234545634563",
|
||||
)
|
||||
|
||||
BarcodeFIM=_BCW("""
|
||||
FIM was developed as part of the POSTNET barcoding system.
|
||||
FIM (Face Identification Marking) is used by the cancelling machines
|
||||
to sort mail according to whether or not they have bar code
|
||||
and their postage requirements. There are four types of FIM
|
||||
called FIM A, FIM B, FIM C, and FIM D.
|
||||
|
||||
The four FIM types have the following meanings:
|
||||
FIM A- Postage required pre-barcoded
|
||||
FIM B - Postage pre-paid, no bar code exists
|
||||
FIM C- Postage prepaid prebarcoded
|
||||
FIM D- Postage required, no bar code exists""",
|
||||
"FIM",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default 1/32in): the bar width.'''),
|
||||
spaceWidth = AttrMapValue(isNumber,'''(float or None, default 1/16in):
|
||||
width of intercharacter gap. None means "use barWidth".'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(float, default 5/8in): The bar height.'''),
|
||||
quiet = AttrMapValue(isBoolean,'''(bool, default 0):
|
||||
Whether to include quiet zones in the symbol.'''),
|
||||
lquiet = AttrMapValue(isNumber,'''(float, default: 15/32in):
|
||||
Quiet zone size to left of code, if quiet is true.'''),
|
||||
rquiet = AttrMapValue(isNumber,'''(float, default 1/4in):
|
||||
Quiet zone size to right left of code, if quiet is true.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps',
|
||||
"A",
|
||||
)
|
||||
|
||||
BarcodePOSTNET=_BCW('',
|
||||
"POSTNET",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default 0.018*in): the bar width.'''),
|
||||
spaceWidth = AttrMapValue(isNumber,'''(float or None, default 0.0275in): width of intercharacter gap.'''),
|
||||
shortHeight = AttrMapValue(isNumber,'''(float, default 0.05in): The short bar height.'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(float, default 0.125in): The full bar height.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps',
|
||||
"78247-1043",
|
||||
)
|
||||
|
||||
BarcodeUSPS_4State=_BCW('',
|
||||
"USPS_4State",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
widthSize = AttrMapValue(isNumber,'''(float, default 1): the bar width size adjustment between 0 and 1.'''),
|
||||
heightSize = AttrMapValue(isNumber,'''(float, default 1): the bar height size adjustment between 0 and 1.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
tracking = AttrMapValue(isString, desc='tracking data'),
|
||||
routing = AttrMapValue(isString, desc='routing data'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps4s',
|
||||
'01234567094987654321',
|
||||
_pre_init="\n\t\tkw.setdefault('routing','01234567891')\n",
|
||||
_methods = "\n\tdef annotate(self,x,y,text,fontName,fontSize,anchor='middle'):\n\t\t_BarcodeWidget.annotate(self,x,y,text,fontName,fontSize,anchor='start')\n"
|
||||
)
|
||||
|
||||
if __name__=='__main__':
|
||||
raise ValueError('widgets.py has no script function')
|
||||
Reference in New Issue
Block a user