zaz-barcode/source/pythonpath/barcode/ean.py

200 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from barcode.base import Barcode
from barcode.charsets import ean as _ean
from barcode.errors import *
"""Module: barcode.ean
:Provided barcodes: EAN-14, EAN-13, EAN-8, JAN
"""
__docformat__ = 'restructuredtext en'
# Python 3
try:
reduce
except NameError:
from functools import reduce
# EAN13 Specs (all sizes in mm)
SIZES = dict(SC0=0.27, SC1=0.297, SC2=0.33, SC3=0.363, SC4=0.396, SC5=0.445,
SC6=0.495, SC7=0.544, SC8=0.61, SC9=0.66)
class EuropeanArticleNumber13(Barcode):
"""Initializes EAN13 object.
:parameters:
ean : String
The ean number as string.
writer : barcode.writer Instance
The writer to render the barcode (default: SVGWriter).
"""
name = 'EAN-13'
digits = 12
def __init__(self, ean, writer=None, **kwargs):
no_checksum = False
if "no_checksum" in kwargs.keys():
no_checksum = kwargs["no_checksum"]
ean = ean[:self.digits]
if not ean.isdigit():
raise IllegalCharacterError('EAN code can only contain numbers.')
if len(ean) != self.digits:
raise NumberOfDigitsError('EAN must have {0} digits, not '
'{1}.'.format(self.digits, len(ean)))
self.ean = ean
# If no checksum
if no_checksum:
# Add a thirteen char if given in parameter,
# otherwise pad with zero
self.ean = '{0}{1}'.format(
ean, ean[self.digits] if len(ean) > self.digits else 0
)
else:
self.ean = '{0}{1}'.format(ean, self.calculate_checksum())
self.writer = writer or Barcode.default_writer()
def __unicode__(self):
return self.ean
__str__ = __unicode__
def get_fullcode(self):
return self.ean
def calculate_checksum(self):
"""Calculates the checksum for EAN13-Code.
:returns: The checksum for `self.ean`.
:rtype: Integer
"""
def sum_(x, y): return int(x) + int(y)
evensum = reduce(sum_, self.ean[-2::-2])
oddsum = reduce(sum_, self.ean[-1::-2])
return (10 - ((evensum + oddsum * 3) % 10)) % 10
def build(self):
"""Builds the barcode pattern from `self.ean`.
:returns: The pattern as string
:rtype: String
"""
code = _ean.EDGE[:]
pattern = _ean.LEFT_PATTERN[int(self.ean[0])]
for i, number in enumerate(self.ean[1:7]):
code += _ean.CODES[pattern[i]][int(number)]
code += _ean.MIDDLE
for number in self.ean[7:]:
code += _ean.CODES['C'][int(number)]
code += _ean.EDGE
return [code]
def to_ascii(self):
"""Returns an ascii representation of the barcode.
:rtype: String
"""
code = self.build()
for i, line in enumerate(code):
code[i] = line.replace('1', '|').replace('0', ' ')
return '\n'.join(code)
def render(self, writer_options=None, text=None):
options = dict(module_width=SIZES['SC2'])
options.update(writer_options or {})
return Barcode.render(self, options, text)
class JapanArticleNumber(EuropeanArticleNumber13):
"""Initializes JAN barcode.
:parameters:
jan : String
The jan number as string.
writer : barcode.writer Instance
The writer to render the barcode (default: SVGWriter).
"""
name = 'JAN'
valid_country_codes = list(range(450, 460)) + list(range(490, 500))
def __init__(self, jan, writer=None):
if int(jan[:3]) not in JapanArticleNumber.valid_country_codes:
raise WrongCountryCodeError("Country code isn't between 450-460 "
"or 490-500.")
EuropeanArticleNumber13.__init__(self, jan, writer)
class EuropeanArticleNumber8(EuropeanArticleNumber13):
"""Represents an EAN-8 barcode. See EAN13's __init__ for details.
:parameters:
ean : String
The ean number as string.
writer : barcode.writer Instance
The writer to render the barcode (default: SVGWriter).
"""
name = 'EAN-8'
digits = 7
def __init__(self, ean, writer=None):
EuropeanArticleNumber13.__init__(self, ean, writer)
def build(self):
"""Builds the barcode pattern from `self.ean`.
:returns: The pattern as string
:rtype: String
"""
code = _ean.EDGE[:]
for number in self.ean[:4]:
code += _ean.CODES['A'][int(number)]
code += _ean.MIDDLE
for number in self.ean[4:]:
code += _ean.CODES['C'][int(number)]
code += _ean.EDGE
return [code]
class EuropeanArticleNumber14(EuropeanArticleNumber13):
"""Represents an EAN-14 barcode. See EAN13's __init__ for details.
:parameters:
ean : String
The ean number as string.
writer : barcode.writer Instance
The writer to render the barcode (default: SVGWriter).
"""
name = 'EAN-14'
digits = 13
def calculate_checksum(self):
"""Calculates the checksum for EAN13-Code.
:returns: The checksum for `self.ean`.
:rtype: Integer
"""
def sum_(x, y): return int(x) + int(y)
evensum = reduce(sum_, self.ean[::2])
oddsum = reduce(sum_, self.ean[1::2])
return (10 - (((evensum * 3) + oddsum) % 10)) % 10
# Shortcuts
EAN14 = EuropeanArticleNumber14
EAN13 = EuropeanArticleNumber13
EAN8 = EuropeanArticleNumber8
JAN = JapanArticleNumber