summaryrefslogtreecommitdiffstats
path: root/share/extensions/barcode
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
commitcca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch)
tree146f39ded1c938019e1ed42d30923c2ac9e86789 /share/extensions/barcode
parentInitial commit. (diff)
downloadinkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.tar.xz
inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'share/extensions/barcode')
-rw-r--r--share/extensions/barcode/Base.py171
-rw-r--r--share/extensions/barcode/BaseEan.py204
-rw-r--r--share/extensions/barcode/Code128.py246
-rw-r--r--share/extensions/barcode/Code25i.py71
-rw-r--r--share/extensions/barcode/Code39.py98
-rw-r--r--share/extensions/barcode/Code39Ext.py97
-rw-r--r--share/extensions/barcode/Code93.py187
-rw-r--r--share/extensions/barcode/Ean13.py44
-rw-r--r--share/extensions/barcode/Ean2.py40
-rw-r--r--share/extensions/barcode/Ean5.py50
-rw-r--r--share/extensions/barcode/Ean8.py38
-rw-r--r--share/extensions/barcode/Rm4scc.py139
-rw-r--r--share/extensions/barcode/Upca.py40
-rw-r--r--share/extensions/barcode/Upce.py112
-rw-r--r--share/extensions/barcode/__init__.py77
15 files changed, 1614 insertions, 0 deletions
diff --git a/share/extensions/barcode/Base.py b/share/extensions/barcode/Base.py
new file mode 100644
index 0000000..024213c
--- /dev/null
+++ b/share/extensions/barcode/Base.py
@@ -0,0 +1,171 @@
+# 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.
+#
+"""
+Base module for rendering barcodes for Inkscape.
+"""
+
+import itertools
+import sys
+
+from inkex import Group, TextElement, Rectangle
+from inkex.localization import inkex_gettext as _
+
+(TEXT_POS_BOTTOM, TEXT_POS_TOP) = range(2)
+(WHITE_BAR, BLACK_BAR, TALL_BAR) = range(3)
+TEXT_TEMPLATE = "font-size:%dpx;text-align:center;text-anchor:middle;"
+
+try:
+ from typing import Optional
+except ImportError:
+ pass
+
+
+class Barcode(object):
+ """Provide a base class for all barcode renderers"""
+
+ default_height = 30
+ font_size = 9
+ name = None # type: Optional[str]
+
+ def error(self, text, msg):
+ """Cause an error to be reported"""
+ sys.stderr.write(
+ _("Error encoding '{}' as {} barcode: {}\n").format(text, self.name, msg)
+ )
+ return "ERROR"
+
+ def encode(self, text):
+ """
+ Replace this with the encoding function, it should return
+ a string of ones and zeros
+ """
+ raise NotImplementedError("You need to write an encode() function.")
+
+ def __init__(self, param):
+ param = param or {}
+ self.document = param.get("document", None)
+ self.known_ids = []
+ self._extra = []
+
+ self.pos_x = int(param.get("x", 0))
+ self.pos_y = int(param.get("y", 0))
+ self.text = param.get("text", None)
+ self.scale = param.get("scale", 1)
+ self.height = param.get("height", self.default_height)
+ self.pos_text = param.get("text_pos", TEXT_POS_BOTTOM)
+
+ if self.document:
+ self.known_ids = list(self.document.xpath("//@id"))
+
+ if not self.text:
+ raise ValueError(_("No string specified for barcode."))
+
+ def get_id(self, name="element"):
+ """Get the next useful id (and claim it)"""
+ index = 0
+ while name in self.known_ids:
+ index += 1
+ name = "barcode{:d}".format(index)
+ self.known_ids.append(name)
+ return name
+
+ def add_extra_barcode(self, barcode, **kw):
+ """Add an extra barcode along side this one, used for ean13 extras"""
+ from . import get_barcode
+
+ kw["height"] = self.height
+ kw["document"] = self.document
+ kw["scale"] = None
+ self._extra.append(get_barcode(barcode, **kw).generate())
+
+ def generate(self):
+ """Generate the actual svg from the coding"""
+ string = self.encode(self.text)
+
+ if string == "ERROR":
+ return
+
+ name = self.get_id("barcode")
+
+ # use an svg group element to contain the barcode
+ barcode = Group()
+ barcode.set("id", name)
+ barcode.set("style", "fill: black;")
+
+ barcode.transform.add_translate(self.pos_x, self.pos_y)
+ if self.scale:
+ barcode.transform.add_scale(self.scale)
+
+ bar_id = 1
+ bar_offset = 0
+ tops = set()
+
+ for datum in self.graphical_array(string):
+ # Datum 0 tells us what style of bar is to come next
+ style = self.get_style(int(datum[0]))
+ # Datum 1 tells us what width in units,
+ # style tells us how wide a unit is
+ width = int(datum[1]) * int(style["width"])
+
+ if style["write"]:
+ tops.add(style["top"])
+ rect = Rectangle()
+ rect.set("x", str(bar_offset))
+ rect.set("y", str(style["top"]))
+ if self.pos_text == TEXT_POS_TOP:
+ rect.set("y", str(style["top"] + self.font_size))
+ rect.set("id", "{}_bar{:d}".format(name, bar_id))
+ rect.set("width", str(width))
+ rect.set("height", str(style["height"]))
+ barcode.append(rect)
+ bar_offset += width
+ bar_id += 1
+
+ for extra in self._extra:
+ if extra is not None:
+ barcode.append(extra)
+
+ bar_width = bar_offset
+ # Add text at the bottom of the barcode
+ text = TextElement()
+ text.set("x", str(int(bar_width / 2)))
+ text.set("y", str(min(tops) + self.font_size - 1))
+ if self.pos_text == TEXT_POS_BOTTOM:
+ text.set("y", str(self.height + max(tops) + self.font_size))
+ text.set("style", TEXT_TEMPLATE % self.font_size)
+ text.set("xml:space", "preserve")
+ text.set("id", "{}_text".format(name))
+ text.text = str(self.text)
+ barcode.append(text)
+ return barcode
+
+ def graphical_array(self, code):
+ """Converts black and white markets into a space array"""
+ return [(x, len(list(y))) for x, y in itertools.groupby(code)]
+
+ def get_style(self, index):
+ """Returns the styles that should be applied to each bar"""
+ result = {"width": 1, "top": 0, "write": True}
+ if index == BLACK_BAR:
+ result["height"] = int(self.height)
+ if index == TALL_BAR:
+ result["height"] = int(self.height) + int(self.font_size / 2)
+ if index == WHITE_BAR:
+ result["write"] = False
+ return result
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]
diff --git a/share/extensions/barcode/Code128.py b/share/extensions/barcode/Code128.py
new file mode 100644
index 0000000..e5f8701
--- /dev/null
+++ b/share/extensions/barcode/Code128.py
@@ -0,0 +1,246 @@
+# coding=utf-8
+#
+# Authored by Martin Owens <doctormo@gmail.com>
+# Debugged by Ralf Heinecke & Martin Siepmann 2007-09-07
+# Horst Schottky 2010-02-27
+#
+# Copyright (C) 2007 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.
+#
+"""
+Renderer for Code128/EAN128 codes. Designed for use with Inkscape.
+"""
+
+import re
+
+from .Base import Barcode
+
+CODE_MAP = [
+ "11011001100",
+ "11001101100",
+ "11001100110",
+ "10010011000",
+ "10010001100",
+ "10001001100",
+ "10011001000",
+ "10011000100",
+ "10001100100",
+ "11001001000",
+ "11001000100",
+ "11000100100",
+ "10110011100",
+ "10011011100",
+ "10011001110",
+ "10111001100",
+ "10011101100",
+ "10011100110",
+ "11001110010",
+ "11001011100",
+ "11001001110",
+ "11011100100",
+ "11001110100",
+ "11101101110",
+ "11101001100",
+ "11100101100",
+ "11100100110",
+ "11101100100",
+ "11100110100",
+ "11100110010",
+ "11011011000",
+ "11011000110",
+ "11000110110",
+ "10100011000",
+ "10001011000",
+ "10001000110",
+ "10110001000",
+ "10001101000",
+ "10001100010",
+ "11010001000",
+ "11000101000",
+ "11000100010",
+ "10110111000",
+ "10110001110",
+ "10001101110",
+ "10111011000",
+ "10111000110",
+ "10001110110",
+ "11101110110",
+ "11010001110",
+ "11000101110",
+ "11011101000",
+ "11011100010",
+ "11011101110",
+ "11101011000",
+ "11101000110",
+ "11100010110",
+ "11101101000",
+ "11101100010",
+ "11100011010",
+ "11101111010",
+ "11001000010",
+ "11110001010",
+ "10100110000",
+ "10100001100",
+ "10010110000",
+ "10010000110",
+ "10000101100",
+ "10000100110",
+ "10110010000",
+ "10110000100",
+ "10011010000",
+ "10011000010",
+ "10000110100",
+ "10000110010",
+ "11000010010",
+ "11001010000",
+ "11110111010",
+ "11000010100",
+ "10001111010",
+ "10100111100",
+ "10010111100",
+ "10010011110",
+ "10111100100",
+ "10011110100",
+ "10011110010",
+ "11110100100",
+ "11110010100",
+ "11110010010",
+ "11011011110",
+ "11011110110",
+ "11110110110",
+ "10101111000",
+ "10100011110",
+ "10001011110",
+ "10111101000",
+ "10111100010",
+ "11110101000",
+ "11110100010",
+ "10111011110",
+ "10111101110",
+ "11101011110",
+ "11110101110",
+ "11010000100",
+ "11010010000",
+ "11010011100",
+ "11000111010",
+ "11",
+]
+
+
+def map_extra(data, chars):
+ """Maps the data into the chars"""
+ result = list(data)
+ for char in chars:
+ result.append(chr(char))
+ result.append("FNC3")
+ result.append("FNC2")
+ result.append("SHIFT")
+ return result
+
+
+# The map_extra method is used to slim down the amount
+# of pre code and instead we generate the lists
+CHAR_AB = list(" !\"#$%&'()*+,-./0123456789:;<=>?@" "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_")
+CHAR_A = map_extra(CHAR_AB, range(0, 31)) # Offset 64
+CHAR_B = map_extra(CHAR_AB, range(96, 127)) # Offset -32
+
+
+class Code128(Barcode):
+ """Main barcode object, generates the encoding bits here"""
+
+ def encode(self, text):
+ blocks = []
+ block = ""
+
+ # Split up into sections of numbers, or characters
+ # This makes sure that all the characters are encoded
+ # In the best way possible for Code128
+ for datum in re.findall(r"(?:(?:\d\d){2,})|(?:^\d\d)|.", text):
+ if len(datum) == 1:
+ block = block + datum
+ else:
+ if block:
+ blocks.append(self.best_block(block))
+ block = ""
+ blocks.append(["C", datum])
+
+ if block:
+ blocks.append(Code128.best_block(block))
+ block = ""
+
+ return Code128.encode_blocks(blocks)
+
+ @staticmethod
+ def best_block(block):
+ """If this has characters above 63, select B over A"""
+ if any(ord(x) > 63 for x in block):
+ return ["B", block]
+ return ["A", block]
+
+ @staticmethod
+ def encode_blocks(blocks):
+ """Encode the given blocks into A, B or C codes"""
+ encode = ""
+ total = 0
+ pos = 0
+
+ for block in blocks:
+ b_set = block[0]
+ datum = block[1]
+
+ # POS : 0, 1
+ # A : 101, 103
+ # B : 100, 104
+ # C : 99, 105
+ num = 0
+ if b_set == "A":
+ num = 103
+ elif b_set == "B":
+ num = 104
+ elif b_set == "C":
+ num = 105
+
+ i = pos
+ if pos:
+ num = 204 - num
+ else:
+ i = 1
+
+ total = total + num * i
+ encode = encode + CODE_MAP[num]
+ pos += 1
+
+ if b_set in ("A", "B"):
+ chars = CHAR_B
+ if b_set == "A":
+ chars = CHAR_A
+
+ for char in datum:
+ total = total + (chars.index(char) * pos)
+ encode = encode + CODE_MAP[chars.index(char)]
+ pos += 1
+ else:
+ for char in (datum[i : i + 2] for i in range(0, len(datum), 2)):
+ total = total + (int(char) * pos)
+ encode = encode + CODE_MAP[int(char)]
+ pos += 1
+
+ checksum = total % 103
+ encode = encode + CODE_MAP[checksum]
+ encode = encode + CODE_MAP[106]
+ encode = encode + CODE_MAP[107]
+
+ return encode
diff --git a/share/extensions/barcode/Code25i.py b/share/extensions/barcode/Code25i.py
new file mode 100644
index 0000000..adc0161
--- /dev/null
+++ b/share/extensions/barcode/Code25i.py
@@ -0,0 +1,71 @@
+# coding=utf-8
+#
+# Copyright (C) 2010 Geoffrey Mosini
+#
+# 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.
+#
+"""
+Generate barcodes for Code25-interleaved 2 of 5, for Inkscape.
+"""
+
+from .Base import Barcode
+from inkex.localization import inkex_gettext as _
+
+# 1 means thick, 0 means thin
+ENCODE = {
+ "0": "00110",
+ "1": "10001",
+ "2": "01001",
+ "3": "11000",
+ "4": "00101",
+ "5": "10100",
+ "6": "01100",
+ "7": "00011",
+ "8": "10010",
+ "9": "01010",
+}
+
+
+class Code25i(Barcode):
+ """Convert a text into string binary of black and white markers"""
+
+ # Start and stop code are already encoded into white (0) and black(1) bars
+ def encode(self, text):
+ if not text.isdigit():
+ return self.error(text, _("CODE25 can only encode numbers."))
+ number = text
+
+ # Number of figures to encode must be even,
+ # a 0 is added to the left in case it's odd.
+ if len(number) % 2 > 0:
+ number = "0" + number
+
+ # Number is encoded by pairs of 2 figures
+ size = len(number) // 2
+ encoded = "1010"
+ for i in range(size):
+ # First in the pair is encoded in black (1), second in white (0)
+ black = ENCODE[number[i * 2]]
+ white = ENCODE[number[i * 2 + 1]]
+ for j in range(5):
+ if black[j] == "1":
+ encoded += "11"
+ else:
+ encoded += "1"
+ if white[j] == "1":
+ encoded += "00"
+ else:
+ encoded += "0"
+ return encoded + "1101"
diff --git a/share/extensions/barcode/Code39.py b/share/extensions/barcode/Code39.py
new file mode 100644
index 0000000..87f346a
--- /dev/null
+++ b/share/extensions/barcode/Code39.py
@@ -0,0 +1,98 @@
+# coding=utf-8
+#
+# Copyright (C) 2007 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.
+#
+"""
+Python barcode renderer for Code39 barcodes. Designed for use with Inkscape.
+"""
+
+from .Base import Barcode
+
+ENCODE = {
+ "0": "000110100",
+ "1": "100100001",
+ "2": "001100001",
+ "3": "101100000",
+ "4": "000110001",
+ "5": "100110000",
+ "6": "001110000",
+ "7": "000100101",
+ "8": "100100100",
+ "9": "001100100",
+ "A": "100001001",
+ "B": "001001001",
+ "C": "101001000",
+ "D": "000011001",
+ "E": "100011000",
+ "F": "001011000",
+ "G": "000001101",
+ "H": "100001100",
+ "I": "001001100",
+ "J": "000011100",
+ "K": "100000011",
+ "L": "001000011",
+ "M": "101000010",
+ "N": "000010011",
+ "O": "100010010",
+ "P": "001010010",
+ "Q": "000000111",
+ "R": "100000110",
+ "S": "001000110",
+ "T": "000010110",
+ "U": "110000001",
+ "V": "011000001",
+ "W": "111000000",
+ "X": "010010001",
+ "Y": "110010000",
+ "Z": "011010000",
+ "-": "010000101",
+ "*": "010010100",
+ "+": "010001010",
+ "$": "010101000",
+ "%": "000101010",
+ "/": "010100010",
+ ".": "110000100",
+ " ": "011000100",
+}
+
+
+class Code39(Barcode):
+ """Convert a text into string binary of black and white markers"""
+
+ def encode(self, text):
+ self.text = text.upper()
+ result = ""
+ # It is possible for us to encode code39
+ # into full ascii, but this feature is
+ # not enabled here
+ for char in "*" + self.text + "*":
+ if char not in ENCODE:
+ char = "-"
+ result = result + ENCODE[char] + "0"
+
+ # Now we need to encode the code39, best read
+ # the code to understand what it's up to:
+ encoded = ""
+ colour = "1" # 1 = Black, 0 = White
+ for data in result:
+ if data == "1":
+ encoded = encoded + colour + colour
+ else:
+ encoded = encoded + colour
+ colour = "0" if colour == "1" else "1"
+
+ return encoded
diff --git a/share/extensions/barcode/Code39Ext.py b/share/extensions/barcode/Code39Ext.py
new file mode 100644
index 0000000..d990680
--- /dev/null
+++ b/share/extensions/barcode/Code39Ext.py
@@ -0,0 +1,97 @@
+# coding=utf-8
+#
+# Copyright (C) 2007 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-1301, USA.
+#
+"""
+Python barcode renderer for Code39 Extended barcodes. Designed for Inkscape.
+"""
+
+from .Code39 import Code39
+
+encode = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
+
+charmap = {}
+
+i = 0
+for char in encode:
+ charmap[char] = i
+ i += 1
+
+
+def get_map(array):
+ """Extended encoding maps for full ASCII Code93"""
+ result = {}
+ for y, x in enumerate(array):
+ result[chr(x)] = encode[y]
+
+ return result
+
+
+# MapA is eclectic, but B, C, D are all ASCII ranges
+mapA = get_map(
+ [
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 0,
+ 64,
+ 96,
+ 127,
+ 127,
+ 127,
+ ]
+) # %
+mapB = get_map(range(1, 26)) # $
+mapC = get_map(range(33, 58)) # /
+mapD = get_map(range(97, 122)) # +
+
+
+class Code39Ext(Code39):
+ """Render Code39 Barcodes"""
+
+ def encode(self, text):
+ # We are only going to extend the Code39 barcodes
+ result = ""
+ for character in text:
+ if character in mapA:
+ character = "%" + mapA[character]
+ elif character in mapB:
+ character = "$" + mapB[character]
+ elif character in mapC:
+ character = "/" + mapC[character]
+ elif character in mapD:
+ character = "+" + mapD[character]
+ result = result + character
+
+ return Code39.encode(self, result)
diff --git a/share/extensions/barcode/Code93.py b/share/extensions/barcode/Code93.py
new file mode 100644
index 0000000..1417b3e
--- /dev/null
+++ b/share/extensions/barcode/Code93.py
@@ -0,0 +1,187 @@
+# coding=utf-8
+#
+# Copyright (C) 2007 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.
+#
+"""
+Python barcode renderer for Code93 barcodes. Designed for use with Inkscape.
+"""
+
+from .Base import Barcode
+
+PALLET = list("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%")
+PALLET.append("($)")
+PALLET.append("(/)")
+PALLET.append("(+)")
+PALLET.append("(%)")
+PALLET.append("MARKER")
+
+MAP = dict((PALLET[i], i) for i in range(len(PALLET)))
+
+
+def get_map(array):
+ """Extended ENCODE maps for full ASCII Code93"""
+ result = {}
+ pos = 10
+ for char in array:
+ result[chr(char)] = PALLET[pos]
+ pos += 1
+ return result
+
+
+# MapA is eclectic, but B, C, D are all ASCII ranges
+MAP_A = get_map(
+ [
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 0,
+ 64,
+ 96,
+ 127,
+ 127,
+ 127,
+ ]
+) # %
+MAP_B = get_map(range(1, 26)) # $
+MAP_C = get_map(range(33, 58)) # /
+MAP_D = get_map(range(97, 122)) # +
+
+ENCODE = [
+ "100010100",
+ "101001000",
+ "101000100",
+ "101000010",
+ "100101000",
+ "100100100",
+ "100100010",
+ "101010000",
+ "100010010",
+ "100001010",
+ "110101000",
+ "110100100",
+ "110100010",
+ "110010100",
+ "110010010",
+ "110001010",
+ "101101000",
+ "101100100",
+ "101100010",
+ "100110100",
+ "100011010",
+ "101011000",
+ "101001100",
+ "101000110",
+ "100101100",
+ "100010110",
+ "110110100",
+ "110110010",
+ "110101100",
+ "110100110",
+ "110010110",
+ "110011010",
+ "101101100",
+ "101100110",
+ "100110110",
+ "100111010",
+ "100101110",
+ "111010100",
+ "111010010",
+ "111001010",
+ "101101110",
+ "101110110",
+ "110101110",
+ "100100110",
+ "111011010",
+ "111010110",
+ "100110010",
+ "101011110",
+ "",
+]
+
+
+class Code93(Barcode):
+ """Encode Code93 Barcode"""
+
+ def encode(self, text):
+ # start marker
+ bits = ENCODE[MAP.get("MARKER", -1)]
+
+ # Extend to ASCII charset ( return Array )
+ text = Code93.encode_ascii(text)
+
+ # Calculate the checksums
+ text.append(Code93.checksum(text, 20)) # C
+ text.append(Code93.checksum(text, 15)) # K
+
+ # Now convert text into the ENCODE bits (black and white stripes)
+ for char in text:
+ bits = bits + ENCODE[MAP.get(char, -1)]
+
+ # end marker and termination bar
+ return bits + ENCODE[MAP.get("MARKER", -1)] + "1"
+
+ @staticmethod
+ def checksum(text, mod):
+ """Generate a code 93 checksum"""
+ weight = len(text) % mod
+ check = 0
+ for char in text:
+ check = check + (MAP[char] * weight)
+ # Reset the weight is required
+ weight -= 1
+ if weight == 0:
+ weight = mod
+
+ return PALLET[check % 47]
+
+ @staticmethod
+ def encode_ascii(text):
+ """Some characters need re-ENCODE into the code93 specification"""
+ result = []
+ for char in text:
+ if char in MAP:
+ result.append(char)
+ elif char in MAP_A:
+ result.append("(%)")
+ result.append(MAP_A[char])
+ elif char in MAP_B:
+ result.append("($)")
+ result.append(MAP_B[char])
+ elif char in MAP_C:
+ result.append("(/)")
+ result.append(MAP_C[char])
+ elif char in MAP_D:
+ result.append("(+)")
+ result.append(MAP_D[char])
+ return result
diff --git a/share/extensions/barcode/Ean13.py b/share/extensions/barcode/Ean13.py
new file mode 100644
index 0000000..21a2e44
--- /dev/null
+++ b/share/extensions/barcode/Ean13.py
@@ -0,0 +1,44 @@
+# coding=utf-8
+#
+# Copyright (C) 2010 Martin Owens
+#
+# Thanks to Lineaire Chez of Inkbar ( www.inkbar.lineaire.net )
+#
+# 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.
+#
+"""
+Python barcode renderer for EAN13 barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+
+
+class Ean13(EanBarcode):
+ """Provide an Ean13 barcode generator"""
+
+ name = "ean13"
+ extras = {2: "Ean2", 5: "Ean5"}
+ checks = [13]
+ lengths = [12]
+
+ def _encode(self, num, guide=False):
+ """Encode an ean13 barcode"""
+ self.text = EanBarcode.space(num[0:1], 4, num[1:7], 5, num[7:], 7)
+ if guide:
+ self.text = self.text[:-4] + ">"
+ return self.enclose(
+ EanBarcode.encode_interleaved(num[0], num[1:7]),
+ EanBarcode.encode_right(num[7:]),
+ )
diff --git a/share/extensions/barcode/Ean2.py b/share/extensions/barcode/Ean2.py
new file mode 100644
index 0000000..1025965
--- /dev/null
+++ b/share/extensions/barcode/Ean2.py
@@ -0,0 +1,40 @@
+# coding=utf-8
+#
+# Copyright (C) 2016 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.
+#
+"""
+Python barcode renderer for EAN2 barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+
+FAMS = ["00", "01", "10", "11"]
+START = "01011"
+
+
+class Ean2(EanBarcode):
+ """Provide an Ean5 barcode generator"""
+
+ length = 2
+ name = "ean5"
+
+ def _encode(self, num, guide=False):
+ if len(num) != 2:
+ num = ([0, 0] + num)[-2:]
+ self.text = " ".join(EanBarcode.space(num))
+ family = ((num[0] * 10) + num[1]) % 4
+ return START + "01".join(EanBarcode.encode_interleaved(family, num, FAMS))
diff --git a/share/extensions/barcode/Ean5.py b/share/extensions/barcode/Ean5.py
new file mode 100644
index 0000000..3c84290
--- /dev/null
+++ b/share/extensions/barcode/Ean5.py
@@ -0,0 +1,50 @@
+# coding=utf-8
+#
+# Copyright (C) 2009 Aaron C Spike
+# 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.
+#
+"""
+Python barcode renderer for EAN5 barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+
+FAMS = [
+ "11000",
+ "10100",
+ "10010",
+ "10001",
+ "01100",
+ "00110",
+ "00011",
+ "01010",
+ "01001",
+ "00101",
+]
+START = "01011"
+
+
+class Ean5(EanBarcode):
+ """Provide an Ean5 barcode generator"""
+
+ name = "ean5"
+ length = 5
+
+ def _encode(self, num, guide=False):
+ self.text = " ".join(EanBarcode.space(num))
+ family = sum([int(n) * int(m) for n, m in zip(num, "39393")]) % 10
+ return START + "01".join(EanBarcode.encode_interleaved(family, num, FAMS))
diff --git a/share/extensions/barcode/Ean8.py b/share/extensions/barcode/Ean8.py
new file mode 100644
index 0000000..d6875fc
--- /dev/null
+++ b/share/extensions/barcode/Ean8.py
@@ -0,0 +1,38 @@
+# 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.
+#
+"""
+Python barcode renderer for EAN8 barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+
+
+class Ean8(EanBarcode):
+ """Provide an EAN8 barcode generator"""
+
+ name = "ean8"
+ checks = [8]
+ lengths = [7]
+
+ def _encode(self, num, guide=False):
+ """Encode an ean8 barcode"""
+ self.text = EanBarcode.space(num[:4], 3, num[4:])
+ return self.enclose(
+ EanBarcode.encode_left(num[:4]), EanBarcode.encode_right(num[4:])
+ )
diff --git a/share/extensions/barcode/Rm4scc.py b/share/extensions/barcode/Rm4scc.py
new file mode 100644
index 0000000..b4d52ba
--- /dev/null
+++ b/share/extensions/barcode/Rm4scc.py
@@ -0,0 +1,139 @@
+# coding=utf-8
+#
+# Copyright (C) 2007 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-1301, USA.
+#
+"""
+Python barcode renderer for RM4CC barcodes. Designed for use with Inkscape.
+"""
+
+from .Base import Barcode
+
+charmap = {
+ "(": "25",
+ ")": "3",
+ "0": "05053535",
+ "1": "05152535",
+ "2": "05153525",
+ "3": "15052535",
+ "4": "15053525",
+ "5": "15152525",
+ "6": "05251535",
+ "7": "05350535",
+ "8": "05351525",
+ "9": "15250535",
+ "A": "15251525",
+ "B": "15350525",
+ "C": "05253515",
+ "D": "05352515",
+ "E": "05353505",
+ "F": "15252515",
+ "G": "15253505",
+ "H": "15352505",
+ "I": "25051535",
+ "J": "25150535",
+ "K": "25151525",
+ "L": "35050535",
+ "M": "35051525",
+ "N": "35150525",
+ "O": "25053525",
+ "P": "25152515",
+ "Q": "25153505",
+ "R": "35052515",
+ "S": "35053505",
+ "T": "35152505",
+ "U": "25251515",
+ "V": "25350515",
+ "W": "25351505",
+ "X": "35250515",
+ "Y": "35251505",
+ "Z": "35350505",
+}
+
+check = ["ZUVWXY", "501234", "B6789A", "HCDEFG", "NIJKLM", "TOPQRS"]
+(BAR_TRACK, BAR_DOWN, BAR_UP, BAR_FULL, BAR_NONE, WHITE_SPACE) = range(6)
+
+
+class Rm4scc(Barcode):
+ """Provice a Rm4scc barcode generator"""
+
+ default_height = 18
+
+ def encode(self, text):
+ result = ""
+
+ text = text.upper()
+ text.replace("(", "")
+ text.replace(")", "")
+
+ text = "(" + text + Rm4scc.checksum(text) + ")"
+
+ i = 0
+ for char in text:
+ if char in charmap:
+ result = result + charmap[char]
+ i += 1
+
+ return result
+
+ @staticmethod
+ def checksum(text):
+ """given a string of data, return the check character"""
+ total_lower = 0
+ total_upper = 0
+ for char in text:
+ if char in charmap:
+ bars = charmap[char][0:8:2]
+ lower = 0
+ upper = 0
+
+ if int(bars[0]) & 1:
+ lower += 4
+ if int(bars[1]) & 1:
+ lower += 2
+ if int(bars[2]) & 1:
+ lower += 1
+ if int(bars[0]) & 2:
+ upper += 4
+ if int(bars[1]) & 2:
+ upper += 2
+ if int(bars[2]) & 2:
+ upper += 1
+ total_lower += lower % 6
+ total_upper += upper % 6
+
+ total_lower = total_upper % 6
+ total_upper %= 6
+
+ checkchar = check[total_upper][total_lower]
+ return checkchar
+
+ def get_style(self, index):
+ """Royal Mail Barcodes use a completely different style"""
+ result = {"width": 2, "write": True, "top": 0}
+ if index == BAR_TRACK: # Track Bar
+ result["top"] = 6
+ result["height"] = 5
+ elif index == BAR_DOWN: # Decender Bar
+ result["top"] = 6
+ result["height"] = 11
+ elif index == BAR_UP: # Accender Bar
+ result["height"] = 11
+ elif index == BAR_FULL: # Full Bar
+ result["height"] = 17
+ elif index == WHITE_SPACE: # White Space
+ result["write"] = False
+ return result
diff --git a/share/extensions/barcode/Upca.py b/share/extensions/barcode/Upca.py
new file mode 100644
index 0000000..f278fca
--- /dev/null
+++ b/share/extensions/barcode/Upca.py
@@ -0,0 +1,40 @@
+# coding=utf-8
+#
+# Copyright (C) 2007 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.
+#
+"""
+Python barcode renderer for UPCA barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+
+
+class Upca(EanBarcode):
+ """Provides a renderer for EAN12 aka UPC-A Barcodes"""
+
+ name = "upca"
+ font_size = 10
+ lengths = [11]
+ checks = [12]
+
+ def _encode(self, num, guide=False):
+ """Encode for a UPC-A Barcode"""
+ self.text = EanBarcode.space(num[0:1], 3, num[1:6], 4, num[6:11], 3, num[11:])
+ return self.enclose(
+ EanBarcode.encode_left(num[0:6]),
+ EanBarcode.encode_right(num[6:12]),
+ )
diff --git a/share/extensions/barcode/Upce.py b/share/extensions/barcode/Upce.py
new file mode 100644
index 0000000..9404ca2
--- /dev/null
+++ b/share/extensions/barcode/Upce.py
@@ -0,0 +1,112 @@
+# 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.
+#
+"""
+Python barcode renderer for UPCE barcodes. Designed for use with Inkscape.
+"""
+
+from .BaseEan import EanBarcode
+from inkex.localization import inkex_gettext as _
+
+# This is almost exactly the same as the standard FAMILIES
+# But flipped around and with the first 111000 instead of 000000.
+FAMS = [
+ "111000",
+ "110100",
+ "110010",
+ "110001",
+ "101100",
+ "100110",
+ "100011",
+ "101010",
+ "101001",
+ "100101",
+]
+
+
+class Upce(EanBarcode):
+ """Generate EAN6/UPC-E barcode generator"""
+
+ name = "upce"
+ font_size = 10
+ lengths = [6, 11]
+ checks = [7, 12]
+ center_bar = "020"
+
+ def _encode(self, num, guide=False):
+ """Generate a UPC-E Barcode"""
+ self.text = EanBarcode.space(["0"], 2, num[:6], 2, num[-1])
+ code = EanBarcode.encode_interleaved(num[-1], num[:6], FAMS)
+ return self.enclose(code)
+
+ def append_checksum(self, number):
+ """Generate a UPCE Checksum"""
+ if len(number) == 6:
+ number = Upce.convert_e2a(number)
+ result = self.get_checksum(number)
+ return Upce.convert_a2e(number) + result
+
+ @staticmethod
+ def convert_a2e(number):
+ """Converting UPC-A to UPC-E, may cause errors."""
+ # All UPC-E Numbers use number system 0
+ if number[0] != "0" or len(number) != 11:
+ # If not then the code is invalid
+ raise ValueError(_("Invalid UPC Number"))
+
+ # Most of the conversions deal
+ # with the specific code parts
+ maker = number[1:6]
+ product = number[6:11]
+
+ # There are 4 cases to convert:
+ if maker[2:] == "000" or maker[2:] == "100" or maker[2:] == "200":
+ # Maximum number product code digits can be encoded
+ if product[:2] == "00":
+ return maker[:2] + product[2:] + maker[2]
+ elif maker[3:5] == "00":
+ # Now only 2 product code digits can be used
+ if product[:3] == "000":
+ return maker[:3] + product[3:] + "3"
+ elif maker[4] == "0":
+ # With even more maker code we have less room for product code
+ if product[:4] == "0000":
+ return maker[0:4] + product[4] + "4"
+ elif product[:4] == "0000" and int(product[4]) > 4:
+ # The last recorse is to try and squeeze it in the last 5 numbers
+ # so long as the product is 00005-00009 so as not to conflict with
+ # the 0-4 used above.
+ return maker + product[4]
+ # Invalid UPC-A Numbe
+ raise ValueError(_("Invalid UPC Number"))
+
+ @staticmethod
+ def convert_e2a(number):
+ """Convert UPC-E to UPC-A by padding with zeros"""
+ # It's more likly to convert this without fault
+ # But we still must be mindful of the 4 conversions
+ if len(number) != 6:
+ return None
+
+ if number[5] in ["0", "1", "2"]:
+ return "0" + number[:2] + number[5] + "0000" + number[2:5]
+ if number[5] == "3":
+ return "0" + number[:3] + "00000" + number[3:5]
+ if number[5] == "4":
+ return "0" + number[:4] + "00000" + number[4]
+ return "0" + number[:5] + "0000" + number[5]
diff --git a/share/extensions/barcode/__init__.py b/share/extensions/barcode/__init__.py
new file mode 100644
index 0000000..1bfe281
--- /dev/null
+++ b/share/extensions/barcode/__init__.py
@@ -0,0 +1,77 @@
+# coding=utf-8
+#
+# Copyright (C) 2014 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-1301, USA.
+#
+# pylint: disable=no-self-use
+"""
+Renderer for barcodes, SVG extension for Inkscape.
+
+For supported barcodes see Barcode module directory.
+"""
+
+from inkex.localization import inkex_gettext as _
+
+# This lists all known Barcodes missing from this package
+# ===== UPC-Based Extensions ====== #
+# Code11
+# ========= Code25-Based ========== #
+# Codabar
+# Postnet
+# ITF25
+# ========= Alpha-numeric ========= #
+# Code39Mod
+# USPS128
+# =========== 2D Based ============ #
+# PDF417
+# PDF417-Macro
+# PDF417-Truncated
+# PDF417-GLI
+
+
+class NoBarcode:
+ """Simple class for no barcode"""
+
+ def __init__(self, msg):
+ self.msg = msg
+
+ def encode(self, text):
+ """Encode the text into a barcode pattern"""
+ raise ValueError(_("No barcode encoder: {}").format(self.msg))
+
+ def generate(self):
+ """Generate actual svg from the barcode pattern"""
+ return None
+
+
+def get_barcode(code, **kw):
+ """Gets a barcode from a list of available barcode formats"""
+ if not code:
+ return NoBarcode(_("No barcode format given."))
+
+ code = str(code).replace("-", "").strip()
+ module = "barcode." + code
+ lst = ["barcode"]
+ try:
+ return getattr(__import__(module, fromlist=lst), code)(kw)
+ except ImportError as err:
+ if code in str(err):
+ return NoBarcode(_("Invalid type of barcode: {}.{}").format(module, code))
+ raise
+ except AttributeError:
+ return NoBarcode(
+ _("Barcode module is missing barcode class: {}.{}").format(module, code)
+ )