[IMP] Changed all module categories, limited number of categories
[odoo/odoo.git] / addons / auction / barcode / common.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 # 3. All advertising materials mentioning features or use of this software
15 #    must display the following acknowledgement:
16 #      This product includes software developed by Tyler C. Sarna.
17 # 4. Neither the name of the author nor the names of contributors
18 #    may be used to endorse or promote products derived from this software
19 #    without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
25 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 #
33
34 from reportlab.platypus.flowables import Flowable
35 from reportlab.lib.units import inch
36 import string
37
38 class Barcode(Flowable):
39     """Abstract Base for barcodes. Includes implementations of
40     some methods suitable for the more primitive barcode types"""
41     
42     def __init__(self, value = ''):
43         self.value = value
44         
45         if not hasattr(self, 'gap'):
46             self.gap = None
47             
48         self.validate()
49         self.encode()
50         #print self.encoded
51         self.decompose()
52         #print self.decomposed
53         self.computeSize()
54
55     def validate(self):
56         self.valid = 1
57         self.validated = self.value
58
59     def encode(self):
60         self.encoded = self.validated
61
62     def decompose(self):
63         self.decomposed = self.encoded
64
65     def computeSize(self, *args):
66         xdim = self.xdim
67         wx = xdim * self.ratio
68
69         if self.gap == None:
70             self.gap = xdim
71             
72         w = 0.0
73         
74         for c in self.decomposed:
75             if c in 'sb':
76                 w = w + xdim
77             elif c in 'SB':
78                 w = w + wx
79             else: # 'i'
80                 w = w + self.gap
81     
82         if self.height is None:
83             self.height = w * 0.15
84             self.height = max(0.25 * inch, self.height)
85             if self.bearers:
86                 self.height = self.height + self.bearers * 2.0 * xdim
87
88         if self.quiet:
89             w = w + self.lquiet + self.rquiet
90             self.xo = self.lquiet
91         else:
92             self.xo = 0.0
93             
94         self.width = w
95
96     def draw(self):
97         xdim = self.xdim
98         wx = xdim * self.ratio
99     
100         left = self.xo
101         b = self.bearers * xdim
102         bb = b * 0.5
103         tb = self.height - (b * 1.5)
104
105         for c in self.decomposed:
106             if c == 'i':
107                 left = left + self.gap
108             elif c == 's':
109                 left = left + xdim
110             elif c == 'S':
111                 left = left + wx
112             elif c == 'b':
113                 self.rect(left, bb, xdim, tb)
114                 left = left + xdim
115             elif c == 'B':
116                 self.rect(left, bb, wx, tb)
117                 left = left + wx
118                 
119         if self.bearers:
120             self.rect(self.lquiet, 0.0, \
121                 self.width - (self.lquiet + self.rquiet), b)
122             self.rect(self.lquiet, self.height - b, \
123                 self.width - (self.lquiet + self.rquiet), b)
124
125     def rect(self, x, y, w, h):
126         self.canv.rect(x, y, w, h, stroke=0, fill=1)
127
128
129 class MultiWidthBarcode(Barcode):
130     """Base for variable-bar-width codes like Code93 and Code128"""
131     
132     def computeSize(self, *args):
133         xdim = self.xdim
134         oa, oA = ord('a') - 1, ord('A') - 1
135
136         w = 0.0
137         
138         for c in self.decomposed:
139             oc = ord(c)
140             if c in string.lowercase:
141                 w = w + xdim * (oc - oa)
142             elif c in string.uppercase:
143                 w = w + xdim * (oc - oA)
144     
145         if self.height is None:
146             self.height = w * 0.15
147             self.height = max(0.25 * inch, self.height)
148
149         if self.quiet:
150             w = w + self.lquiet + self.rquiet
151             self.xo = self.lquiet
152         else:
153             self.xo = 0.0
154             
155         self.width = w
156
157     def draw(self):
158         oa, oA = ord('a') - 1, ord('A') - 1
159         xdim = self.xdim
160         left = self.xo
161
162         for c in self.decomposed:
163             oc = ord(c)
164             if c in string.lowercase:
165                 left = left + (oc - oa) * xdim
166             elif c in string.uppercase:
167                 w = (oc - oA) * xdim
168                 self.rect(left, 0.0, w, self.height)
169                 left = left + w
170
171
172 class I2of5(Barcode):
173     """
174     Interleaved 2 of 5 is a numeric-only barcode.  It encodes an even
175     number of digits; if an odd number is given, a 0 is prepended.
176
177     Options that may be passed to constructor:
178
179         value (int, or numeric string. required.):
180             The value to encode.
181    
182         xdim (float, default .0075):
183             X-Dimension, or width of the smallest element
184             Minumum is .0075 inch (7.5 mils).
185             
186         ratio (float, default 2.2):
187             The ratio of wide elements to narrow elements.
188             Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
189             xdim is greater than 20 mils (.02 inch))
190             
191         gap (float or None, default None):
192             width of intercharacter gap. None means "use xdim".
193         
194         height (float, see default below):
195             Height of the symbol.  Default is the height of the two
196             bearer bars (if they exist) plus the greater of .25 inch
197             or .15 times the symbol's length.
198
199         checksum (bool, default 1):
200             Wether to compute and include the check digit
201             
202         bearers (float, in units of xdim. default 3.0):
203             Height of bearer bars (horizontal bars along the top and
204             bottom of the barcode). Default is 3 x-dimensions.
205             Set to zero for no bearer bars. (Bearer bars help detect
206             misscans, so it is suggested to leave them on).
207             
208         quiet (bool, default 1):
209             Wether to include quiet zones in the symbol.
210             
211         lquiet (float, see default below):
212             Quiet zone size to left of code, if quiet is true.
213             Default is the greater of .25 inch, or .15 times the symbol's
214             length.
215             
216         rquiet (float, defaults as above):
217             Quiet zone size to right left of code, if quiet is true.
218             
219     Sources of Information on Interleaved 2 of 5:
220
221     http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html
222     http://www.adams1.com/pub/russadam/i25code.html
223
224     Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from
225     http://www.aimglobal.org/aimstore/
226     """
227
228     patterns = {
229         'start' : 'bsbs',
230         'stop' : 'Bsb',
231
232         'B0' : 'bbBBb',     'S0' : 'ssSSs',
233         'B1' : 'BbbbB',     'S1' : 'SsssS',
234         'B2' : 'bBbbB',     'S2' : 'sSssS',
235         'B3' : 'BBbbb',     'S3' : 'SSsss',
236         'B4' : 'bbBbB',     'S4' : 'ssSsS',
237         'B5' : 'BbBbb',     'S5' : 'SsSss',
238         'B6' : 'bBBbb',     'S6' : 'sSSss',
239         'B7' : 'bbbBB',     'S7' : 'sssSS',
240         'B8' : 'BbbBb',     'S8' : 'SssSs',
241         'B9' : 'bBbBb',     'S9' : 'sSsSs'
242     }
243
244     def __init__(self, value='', **args):
245         self.height = None
246         self.xdim = inch * 0.0075
247         self.ratio = 2.2
248         self.checksum = 1
249         self.bearers = 3.0
250         self.quiet = 1
251         self.lquiet = self.rquiet = None
252
253         if type(value) == type(1):
254             value = str(value)
255
256         for (k, v) in args.items():
257             setattr(self, k, v)
258
259         if self.quiet:
260             if self.lquiet is None:
261                 self.lquiet = min(inch * 0.25, self.xdim * 10.0)
262                 self.rquiet = min(inch * 0.25, self.xdim * 10.0)
263         else:
264             self.lquiet = self.rquiet = 0.0
265
266         Barcode.__init__(self, value)
267
268     def validate(self):
269         vval = ""
270         self.valid = 1
271         for c in string.strip(self.value):
272             if c not in string.digits:
273                 self.valid = 0
274                 continue
275             vval = vval + c
276         self.validated = vval
277         return vval
278
279     def encode(self):
280         s = self.validated
281
282         # make sure result will be a multiple of 2 digits long,
283         # checksum included
284         if ((len(self.validated) % 2 == 0) and self.checksum) \
285         or ((len(self.validated) % 2 == 1) and not self.checksum):
286             s = '0' + s
287
288         if self.checksum:
289             c = 0
290             cm = 3
291
292             for d in s:
293                 c = c + cm * int(d)
294                 if cm == 3:
295                     cm = 1
296                 else:
297                     cm = 3
298
299             d = 10 - (int(d) % 10)
300             s = s + `d`
301
302         self.encoded = s
303
304     def decompose(self):
305         dval = self.patterns['start']
306
307         for i in range(0, len(self.encoded), 2):
308             b = self.patterns['B' + self.encoded[i]]
309             s = self.patterns['S' + self.encoded[i+1]]
310
311             for i in range(0, len(b)):
312                 dval = dval + b[i] + s[i]
313
314         self.decomposed = dval + self.patterns['stop']
315         return self.decomposed
316
317
318
319 class MSI(Barcode):
320     """
321     MSI is a numeric-only barcode.
322
323     Options that may be passed to constructor:
324
325         value (int, or numeric string. required.):
326             The value to encode.
327    
328         xdim (float, default .0075):
329             X-Dimension, or width of the smallest element
330             
331         ratio (float, default 2.2):
332             The ratio of wide elements to narrow elements.
333             
334         gap (float or None, default None):
335             width of intercharacter gap. None means "use xdim".
336         
337         height (float, see default below):
338             Height of the symbol.  Default is the height of the two
339             bearer bars (if they exist) plus the greater of .25 inch
340             or .15 times the symbol's length.
341
342         checksum (bool, default 1):
343             Wether to compute and include the check digit
344             
345         bearers (float, in units of xdim. default 0):
346             Height of bearer bars (horizontal bars along the top and
347             bottom of the barcode). Default is 0 (no bearers).
348             
349         lquiet (float, see default below):
350             Quiet zone size to left of code, if quiet is true.
351             Default is the greater of .25 inch, or 10 xdims.
352             
353         rquiet (float, defaults as above):
354             Quiet zone size to right left of code, if quiet is true.
355             
356     Sources of Information on MSI Bar Code:
357
358     http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html
359     http://www.adams1.com/pub/russadam/plessy.html
360     """
361
362     patterns = {
363         'start' : 'Bs',          'stop' : 'bSb',
364
365         '0' : 'bSbSbSbS',        '1' : 'bSbSbSBs',
366         '2' : 'bSbSBsbS',        '3' : 'bSbSBsBs',
367         '4' : 'bSBsbSbS',        '5' : 'bSBsbSBs',
368         '6' : 'bSBsBsbS',        '7' : 'bSBsBsBs',
369         '8' : 'BsbSbSbS',        '9' : 'BsbSbSBs'
370     }
371
372     def __init__(self, value="", **args):
373         self.height = None
374         self.xdim = inch * 0.0075
375         self.ratio = 2.2
376         self.checksum = 1
377         self.bearers = 0.0
378         self.quiet = 1
379         self.lquiet = self.rquiet = None
380
381         if type(value) == type(1):
382             value = str(value)
383
384         for (k, v) in args.items():
385             setattr(self, k, v)
386
387         if self.quiet:
388             if self.lquiet is None:
389                 self.lquiet = max(inch * 0.25, self.xdim * 10.0)
390                 self.rquiet = max(inch * 0.25, self.xdim * 10.0)
391         else:
392             self.lquiet = self.rquiet = 0.0
393
394         Barcode.__init__(self, value)
395
396     def validate(self):
397         vval = ""
398         self.valid = 1
399         for c in string.strip(self.value):
400             if c not in string.digits:
401                 self.valid = 0
402                 continue
403             vval = vval + c
404         self.validated = vval
405         return vval
406
407     def encode(self):
408         s = self.validated
409
410         if self.checksum:
411             c = ''
412             for i in range(1, len(s), 2):
413                 c = c + s[i]
414             d = str(int(c) * 2)
415             t = 0
416             for c in d:
417                 t = t + int(c)
418             for i in range(0, len(s), 2):
419                 t = t + int(s[i])
420             c = 10 - (t % 10)
421
422             s = s + str(c)
423
424         self.encoded = s
425
426     def decompose(self):
427         dval = self.patterns['start']
428
429         for c in self.encoded:
430             dval = dval + self.patterns[c]
431
432         self.decomposed = dval + self.patterns['stop']
433         return self.decomposed
434
435
436
437 class Codabar(Barcode):
438     """
439     Codabar is a numeric plus some puntuation ("-$:/.+") barcode
440     with four start/stop characters (A, B, C, and D).
441
442     Options that may be passed to constructor:
443
444         value (string. required.):
445             The value to encode.
446    
447         xdim (float, default .0065):
448             X-Dimension, or width of the smallest element
449             minimum is 6.5 mils (.0065 inch)
450             
451         ratio (float, default 2.0):
452             The ratio of wide elements to narrow elements.
453             
454         gap (float or None, default None):
455             width of intercharacter gap. None means "use xdim".
456         
457         height (float, see default below):
458             Height of the symbol.  Default is the height of the two
459             bearer bars (if they exist) plus the greater of .25 inch
460             or .15 times the symbol's length.
461
462         checksum (bool, default 0):
463             Wether to compute and include the check digit
464             
465         bearers (float, in units of xdim. default 0):
466             Height of bearer bars (horizontal bars along the top and
467             bottom of the barcode). Default is 0 (no bearers).
468             
469         quiet (bool, default 1):
470             Wether to include quiet zones in the symbol.
471             
472         lquiet (float, see default below):
473             Quiet zone size to left of code, if quiet is true.
474             Default is the greater of .25 inch, or 10 xdim
475             
476         rquiet (float, defaults as above):
477             Quiet zone size to right left of code, if quiet is true.
478             
479     Sources of Information on Codabar
480
481     http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html
482     http://www.barcodeman.com/codabar.html
483
484     Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from
485     http://www.aimglobal.org/aimstore/
486     """
487
488     patterns = {
489         '0':    'bsbsbSB',        '1':    'bsbsBSb',        '2':    'bsbSbsB',
490         '3':    'BSbsbsb',        '4':    'bsBsbSb',        '5':    'BsbsbSb',
491         '6':    'bSbsbsB',        '7':    'bSbsBsb',        '8':    'bSBsbsb',
492         '9':    'BsbSbsb',        '-':    'bsbSBsb',        '$':    'bsBSbsb',
493         ':':    'BsbsBsB',        '/':    'BsBsbsB',        '.':    'BsBsBsb',
494         '+':    'bsBsBsB',        'A':    'bsBSbSb',        'B':    'bSbSbsB',
495         'C':    'bsbSbSB',        'D':    'bsbSBSb'
496     }
497
498     values = {
499         '0' : 0,    '1' : 1,    '2' : 2,    '3' : 3,    '4' : 4,
500         '5' : 5,    '6' : 6,    '7' : 7,    '8' : 8,    '9' : 9,
501         '-' : 10,   '$' : 11,   ':' : 12,   '/' : 13,   '.' : 14,
502         '+' : 15,   'A' : 16,   'B' : 17,   'C' : 18,   'D' : 19
503     }
504
505     chars = string.digits + "-$:/.+"
506
507     def __init__(self, value='', **args):
508         self.height = None
509         self.xdim = inch * 0.0065
510         self.ratio = 2.0 # XXX ?
511         self.checksum = 0
512         self.bearers = 0.0
513         self.quiet = 1
514         self.lquiet = self.rquiet = None
515
516         if type(value) == type(1):
517             value = str(value)
518
519         for (k, v) in args.items():
520             setattr(self, k, v)
521
522         if self.quiet:
523             if self.lquiet is None:
524                 self.lquiet = min(inch * 0.25, self.xdim * 10.0)
525                 self.rquiet = min(inch * 0.25, self.xdim * 10.0)
526         else:
527             self.lquiet = self.rquiet = 0.0
528
529         Barcode.__init__(self, value)
530
531     def validate(self):
532         vval = ""
533         self.valid = 1
534         s = string.strip(self.value)
535         for i in range(0, len(s)):
536             c = s[i]
537             if c not in self.chars:
538                 if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'):
539                     self.Valid = 0
540                     continue
541             vval = vval + c
542
543         if vval[0] not in 'ABCD':
544             vval = 'A' + vval
545         if vval[-1] not in 'ABCD':
546             vval = vval + vval[0]
547
548         self.validated = vval
549         return vval
550
551     def encode(self):
552         s = self.validated
553
554         if self.checksum:
555             v = 0
556             for c in s:
557                 v = v + self.values[v]
558             v = 16 - (v % 16)
559             s = s + self.chars[v]
560
561         self.encoded = s
562
563     def decompose(self):
564         dval = ""
565         for c in self.encoded:
566             dval = dval + self.patterns[c] + 'i'
567         self.decomposed = dval[:-1]            
568         return self.decomposed
569
570
571
572 class Code11(Barcode):
573     """
574     Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus
575     dash ("-"). 11 characters total, hence the name.
576     
577         value (int or string. required.):
578             The value to encode.
579    
580         xdim (float, default .0075):
581             X-Dimension, or width of the smallest element
582             
583         ratio (float, default 2.2):
584             The ratio of wide elements to narrow elements.
585             
586         gap (float or None, default None):
587             width of intercharacter gap. None means "use xdim".
588         
589         height (float, see default below):
590             Height of the symbol.  Default is the height of the two
591             bearer bars (if they exist) plus the greater of .25 inch
592             or .15 times the symbol's length.
593
594         checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
595             How many checksum digits to include. -1 ("auto") means
596             1 if the number of digits is 10 or less, else 2.
597             
598         bearers (float, in units of xdim. default 0):
599             Height of bearer bars (horizontal bars along the top and
600             bottom of the barcode). Default is 0 (no bearers).
601             
602         quiet (bool, default 1):
603             Wether to include quiet zones in the symbol.
604             
605         lquiet (float, see default below):
606             Quiet zone size to left of code, if quiet is true.
607             Default is the greater of .25 inch, or 10 xdim
608             
609         rquiet (float, defaults as above):
610             Quiet zone size to right left of code, if quiet is true.
611             
612     Sources of Information on Code 11:
613
614     http://www.cwi.nl/people/dik/english/codes/barcodes.html
615     """
616     
617     chars = string.digits + '-'
618     
619     patterns = {
620         '0' : 'bsbsB',        '1' : 'BsbsB',        '2' : 'bSbsB',
621         '3' : 'BSbsb',        '4' : 'bsBsB',        '5' : 'BsBsb',
622         '6' : 'bSBsb',        '7' : 'bsbSB',        '8' : 'BsbSb',
623         '9' : 'Bsbsb',        '-' : 'bsBsb',        'S' : 'bsBSb' # Start/Stop
624     }
625
626     values = {
627         '0' : 0,    '1' : 1,    '2' : 2,    '3' : 3,    '4' : 4,
628         '5' : 5,    '6' : 6,    '7' : 7,    '8' : 8,    '9' : 9,
629         '-' : 10,
630     }
631
632     def __init__(self, value='', **args):
633         self.height = None
634         self.xdim = inch * 0.0075
635         self.ratio = 2.2 # XXX ?
636         self.checksum = -1 # Auto 
637         self.bearers = 0.0
638         self.quiet = 1
639         self.lquiet = self.rquiet = None
640
641         if type(value) == type(1):
642             value = str(value)
643
644         for (k, v) in args.items():
645             setattr(self, k, v)
646
647         if self.quiet:
648             if self.lquiet is None:
649                 self.lquiet = min(inch * 0.25, self.xdim * 10.0)
650                 self.rquiet = min(inch * 0.25, self.xdim * 10.0)
651         else:
652             self.lquiet = self.rquiet = 0.0
653
654         Barcode.__init__(self, value)
655
656     def validate(self):
657         vval = ""
658         self.valid = 1
659         s = string.strip(self.value)
660         for i in range(0, len(s)):
661             c = s[i]
662             if c not in self.chars:
663                 self.Valid = 0
664                 continue
665             vval = vval + c
666
667         self.validated = vval
668         return vval
669
670     def encode(self):
671         s = self.validated
672
673         if self.checksum == -1:
674             if len(s) <= 10:
675                 self.checksum = 1
676             else:
677                 self.checksum = 2
678
679         if self.checksum > 0:
680             # compute first checksum
681             i = 0; v = 1; c = 0
682             while i < len(s):
683                 c = c + v * string.index(self.chars, s[-(i+1)])
684                 i = i + 1; v = v + 1
685                 if v > 10:
686                     v = 1
687             s = s + self.chars[c % 11]
688
689         if self.checksum > 1:
690             # compute second checksum
691             i = 0; v = 1; c = 0
692             while i < len(s):
693                 c = c + v * string.index(self.chars, s[-(i+1)])
694                 i = i + 1; v = v + 1
695                 if v > 9:
696                     v = 1
697             s = s + self.chars[c % 10]
698
699         self.encoded = 'S' + s + 'S'
700
701     def decompose(self):
702         dval = ""
703         for c in self.encoded:
704             dval = dval + self.patterns[c] + 'i'
705         self.decomposed = dval[:-1]            
706         return self.decomposed
707 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: