# -*- 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