diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
commit | cca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch) | |
tree | 146f39ded1c938019e1ed42d30923c2ac9e86789 /share/extensions/barcode/BaseEan.py | |
parent | Initial commit. (diff) | |
download | inkscape-upstream.tar.xz inkscape-upstream.zip |
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | share/extensions/barcode/BaseEan.py | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/share/extensions/barcode/BaseEan.py b/share/extensions/barcode/BaseEan.py new file mode 100644 index 0000000..d1ab58e --- /dev/null +++ b/share/extensions/barcode/BaseEan.py @@ -0,0 +1,204 @@ +# coding=utf-8 +# +# Copyright (C) 2010 Martin Owens +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. +# +""" +Some basic common code shared between EAN and UCP generators. +""" + +from .Base import Barcode, TEXT_POS_TOP +from inkex.localization import inkex_gettext as _ + +try: + from typing import Optional, List, Dict +except ImportError: + pass + +MAPPING = [ + # Left side of barcode Family '0' + [ + "0001101", + "0011001", + "0010011", + "0111101", + "0100011", + "0110001", + "0101111", + "0111011", + "0110111", + "0001011", + ], + # Left side of barcode Family '1' and flipped to right side. + [ + "0100111", + "0110011", + "0011011", + "0100001", + "0011101", + "0111001", + "0000101", + "0010001", + "0001001", + "0010111", + ], +] +# This chooses which of the two encodings above to use. +FAMILIES = ( + "000000", + "001011", + "001101", + "001110", + "010011", + "011001", + "011100", + "010101", + "010110", + "011010", +) + + +class EanBarcode(Barcode): + """Simple base class for all EAN type barcodes""" + + lengths = None # type: Optional[List[int]] + length = None # type: Optional[int] + checks = [] # type: List[int] + extras = {} # type: Dict[int, str] + magic = 10 + guard_bar = "202" + center_bar = "02020" + + @staticmethod + def intarray(number): + """Convert a string of digits into an array of ints""" + return [int(i) for i in number] + + @staticmethod + def encode_interleaved(family, number, fams=FAMILIES): + """Encode any side of the barcode, interleaved""" + result = [] + encset = EanBarcode.intarray(fams[family]) + for i, _ in enumerate(number): + thismap = MAPPING[encset[i]] + result.append(thismap[number[i]]) + return result + + @staticmethod + def encode_right(number): + """Encode the right side of the barcode, non-interleaved""" + result = [] + for num in number: + # The right side is always the reverse of the left's family '1' + result.append(MAPPING[1][num][::-1]) + return result + + @staticmethod + def encode_left(number): + """Encode the left side of the barcode, non-interleaved""" + result = [] + for num in number: + result.append(MAPPING[0][num]) + return result + + @staticmethod + def space(*spacing): + """Space out an array of numbers""" + result = "" + for space in spacing: + if isinstance(space, list): + for i in space: + result += str(i) + elif isinstance(space, int): + result += " " * space + return result + + def get_lengths(self): + """Return a list of acceptable lengths""" + if self.length: + return [self.length] + return self.lengths[:] + + def encode(self, text): + """Encode any EAN barcode""" + code = text.replace(" ", "").strip() + guide = code.endswith(">") + code = code.strip(">") + + if not code.isdigit(): + return self.error(code, _("Not a Number, must be digits 0-9 only")) + lengths = self.get_lengths() + self.checks + + # Allow extra barcodes after the first one + if len(code) not in lengths: + for extra in self.extras: + sep = len(code) - extra + if sep in lengths: + # Generate a barcode along side this one. + self.add_extra_barcode( + self.extras[extra], + text=code[sep:], + x=self.pos_x + 400 * self.scale, + text_pos=TEXT_POS_TOP, + ) + code = code[:sep] + + if len(code) not in lengths: + return self.error( + code, + _("Wrong size {:d}, must be {} digits").format( + len(code), ", ".join([str(length) for length in lengths]) + ), + ) + + if self.checks: + if len(code) not in self.checks: + code = self.append_checksum(code) + elif not self.verify_checksum(code): + return self.error(code, _("Checksum failed, omit for new sum")) + return self._encode(EanBarcode.intarray(code), guide=guide) + + def _encode(self, num, guide=False): + """ + Write your EAN encoding function, it's passed in an array of int and + it should return a string on 1 and 0 for black and white parts + """ + raise NotImplementedError("_encode should be provided by parent EAN") + + def enclose(self, left, right=()): + """Standard Enclosure""" + parts = [self.guard_bar] + left + parts.append(self.center_bar) + parts += list(right) + [self.guard_bar] + return "".join(parts) + + def get_checksum(self, num): + """Generate a UPCA/EAN13/EAN8 Checksum""" + # Left to right,checksum based on first digits. + total = sum([int(n) * (3, 1)[x % 2] for x, n in enumerate(num[::-1])]) + # Modulous result to a single digit checksum + checksum = self.magic - (total % self.magic) + if checksum < 0 or checksum >= self.magic: + return "0" + return str(checksum) + + def append_checksum(self, number): + """Apply the checksum to a short number""" + return number + self.get_checksum(number) + + def verify_checksum(self, number): + """Verify any checksum""" + return self.get_checksum(number[:-1]) == number[-1] |