Code

Extensions. Barcode extension refactoring (see https://code.launchpad.net/~doctormo...
[inkscape.git] / share / extensions / Barcode / Base.py
1 #
2 # Copyright (C) 2010 Martin Owens
3 #
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.
8 #
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.
13 #
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 #
18 """
19 Base module for rendering barcodes for Inkscape.
20 """
22 import itertools
23 import sys
24 from lxml import etree
26 (WHITE_BAR, BLACK_BAR, TALL_BAR) = range(3)
27 TEXT_TEMPLATE = 'font-size:%dpx;text-align:center;text-anchor:middle;'
29 class Barcode(object):
30     """Provide a base class for all barcode renderers"""
31     name = None
33     def error(self, bar, msg):
34         """Cause an error to be reported"""
35         sys.stderr.write(
36             "Error encoding '%s' as %s barcode: %s\n" % (bar, self.name, msg))
38     def __init__(self, param={}):
39         self.document = param.get('document', None)
40         self.x        = int(param.get('x', 0))
41         self.y        = int(param.get('y', 0))
42         self.height   = param.get('height', 30)
43         self.label    = param.get('text', None)
44         self.string   = self.encode( self.label )
46         if not self.string:
47             return
49         self.width  = len(self.string)
50         self.data   = self.graphicalArray(self.string)
52     def generate(self):
53         """Generate the actual svg from the coding"""
54         svg_uri = u'http://www.w3.org/2000/svg'
55         if not self.string or not self.data:
56             return
57         if not self.document:
58             return self.error("No document defined")
59         
60         data = self.data
61         # Collect document ids
62         doc_ids = {}
63         docIdNodes = self.document.xpath('//@id')
64         for m in docIdNodes:
65             doc_ids[m] = 1
67         # We don't have svg documents so lets do something raw:
68         name  = 'barcode'
70         # Make sure that the id/name is inique
71         index = 0
72         while (doc_ids.has_key(name)):
73             name = 'barcode' + str(index)
74             index = index + 1
76         # use an svg group element to contain the barcode
77         barcode = etree.Element('{%s}%s' % (svg_uri,'g'))
78         barcode.set('id', name)
79         barcode.set('style', 'fill: black;')
80         barcode.set('transform', 'translate(%d,%d)' % (self.x, self.y))
82         bar_offset = 0
83         bar_id     = 1
85         for datum in data:
86             # Datum 0 tells us what style of bar is to come next
87             style = self.getStyle(int(datum[0]))
88             # Datum 1 tells us what width in units,
89             # style tells us how wide a unit is
90             width = int(datum[1]) * int(style['width'])
92             if style['write']:
93                 rect = etree.SubElement(barcode,'{%s}%s' % (svg_uri,'rect'))
94                 rect.set('x',      str(bar_offset))
95                 rect.set('y',      str(style['top']))
96                 rect.set('width',  str(width))
97                 rect.set('height', str(style['height']))
98                 rect.set('id',     "%s_bar%d" % (name, bar_id))
99             bar_offset += width
100             bar_id += 1
102         bar_width = bar_offset
103         # Add text at the bottom of the barcode
104         text = etree.SubElement(barcode,'{%s}%s' % (svg_uri,'text'))
105         text.set( 'x', str(int(bar_width / 2)))
106         text.set( 'y', str(self.height + self.fontSize() ))
107         text.set( 'style', TEXT_TEMPLATE % self.fontSize() )
108         text.set( '{http://www.w3.org/XML/1998/namespace}space', 'preserve' )
109         text.set( 'id', '%s_text' % name )
110         text.text = str(self.label)
111         return barcode
113     def graphicalArray(self, code):
114         """Converts black and white markets into a space array"""
115         return [(x,len(list(y))) for x, y in itertools.groupby(code)]
117     def getStyle(self, index):
118         """Returns the styles that should be applied to each bar"""
119         result = { 'width' : 1, 'top' : 0, 'write' : True }
120         if index == BLACK_BAR:
121             result['height'] = int(self.height)
122         if index == TALL_BAR:
123             result['height'] = int(self.height) + int(self.fontSize() / 2)
124         if index == WHITE_BAR:
125             result['write'] = False
126         return result
128     def fontSize(self):
129         """Return the ideal font size, defaults to 9px"""
130         return 9