1 '''
2 Copyright (C) 2007 Martin Owens
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 '''
19 import itertools
20 import sys
21 from lxml import etree
23 class Barcode:
24 def __init__(self, param={}):
25 self.document = None
26 self.x = 0
27 self.y = 0
29 if param.has_key('document'):
30 self.document = param['document']
31 if param.has_key('x'):
32 self.x = param['x']
33 if param.has_key('y'):
34 self.y = param['y']
36 if param.has_key('height'):
37 self.height = param['height']
38 else:
39 self.height = 30
41 self.text = param['text']
42 self.label = self.text
43 self.string = self.encode( self.text )
44 if not self.string:
45 return
46 self.width = len(self.string)
47 self.data = self.graphicalArray(self.string)
49 def generate(self):
50 svg_uri = u'http://www.w3.org/2000/svg'
51 if not self.string or not self.data:
52 return
54 data = self.data;
56 # create an SVG document if required
57 # if not self.document:
58 # self.document = UNKNOWN
60 if not self.document:
61 sys.stderr.write("No document defined to add barcode to\n")
62 return
64 # Collect document ids
65 doc_ids = {}
66 docIdNodes = self.document.xpath('//@id')
67 for m in docIdNodes:
68 doc_ids[m] = 1
70 # We don't have svg documents so lets do something raw:
71 name = 'barcode'
73 # Make sure that the id/name is inique
74 index = 0
75 while (doc_ids.has_key(name)):
76 name = 'barcode' + str(index)
77 index = index + 1
79 # use an svg group element to contain the barcode
80 barcode = etree.Element('{%s}%s' % (svg_uri,'g'))
81 barcode.set('id', name)
82 barcode.set('style', 'fill: black;')
84 draw = 1
85 wOffset = int(self.x)
86 id = 1
88 for datum in data:
89 # Datum 0 tells us what style of bar is to come next
90 style = self.getStyle(int(datum[0]))
91 # Datum 1 tells us what width in units,
92 # style tells us how wide a unit is
93 width = int(datum[1]) * int(style['width'])
95 if style['write']:
96 # Add height for styles such as EA8 where
97 # the barcode goes into the text
99 rect = etree.SubElement(barcode,'{%s}%s' % (svg_uri,'rect'))
100 rect.set('x', str(wOffset))
101 rect.set('y', str(style['top']))
102 rect.set('width', str(width))
103 rect.set('height', str(style['height']))
104 rect.set('id', name + '_bar' + str(id))
105 wOffset = int(wOffset) + int(width)
106 id = id + 1
108 barwidth = wOffset - int(self.x)
109 # Add text at the bottom of the barcode
110 text = etree.SubElement(barcode,'{%s}%s' % (svg_uri,'text'))
111 text.set( 'x', str(int(self.x) + int(barwidth / 2)) )
112 text.set( 'y', str(int(self.height) + 10 + int(self.y)) )
113 text.set( 'style', 'font-size:' + self.fontSize() + 'px;text-align:center;text-anchor:middle;' )
114 text.set( '{http://www.w3.org/XML/1998/namespace}space', 'preserve' )
115 text.set( 'id', name + '_bottomtext' )
117 text.text = str(self.label)
119 return barcode
121 # Converts black and white markers into a space array
122 def graphicalArray(self, code):
123 return [(x,len(list(y))) for x, y in itertools.groupby(code)]
125 def getStyle(self, index):
126 result = { 'width' : 1, 'top' : int(self.y), 'write' : False }
127 if index==1: # Black Bar
128 result['height'] = int(self.height)
129 result['write'] = True
130 return result
132 def fontSize(self):
133 return '9'