File: upc.py

package info (click to toggle)
python-barcode 0.15.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 684 kB
  • sloc: python: 1,661; makefile: 23; sh: 9
file content (115 lines) | stat: -rwxr-xr-x 3,018 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Module: barcode.upc

:Provided barcodes: UPC-A
"""
__docformat__ = "restructuredtext en"

from functools import reduce

from barcode.base import Barcode
from barcode.charsets import upc as _upc
from barcode.errors import IllegalCharacterError
from barcode.errors import NumberOfDigitsError


class UniversalProductCodeA(Barcode):
    """Universal Product Code (UPC) barcode.

    UPC-A consists of 12 numeric digits.
    """

    name = "UPC-A"

    digits = 11

    def __init__(self, upc, writer=None, make_ean=False) -> None:
        """Initializes new UPC-A barcode.

        :param str upc: The upc number as string.
        :param writer: barcode.writer instance. The writer to render the
            barcode (default: SVGWriter).
        :param bool make_ean: Indicates if a leading zero should be added to
            the barcode. This converts the UPC into a valid European Article
            Number (EAN).
        """
        self.ean = make_ean
        upc = upc[: self.digits]
        if not upc.isdigit():
            raise IllegalCharacterError("UPC code can only contain numbers.")
        if len(upc) != self.digits:
            raise NumberOfDigitsError(
                f"UPC must have {self.digits} digits, not {len(upc)}."
            )
        self.upc = upc
        self.upc = f"{upc}{self.calculate_checksum()}"
        self.writer = writer or self.default_writer()

    def __str__(self) -> str:
        if self.ean:
            return "0" + self.upc

        return self.upc

    def get_fullcode(self):
        if self.ean:
            return "0" + self.upc

        return self.upc

    def calculate_checksum(self):
        """Calculates the checksum for UPCA/UPC codes

        :return: The checksum for 'self.upc'
        :rtype: int
        """

        def sum_(x, y):
            return int(x) + int(y)

        upc = self.upc[0 : self.digits]
        oddsum = reduce(sum_, upc[::2])
        evensum = reduce(sum_, upc[1::2])
        check = (evensum + oddsum * 3) % 10
        if check == 0:
            return 0

        return 10 - check

    def build(self):
        """Builds the barcode pattern from 'self.upc'

        :return: The pattern as string
        :rtype: str
        """
        code = _upc.EDGE[:]

        for _i, number in enumerate(self.upc[0:6]):
            code += _upc.CODES["L"][int(number)]

        code += _upc.MIDDLE

        for number in self.upc[6:]:
            code += _upc.CODES["R"][int(number)]

        code += _upc.EDGE

        return [code]

    def to_ascii(self):
        """Returns an ascii representation of the barcode.

        :rtype: str
        """

        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 = {"module_width": 0.33}
        options.update(writer_options or {})
        return super().render(options, text)


UPCA = UniversalProductCodeA