Primer commit
This commit is contained in:
BIN
venv/lib/python3.11/site-packages/barcode/DejaVuSansMono.ttf
Executable file
BIN
venv/lib/python3.11/site-packages/barcode/DejaVuSansMono.ttf
Executable file
Binary file not shown.
127
venv/lib/python3.11/site-packages/barcode/__init__.py
Normal file
127
venv/lib/python3.11/site-packages/barcode/__init__.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""This package provides a simple way to create standard barcodes.
|
||||
It needs no external packages to be installed, the barcodes are
|
||||
created as SVG objects. If Pillow is installed, the barcodes can also be
|
||||
rendered as images (all formats supported by Pillow).
|
||||
"""
|
||||
import os
|
||||
from typing import BinaryIO
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
from barcode.codabar import CODABAR
|
||||
from barcode.codex import PZN
|
||||
from barcode.codex import Code39
|
||||
from barcode.codex import Code128
|
||||
from barcode.codex import Gs1_128
|
||||
from barcode.ean import EAN8
|
||||
from barcode.ean import EAN8_GUARD
|
||||
from barcode.ean import EAN13
|
||||
from barcode.ean import EAN13_GUARD
|
||||
from barcode.ean import EAN14
|
||||
from barcode.ean import JAN
|
||||
from barcode.errors import BarcodeNotFoundError
|
||||
from barcode.isxn import ISBN10
|
||||
from barcode.isxn import ISBN13
|
||||
from barcode.isxn import ISSN
|
||||
from barcode.itf import ITF
|
||||
from barcode.upc import UPCA
|
||||
from barcode.version import version # noqa: F401
|
||||
|
||||
__BARCODE_MAP = {
|
||||
"ean8": EAN8,
|
||||
"ean8-guard": EAN8_GUARD,
|
||||
"ean13": EAN13,
|
||||
"ean13-guard": EAN13_GUARD,
|
||||
"ean": EAN13,
|
||||
"gtin": EAN14,
|
||||
"ean14": EAN14,
|
||||
"jan": JAN,
|
||||
"upc": UPCA,
|
||||
"upca": UPCA,
|
||||
"isbn": ISBN13,
|
||||
"isbn13": ISBN13,
|
||||
"gs1": ISBN13,
|
||||
"isbn10": ISBN10,
|
||||
"issn": ISSN,
|
||||
"code39": Code39,
|
||||
"pzn": PZN,
|
||||
"code128": Code128,
|
||||
"itf": ITF,
|
||||
"gs1_128": Gs1_128,
|
||||
"codabar": CODABAR,
|
||||
"nw-7": CODABAR,
|
||||
}
|
||||
|
||||
PROVIDED_BARCODES = list(__BARCODE_MAP)
|
||||
PROVIDED_BARCODES.sort()
|
||||
|
||||
|
||||
def get(
|
||||
name: str,
|
||||
code: Optional[str] = None,
|
||||
writer=None,
|
||||
options: Optional[dict] = None,
|
||||
):
|
||||
"""Helper method for getting a generator or even a generated code.
|
||||
|
||||
:param name: The name of the type of barcode desired.
|
||||
:param code: The actual information to encode. If this parameter is
|
||||
provided, a generated barcode is returned. Otherwise, the barcode class
|
||||
is returned.
|
||||
:param Writer writer: An alternative writer to use when generating the
|
||||
barcode.
|
||||
:param options: Additional options to be passed on to the barcode when
|
||||
generating.
|
||||
"""
|
||||
options = options or {}
|
||||
try:
|
||||
barcode = __BARCODE_MAP[name.lower()]
|
||||
except KeyError as e:
|
||||
raise BarcodeNotFoundError(f"The barcode {name!r} is not known.") from e
|
||||
if code is not None:
|
||||
return barcode(code, writer, **options)
|
||||
|
||||
return barcode
|
||||
|
||||
|
||||
def get_class(name):
|
||||
return get_barcode(name)
|
||||
|
||||
|
||||
def generate(
|
||||
name: str,
|
||||
code: str,
|
||||
writer=None,
|
||||
output: Union[str, os.PathLike, BinaryIO, None] = None,
|
||||
writer_options: Union[Dict, None] = None,
|
||||
text: Union[str, None] = None,
|
||||
):
|
||||
"""Shortcut to generate a barcode in one line.
|
||||
|
||||
:param name: Name of the type of barcode to use.
|
||||
:param code: Data to encode into the barcode.
|
||||
:param writer: A writer to use (e.g.: ImageWriter or SVGWriter).
|
||||
:param output: Destination file-like or path-like where to save the generated
|
||||
barcode.
|
||||
:param writer_options: Options to pass on to the writer instance.
|
||||
:param text: Text to render under the barcode.
|
||||
"""
|
||||
from barcode.base import Barcode
|
||||
|
||||
writer = writer or Barcode.default_writer()
|
||||
writer.set_options(writer_options or {})
|
||||
|
||||
barcode = get(name, code, writer)
|
||||
|
||||
if isinstance(output, str):
|
||||
return barcode.save(output, writer_options, text)
|
||||
if output:
|
||||
barcode.write(output, writer_options, text)
|
||||
return None
|
||||
|
||||
raise TypeError("'output' cannot be None")
|
||||
|
||||
|
||||
get_barcode = get
|
||||
get_barcode_class = get_class
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
100
venv/lib/python3.11/site-packages/barcode/base.py
Normal file
100
venv/lib/python3.11/site-packages/barcode/base.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""barcode.base
|
||||
|
||||
"""
|
||||
from typing import ClassVar
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
from barcode.writer import BaseWriter
|
||||
from barcode.writer import SVGWriter
|
||||
|
||||
|
||||
class Barcode:
|
||||
name = ""
|
||||
|
||||
digits = 0
|
||||
|
||||
default_writer = SVGWriter
|
||||
|
||||
default_writer_options: ClassVar[dict] = {
|
||||
"module_width": 0.2,
|
||||
"module_height": 15.0,
|
||||
"quiet_zone": 6.5,
|
||||
"font_size": 10,
|
||||
"text_distance": 5.0,
|
||||
"background": "white",
|
||||
"foreground": "black",
|
||||
"write_text": True,
|
||||
"text": "",
|
||||
}
|
||||
|
||||
writer: BaseWriter
|
||||
|
||||
def to_ascii(self) -> str:
|
||||
code = self.build()
|
||||
for i, line in enumerate(code):
|
||||
code[i] = line.replace("1", "X").replace("0", " ")
|
||||
return "\n".join(code)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.__class__.__name__}({self.get_fullcode()!r})>"
|
||||
|
||||
def build(self) -> List[str]:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_fullcode(self):
|
||||
"""Returns the full code, encoded in the barcode.
|
||||
|
||||
:returns: Full human readable code.
|
||||
:rtype: String
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def save(
|
||||
self, filename: str, options: Optional[dict] = None, text: Optional[str] = None
|
||||
) -> str:
|
||||
"""Renders the barcode and saves it in `filename`.
|
||||
|
||||
:param filename: Filename to save the barcode in (without filename extension).
|
||||
:param options: The same as in `self.render`.
|
||||
:param text: Text to render under the barcode.
|
||||
|
||||
:returns: The full filename with extension.
|
||||
"""
|
||||
output = self.render(options, text) if text else self.render(options)
|
||||
|
||||
return self.writer.save(filename, output)
|
||||
|
||||
def write(self, fp, options=None, text=None):
|
||||
"""Renders the barcode and writes it to the file like object
|
||||
`fp`.
|
||||
|
||||
:parameters:
|
||||
fp : File like object
|
||||
Object to write the raw data in.
|
||||
options : Dict
|
||||
The same as in `self.render`.
|
||||
text : str
|
||||
Text to render under the barcode.
|
||||
"""
|
||||
output = self.render(options, text)
|
||||
self.writer.write(output, fp)
|
||||
|
||||
def render(self, writer_options: Optional[dict] = None, text: Optional[str] = None):
|
||||
"""Renders the barcode using `self.writer`.
|
||||
|
||||
:param writer_options: Options for `self.writer`, see writer docs for details.
|
||||
:param text: Text to render under the barcode.
|
||||
|
||||
:returns: Output of the writers render method.
|
||||
"""
|
||||
options = self.default_writer_options.copy()
|
||||
options.update(writer_options or {})
|
||||
if options["write_text"] or text is not None:
|
||||
if text is not None:
|
||||
options["text"] = text
|
||||
else:
|
||||
options["text"] = self.get_fullcode()
|
||||
self.writer.set_options(options)
|
||||
code = self.build()
|
||||
return self.writer.render(code)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
# W = Wide bar
|
||||
# w = wide space
|
||||
# N = Narrow bar
|
||||
# n = narrow space
|
||||
|
||||
CODES = {
|
||||
"0": "NnNnNwW",
|
||||
"1": "NnNnWwN",
|
||||
"2": "NnNwNnW",
|
||||
"3": "WwNnNnN",
|
||||
"4": "NnWnNwN",
|
||||
"5": "WnNnNwN",
|
||||
"6": "NwNnNnW",
|
||||
"7": "NwNnWnN",
|
||||
"8": "NwWnNnN",
|
||||
"9": "WnNwNnN",
|
||||
"-": "NnNwWnN",
|
||||
"$": "NnWwNnN",
|
||||
":": "WnNnWnW",
|
||||
"/": "WnWnNnW",
|
||||
".": "WnWnWnN",
|
||||
"+": "NnWnWnW",
|
||||
}
|
||||
|
||||
STARTSTOP = {"A": "NnWwNwN", "B": "NwNwNnW", "C": "NnNwNwW", "D": "NnNwWwN"}
|
||||
216
venv/lib/python3.11/site-packages/barcode/charsets/code128.py
Normal file
216
venv/lib/python3.11/site-packages/barcode/charsets/code128.py
Normal file
@@ -0,0 +1,216 @@
|
||||
import string
|
||||
|
||||
# Charsets for code 128
|
||||
|
||||
_common = (
|
||||
" ",
|
||||
"!",
|
||||
'"',
|
||||
"#",
|
||||
"$",
|
||||
"%",
|
||||
"&",
|
||||
"'",
|
||||
"(",
|
||||
")",
|
||||
"*",
|
||||
"+",
|
||||
",",
|
||||
"-",
|
||||
".",
|
||||
"/",
|
||||
*tuple(string.digits),
|
||||
":",
|
||||
";",
|
||||
"<",
|
||||
"=",
|
||||
">",
|
||||
"?",
|
||||
"@",
|
||||
*tuple(string.ascii_uppercase),
|
||||
"[",
|
||||
"\\",
|
||||
"]",
|
||||
"^",
|
||||
"_",
|
||||
)
|
||||
|
||||
_charset_a = (
|
||||
*_common,
|
||||
"\x00",
|
||||
"\x01",
|
||||
"\x02",
|
||||
"\x03",
|
||||
"\x04",
|
||||
"\x05",
|
||||
"\x06",
|
||||
"\x07",
|
||||
"\x08",
|
||||
"\t",
|
||||
"\n",
|
||||
"\x0b",
|
||||
"\x0c",
|
||||
"\r",
|
||||
"\x0e",
|
||||
"\x0f",
|
||||
"\x10",
|
||||
"\x11",
|
||||
"\x12",
|
||||
"\x13",
|
||||
"\x14",
|
||||
"\x15",
|
||||
"\x16",
|
||||
"\x17",
|
||||
"\x18",
|
||||
"\x19",
|
||||
"\x1a",
|
||||
"\x1b",
|
||||
"\x1c",
|
||||
"\x1d",
|
||||
"\x1e",
|
||||
"\x1f",
|
||||
"ó",
|
||||
"ò",
|
||||
"SHIFT",
|
||||
"TO_C",
|
||||
"TO_B",
|
||||
"ô",
|
||||
"ñ",
|
||||
)
|
||||
|
||||
_charset_b = (
|
||||
*_common,
|
||||
"`",
|
||||
*tuple(string.ascii_lowercase),
|
||||
"{",
|
||||
"|",
|
||||
"}",
|
||||
"~",
|
||||
"\x7f",
|
||||
"ó",
|
||||
"ò",
|
||||
"SHIFT",
|
||||
"TO_C",
|
||||
"ô",
|
||||
"TO_A",
|
||||
"ñ",
|
||||
)
|
||||
|
||||
ALL = set(_common + _charset_a + _charset_b)
|
||||
A = {c: i for i, c in enumerate(_charset_a)}
|
||||
B = {c: i for i, c in enumerate(_charset_b)}
|
||||
C = {"TO_B": 100, "TO_A": 101, "\xf1": 102}
|
||||
|
||||
CODES = (
|
||||
"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",
|
||||
)
|
||||
|
||||
STOP = "11000111010"
|
||||
|
||||
START_CODES = {"A": 103, "B": 104, "C": 105}
|
||||
TO = {101: START_CODES["A"], 100: START_CODES["B"], 99: START_CODES["C"]}
|
||||
61
venv/lib/python3.11/site-packages/barcode/charsets/code39.py
Normal file
61
venv/lib/python3.11/site-packages/barcode/charsets/code39.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import string
|
||||
|
||||
# Charsets for code 39
|
||||
REF = (
|
||||
tuple(string.digits)
|
||||
+ tuple(string.ascii_uppercase)
|
||||
+ ("-", ".", " ", "$", "/", "+", "%")
|
||||
)
|
||||
B = "1"
|
||||
E = "0"
|
||||
CODES = (
|
||||
"101000111011101",
|
||||
"111010001010111",
|
||||
"101110001010111",
|
||||
"111011100010101",
|
||||
"101000111010111",
|
||||
"111010001110101",
|
||||
"101110001110101",
|
||||
"101000101110111",
|
||||
"111010001011101",
|
||||
"101110001011101",
|
||||
"111010100010111",
|
||||
"101110100010111",
|
||||
"111011101000101",
|
||||
"101011100010111",
|
||||
"111010111000101",
|
||||
"101110111000101",
|
||||
"101010001110111",
|
||||
"111010100011101",
|
||||
"101110100011101",
|
||||
"101011100011101",
|
||||
"111010101000111",
|
||||
"101110101000111",
|
||||
"111011101010001",
|
||||
"101011101000111",
|
||||
"111010111010001",
|
||||
"101110111010001",
|
||||
"101010111000111",
|
||||
"111010101110001",
|
||||
"101110101110001",
|
||||
"101011101110001",
|
||||
"111000101010111",
|
||||
"100011101010111",
|
||||
"111000111010101",
|
||||
"100010111010111",
|
||||
"111000101110101",
|
||||
"100011101110101",
|
||||
"100010101110111",
|
||||
"111000101011101",
|
||||
"100011101011101",
|
||||
"100010001000101",
|
||||
"100010001010001",
|
||||
"100010100010001",
|
||||
"101000100010001",
|
||||
)
|
||||
|
||||
EDGE = "100010111011101"
|
||||
MIDDLE = "0"
|
||||
|
||||
# MAP for assigning every symbol (REF) to (reference number, barcode)
|
||||
MAP = dict(zip(REF, enumerate(CODES)))
|
||||
52
venv/lib/python3.11/site-packages/barcode/charsets/ean.py
Normal file
52
venv/lib/python3.11/site-packages/barcode/charsets/ean.py
Normal file
@@ -0,0 +1,52 @@
|
||||
EDGE = "101"
|
||||
MIDDLE = "01010"
|
||||
CODES = {
|
||||
"A": (
|
||||
"0001101",
|
||||
"0011001",
|
||||
"0010011",
|
||||
"0111101",
|
||||
"0100011",
|
||||
"0110001",
|
||||
"0101111",
|
||||
"0111011",
|
||||
"0110111",
|
||||
"0001011",
|
||||
),
|
||||
"B": (
|
||||
"0100111",
|
||||
"0110011",
|
||||
"0011011",
|
||||
"0100001",
|
||||
"0011101",
|
||||
"0111001",
|
||||
"0000101",
|
||||
"0010001",
|
||||
"0001001",
|
||||
"0010111",
|
||||
),
|
||||
"C": (
|
||||
"1110010",
|
||||
"1100110",
|
||||
"1101100",
|
||||
"1000010",
|
||||
"1011100",
|
||||
"1001110",
|
||||
"1010000",
|
||||
"1000100",
|
||||
"1001000",
|
||||
"1110100",
|
||||
),
|
||||
}
|
||||
LEFT_PATTERN = (
|
||||
"AAAAAA",
|
||||
"AABABB",
|
||||
"AABBAB",
|
||||
"AABBBA",
|
||||
"ABAABB",
|
||||
"ABBAAB",
|
||||
"ABBBAA",
|
||||
"ABABAB",
|
||||
"ABABBA",
|
||||
"ABBABA",
|
||||
)
|
||||
19
venv/lib/python3.11/site-packages/barcode/charsets/itf.py
Normal file
19
venv/lib/python3.11/site-packages/barcode/charsets/itf.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# W = Wide bar
|
||||
# w = wide space
|
||||
# N = Narrow bar
|
||||
# n = narrow space
|
||||
|
||||
START = "NnNn"
|
||||
STOP = "WnN"
|
||||
CODES = (
|
||||
"NNWWN",
|
||||
"WNNNW",
|
||||
"NWNNW",
|
||||
"WWNNN",
|
||||
"NNWNW",
|
||||
"WNWNN",
|
||||
"NWWNN",
|
||||
"NNNWW",
|
||||
"WNNWN",
|
||||
"NWNWN",
|
||||
)
|
||||
28
venv/lib/python3.11/site-packages/barcode/charsets/upc.py
Normal file
28
venv/lib/python3.11/site-packages/barcode/charsets/upc.py
Normal file
@@ -0,0 +1,28 @@
|
||||
EDGE = "101"
|
||||
MIDDLE = "01010"
|
||||
CODES = {
|
||||
"L": (
|
||||
"0001101",
|
||||
"0011001",
|
||||
"0010011",
|
||||
"0111101",
|
||||
"0100011",
|
||||
"0110001",
|
||||
"0101111",
|
||||
"0111011",
|
||||
"0110111",
|
||||
"0001011",
|
||||
),
|
||||
"R": (
|
||||
"1110010",
|
||||
"1100110",
|
||||
"1101100",
|
||||
"1000010",
|
||||
"1011100",
|
||||
"1001110",
|
||||
"1010000",
|
||||
"1000100",
|
||||
"1001000",
|
||||
"1110100",
|
||||
),
|
||||
}
|
||||
75
venv/lib/python3.11/site-packages/barcode/codabar.py
Normal file
75
venv/lib/python3.11/site-packages/barcode/codabar.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""Module: barcode.codabar
|
||||
|
||||
:Provided barcodes: Codabar (NW-7)
|
||||
"""
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from barcode.base import Barcode
|
||||
from barcode.charsets import codabar
|
||||
from barcode.errors import BarcodeError
|
||||
from barcode.errors import IllegalCharacterError
|
||||
|
||||
|
||||
class CODABAR(Barcode):
|
||||
"""Initializes a new CODABAR instance.
|
||||
|
||||
:parameters:
|
||||
code : String
|
||||
Codabar (NW-7) string that matches [ABCD][0-9$:/.+-]+[ABCD]
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
narrow: Integer
|
||||
Width of the narrow elements (default: 2)
|
||||
wide: Integer
|
||||
Width of the wide elements (default: 5)
|
||||
wide/narrow must be in the range 2..3
|
||||
"""
|
||||
|
||||
name = "Codabar (NW-7)"
|
||||
|
||||
def __init__(self, code, writer=None, narrow=2, wide=5) -> None:
|
||||
self.code = code
|
||||
self.writer = writer or self.default_writer()
|
||||
self.narrow = narrow
|
||||
self.wide = wide
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.code
|
||||
|
||||
def get_fullcode(self):
|
||||
return self.code
|
||||
|
||||
def build(self):
|
||||
try:
|
||||
data = (
|
||||
codabar.STARTSTOP[self.code[0]] + "n"
|
||||
) # Start with [A-D], followed by a narrow space
|
||||
|
||||
except KeyError:
|
||||
raise BarcodeError("Codabar should start with either A,B,C or D") from None
|
||||
|
||||
try:
|
||||
data += "n".join(
|
||||
[codabar.CODES[c] for c in self.code[1:-1]]
|
||||
) # separated by a narrow space
|
||||
except KeyError:
|
||||
raise IllegalCharacterError(
|
||||
"Codabar can only contain numerics or $:/.+-"
|
||||
) from None
|
||||
|
||||
try:
|
||||
data += "n" + codabar.STARTSTOP[self.code[-1]] # End with [A-D]
|
||||
except KeyError:
|
||||
raise BarcodeError("Codabar should end with either A,B,C or D") from None
|
||||
|
||||
raw = ""
|
||||
for e in data:
|
||||
if e == "W":
|
||||
raw += "1" * self.wide
|
||||
if e == "w":
|
||||
raw += "0" * self.wide
|
||||
if e == "N":
|
||||
raw += "1" * self.narrow
|
||||
if e == "n":
|
||||
raw += "0" * self.narrow
|
||||
return [raw]
|
||||
279
venv/lib/python3.11/site-packages/barcode/codex.py
Normal file
279
venv/lib/python3.11/site-packages/barcode/codex.py
Normal file
@@ -0,0 +1,279 @@
|
||||
"""Module: barcode.codex
|
||||
|
||||
:Provided barcodes: Code 39, Code 128, PZN
|
||||
"""
|
||||
|
||||
from typing import Collection
|
||||
|
||||
from barcode.base import Barcode
|
||||
from barcode.charsets import code39
|
||||
from barcode.charsets import code128
|
||||
from barcode.errors import BarcodeError
|
||||
from barcode.errors import IllegalCharacterError
|
||||
from barcode.errors import NumberOfDigitsError
|
||||
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
# Sizes
|
||||
MIN_SIZE = 0.2
|
||||
MIN_QUIET_ZONE = 2.54
|
||||
|
||||
|
||||
def check_code(code: str, name: str, allowed: Collection[str]) -> None:
|
||||
wrong = []
|
||||
for char in code:
|
||||
if char not in allowed:
|
||||
wrong.append(char)
|
||||
if wrong:
|
||||
raise IllegalCharacterError(
|
||||
"The following characters are not valid for {name}: {wrong}".format(
|
||||
name=name, wrong=", ".join(wrong)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Code39(Barcode):
|
||||
"""A Code39 barcode implementation"""
|
||||
|
||||
name = "Code 39"
|
||||
|
||||
def __init__(self, code: str, writer=None, add_checksum: bool = True) -> None:
|
||||
r"""
|
||||
:param code: Code 39 string without \* and without checksum.
|
||||
:param writer: A ``barcode.writer`` instance used to render the barcode
|
||||
(default: SVGWriter).
|
||||
:param add_checksum: Add the checksum to code or not
|
||||
"""
|
||||
|
||||
self.code = code.upper()
|
||||
if add_checksum:
|
||||
self.code += self.calculate_checksum()
|
||||
self.writer = writer or self.default_writer()
|
||||
check_code(self.code, self.name, code39.REF)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.code
|
||||
|
||||
def get_fullcode(self) -> str:
|
||||
""":returns: The full code as it will be encoded."""
|
||||
return self.code
|
||||
|
||||
def calculate_checksum(self):
|
||||
check = sum(code39.MAP[x][0] for x in self.code) % 43
|
||||
for k, v in code39.MAP.items():
|
||||
if check == v[0]:
|
||||
return k
|
||||
return None
|
||||
|
||||
def build(self):
|
||||
chars = [code39.EDGE]
|
||||
for char in self.code:
|
||||
chars.append(code39.MAP[char][1])
|
||||
chars.append(code39.EDGE)
|
||||
return [code39.MIDDLE.join(chars)]
|
||||
|
||||
def render(self, writer_options=None, text=None):
|
||||
options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE}
|
||||
options.update(writer_options or {})
|
||||
return super().render(options, text)
|
||||
|
||||
|
||||
class PZN7(Code39):
|
||||
"""Initializes new German number for pharmaceutical products.
|
||||
|
||||
:parameters:
|
||||
pzn : String
|
||||
Code to render.
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
"""
|
||||
|
||||
name = "Pharmazentralnummer"
|
||||
|
||||
digits = 6
|
||||
|
||||
def __init__(self, pzn, writer=None) -> None:
|
||||
pzn = pzn[: self.digits]
|
||||
if not pzn.isdigit():
|
||||
raise IllegalCharacterError("PZN can only contain numbers.")
|
||||
if len(pzn) != self.digits:
|
||||
raise NumberOfDigitsError(
|
||||
f"PZN must have {self.digits} digits, not {len(pzn)}."
|
||||
)
|
||||
self.pzn = pzn
|
||||
self.pzn = f"{pzn}{self.calculate_checksum()}"
|
||||
super().__init__(f"PZN-{self.pzn}", writer, add_checksum=False)
|
||||
|
||||
def get_fullcode(self):
|
||||
return f"PZN-{self.pzn}"
|
||||
|
||||
def calculate_checksum(self):
|
||||
sum_ = sum(int(x) * int(y) for x, y in enumerate(self.pzn, start=2))
|
||||
checksum = sum_ % 11
|
||||
if checksum == 10:
|
||||
raise BarcodeError("Checksum can not be 10 for PZN.")
|
||||
|
||||
return checksum
|
||||
|
||||
|
||||
class PZN8(PZN7):
|
||||
"""Will be fully added in v0.9."""
|
||||
|
||||
digits = 7
|
||||
|
||||
|
||||
class Code128(Barcode):
|
||||
"""Initializes a new Code128 instance. The checksum is added automatically
|
||||
when building the bars.
|
||||
|
||||
:parameters:
|
||||
code : String
|
||||
Code 128 string without checksum (added automatically).
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
"""
|
||||
|
||||
name = "Code 128"
|
||||
|
||||
def __init__(self, code, writer=None) -> None:
|
||||
self.code = code
|
||||
self.writer = writer or self.default_writer()
|
||||
self._charset = "B"
|
||||
self._buffer = ""
|
||||
check_code(self.code, self.name, code128.ALL)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.code
|
||||
|
||||
@property
|
||||
def encoded(self):
|
||||
return self._build()
|
||||
|
||||
def get_fullcode(self):
|
||||
return self.code
|
||||
|
||||
def _new_charset(self, which):
|
||||
if which == "A":
|
||||
code = self._convert("TO_A")
|
||||
elif which == "B":
|
||||
code = self._convert("TO_B")
|
||||
elif which == "C":
|
||||
code = self._convert("TO_C")
|
||||
self._charset = which
|
||||
return [code]
|
||||
|
||||
def _maybe_switch_charset(self, pos):
|
||||
char = self.code[pos]
|
||||
next_ = self.code[pos : pos + 10]
|
||||
|
||||
def look_next():
|
||||
digits = 0
|
||||
for c in next_:
|
||||
if c.isdigit():
|
||||
digits += 1
|
||||
else:
|
||||
break
|
||||
return digits > 3
|
||||
|
||||
codes = []
|
||||
if self._charset == "C" and not char.isdigit():
|
||||
if char in code128.B:
|
||||
codes = self._new_charset("B")
|
||||
elif char in code128.A:
|
||||
codes = self._new_charset("A")
|
||||
if len(self._buffer) == 1:
|
||||
codes.append(self._convert(self._buffer[0]))
|
||||
self._buffer = ""
|
||||
elif self._charset == "B":
|
||||
if look_next():
|
||||
codes = self._new_charset("C")
|
||||
elif char not in code128.B and char in code128.A:
|
||||
codes = self._new_charset("A")
|
||||
elif self._charset == "A":
|
||||
if look_next():
|
||||
codes = self._new_charset("C")
|
||||
elif char not in code128.A and char in code128.B:
|
||||
codes = self._new_charset("B")
|
||||
return codes
|
||||
|
||||
def _convert(self, char):
|
||||
if self._charset == "A":
|
||||
return code128.A[char]
|
||||
if self._charset == "B":
|
||||
return code128.B[char]
|
||||
if self._charset == "C":
|
||||
if char in code128.C:
|
||||
return code128.C[char]
|
||||
if char.isdigit():
|
||||
self._buffer += char
|
||||
if len(self._buffer) == 2:
|
||||
value = int(self._buffer)
|
||||
self._buffer = ""
|
||||
return value
|
||||
return None
|
||||
return None
|
||||
return None
|
||||
|
||||
def _try_to_optimize(self, encoded):
|
||||
if encoded[1] in code128.TO:
|
||||
encoded[:2] = [code128.TO[encoded[1]]]
|
||||
return encoded
|
||||
|
||||
def _calculate_checksum(self, encoded):
|
||||
cs = [encoded[0]]
|
||||
for i, code_num in enumerate(encoded[1:], start=1):
|
||||
cs.append(i * code_num)
|
||||
return sum(cs) % 103
|
||||
|
||||
def _build(self):
|
||||
encoded = [code128.START_CODES[self._charset]]
|
||||
for i, char in enumerate(self.code):
|
||||
encoded.extend(self._maybe_switch_charset(i))
|
||||
code_num = self._convert(char)
|
||||
if code_num is not None:
|
||||
encoded.append(code_num)
|
||||
# Finally look in the buffer
|
||||
if len(self._buffer) == 1:
|
||||
encoded.extend(self._new_charset("B"))
|
||||
encoded.append(self._convert(self._buffer[0]))
|
||||
self._buffer = ""
|
||||
return self._try_to_optimize(encoded)
|
||||
|
||||
def build(self):
|
||||
encoded = self._build()
|
||||
encoded.append(self._calculate_checksum(encoded))
|
||||
code = ""
|
||||
for code_num in encoded:
|
||||
code += code128.CODES[code_num]
|
||||
code += code128.STOP
|
||||
code += "11"
|
||||
return [code]
|
||||
|
||||
def render(self, writer_options=None, text=None):
|
||||
options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE}
|
||||
options.update(writer_options or {})
|
||||
return super().render(options, text)
|
||||
|
||||
|
||||
class Gs1_128(Code128): # noqa: N801
|
||||
"""
|
||||
following the norm, a gs1-128 barcode is a subset of code 128 barcode,
|
||||
it can be generated by prepending the code with the FNC1 character
|
||||
https://en.wikipedia.org/wiki/GS1-128
|
||||
https://www.gs1-128.info/
|
||||
"""
|
||||
|
||||
name = "GS1-128"
|
||||
|
||||
FNC1_CHAR = "\xf1"
|
||||
|
||||
def __init__(self, code, writer=None) -> None:
|
||||
code = self.FNC1_CHAR + code
|
||||
super().__init__(code, writer)
|
||||
|
||||
def get_fullcode(self):
|
||||
return super().get_fullcode()[1:]
|
||||
|
||||
|
||||
# For pre 0.8 compatibility
|
||||
PZN = PZN7
|
||||
234
venv/lib/python3.11/site-packages/barcode/ean.py
Normal file
234
venv/lib/python3.11/site-packages/barcode/ean.py
Normal file
@@ -0,0 +1,234 @@
|
||||
"""Module: barcode.ean
|
||||
|
||||
:Provided barcodes: EAN-14, EAN-13, EAN-8, JAN
|
||||
"""
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from functools import reduce
|
||||
|
||||
from barcode.base import Barcode
|
||||
from barcode.charsets import ean as _ean
|
||||
from barcode.errors import IllegalCharacterError
|
||||
from barcode.errors import NumberOfDigitsError
|
||||
from barcode.errors import WrongCountryCodeError
|
||||
|
||||
# EAN13 Specs (all sizes in mm)
|
||||
SIZES = {
|
||||
"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, no_checksum=False, guardbar=False) -> None:
|
||||
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 {} digits, not {}.".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 = "{}{}".format(
|
||||
ean, ean[self.digits] if len(ean) > self.digits else 0
|
||||
)
|
||||
else:
|
||||
self.ean = f"{ean}{self.calculate_checksum()}"
|
||||
|
||||
self.guardbar = guardbar
|
||||
if guardbar:
|
||||
self.EDGE = _ean.EDGE.replace("1", "G")
|
||||
self.MIDDLE = _ean.MIDDLE.replace("1", "G")
|
||||
else:
|
||||
self.EDGE = _ean.EDGE
|
||||
self.MIDDLE = _ean.MIDDLE
|
||||
self.writer = writer or self.default_writer()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.ean
|
||||
|
||||
def get_fullcode(self):
|
||||
if self.guardbar:
|
||||
return self.ean[0] + " " + self.ean[1:7] + " " + self.ean[7:] + " >"
|
||||
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 = self.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 += self.MIDDLE
|
||||
for number in self.ean[7:]:
|
||||
code += _ean.CODES["C"][int(number)]
|
||||
code += self.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("G", "|").replace("1", "|").replace("0", " ")
|
||||
return "\n".join(code)
|
||||
|
||||
def render(self, writer_options=None, text=None):
|
||||
options = {"module_width": SIZES["SC2"]}
|
||||
options.update(writer_options or {})
|
||||
return super().render(options, text)
|
||||
|
||||
|
||||
class EuropeanArticleNumber13WithGuard(EuropeanArticleNumber13):
|
||||
name = "EAN-13 with guards"
|
||||
|
||||
def __init__(self, ean, writer=None, no_checksum=False, guardbar=True) -> None:
|
||||
super().__init__(ean, writer, no_checksum, guardbar)
|
||||
|
||||
|
||||
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, *args, **kwargs) -> None:
|
||||
if int(jan[:3]) not in self.valid_country_codes:
|
||||
raise WrongCountryCodeError(
|
||||
"Country code isn't between 450-460 or 490-500."
|
||||
)
|
||||
super().__init__(jan, *args, **kwargs)
|
||||
|
||||
|
||||
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 build(self):
|
||||
"""Builds the barcode pattern from `self.ean`.
|
||||
|
||||
:returns: The pattern as string
|
||||
:rtype: String
|
||||
"""
|
||||
code = self.EDGE[:]
|
||||
for number in self.ean[:4]:
|
||||
code += _ean.CODES["A"][int(number)]
|
||||
code += self.MIDDLE
|
||||
for number in self.ean[4:]:
|
||||
code += _ean.CODES["C"][int(number)]
|
||||
code += self.EDGE
|
||||
return [code]
|
||||
|
||||
def get_fullcode(self):
|
||||
if self.guardbar:
|
||||
return "< " + self.ean[:4] + " " + self.ean[4:] + " >"
|
||||
return self.ean
|
||||
|
||||
|
||||
class EuropeanArticleNumber8WithGuard(EuropeanArticleNumber8):
|
||||
name = "EAN-8 with guards"
|
||||
|
||||
def __init__(self, ean, writer=None, no_checksum=False, guardbar=True) -> None:
|
||||
super().__init__(ean, writer, no_checksum, guardbar)
|
||||
|
||||
|
||||
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
|
||||
EAN13_GUARD = EuropeanArticleNumber13WithGuard
|
||||
EAN8 = EuropeanArticleNumber8
|
||||
EAN8_GUARD = EuropeanArticleNumber8WithGuard
|
||||
JAN = JapanArticleNumber
|
||||
28
venv/lib/python3.11/site-packages/barcode/errors.py
Normal file
28
venv/lib/python3.11/site-packages/barcode/errors.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""barcode.errors"""
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
|
||||
class BarcodeError(Exception):
|
||||
def __init__(self, msg) -> None:
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.msg
|
||||
|
||||
|
||||
class IllegalCharacterError(BarcodeError):
|
||||
"""Raised when a barcode-string contains illegal characters."""
|
||||
|
||||
|
||||
class BarcodeNotFoundError(BarcodeError):
|
||||
"""Raised when an unknown barcode is requested."""
|
||||
|
||||
|
||||
class NumberOfDigitsError(BarcodeError):
|
||||
"""Raised when the number of digits do not match."""
|
||||
|
||||
|
||||
class WrongCountryCodeError(BarcodeError):
|
||||
"""Raised when a JAN (Japan Article Number) don't starts with 450-459
|
||||
or 490-499.
|
||||
"""
|
||||
BIN
venv/lib/python3.11/site-packages/barcode/fonts/DejaVuSansMono.ttf
Executable file
BIN
venv/lib/python3.11/site-packages/barcode/fonts/DejaVuSansMono.ttf
Executable file
Binary file not shown.
129
venv/lib/python3.11/site-packages/barcode/isxn.py
Normal file
129
venv/lib/python3.11/site-packages/barcode/isxn.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Module: barcode.isxn
|
||||
|
||||
:Provided barcodes: ISBN-13, ISBN-10, ISSN
|
||||
|
||||
This module provides some special codes, which are no standalone barcodes.
|
||||
All codes where transformed to EAN-13 barcodes. In every case, the checksum
|
||||
is new calculated.
|
||||
|
||||
Example::
|
||||
|
||||
>>> from barcode import get_barcode
|
||||
>>> ISBN = get_barcode('isbn10')
|
||||
>>> isbn = ISBN('0132354187')
|
||||
>>> isbn
|
||||
'0132354187'
|
||||
>>> isbn.get_fullcode()
|
||||
'9780132354189'
|
||||
>>> # Test with wrong checksum
|
||||
>>> isbn = ISBN('0132354180')
|
||||
>>> isbn
|
||||
'0132354187'
|
||||
|
||||
"""
|
||||
from barcode.ean import EuropeanArticleNumber13
|
||||
from barcode.errors import BarcodeError
|
||||
from barcode.errors import WrongCountryCodeError
|
||||
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
|
||||
class InternationalStandardBookNumber13(EuropeanArticleNumber13):
|
||||
"""Initializes new ISBN-13 barcode.
|
||||
|
||||
:parameters:
|
||||
isbn : String
|
||||
The isbn number as string.
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
"""
|
||||
|
||||
name = "ISBN-13"
|
||||
|
||||
def __init__(self, isbn, writer=None) -> None:
|
||||
isbn = isbn.replace("-", "")
|
||||
self.isbn13 = isbn
|
||||
if isbn[:3] not in ("978", "979"):
|
||||
raise WrongCountryCodeError("ISBN must start with 978 or 979.")
|
||||
if isbn[:3] == "979" and isbn[3:4] not in ("1", "8"):
|
||||
raise BarcodeError("ISBN must start with 97910 or 97911.")
|
||||
super().__init__(isbn, writer)
|
||||
|
||||
|
||||
class InternationalStandardBookNumber10(InternationalStandardBookNumber13):
|
||||
"""Initializes new ISBN-10 barcode. This code is rendered as EAN-13 by
|
||||
prefixing it with 978.
|
||||
|
||||
:parameters:
|
||||
isbn : String
|
||||
The isbn number as string.
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
"""
|
||||
|
||||
name = "ISBN-10"
|
||||
|
||||
digits = 9
|
||||
|
||||
def __init__(self, isbn, writer=None) -> None:
|
||||
isbn = isbn.replace("-", "")
|
||||
isbn = isbn[: self.digits]
|
||||
super().__init__("978" + isbn, writer)
|
||||
self.isbn10 = isbn
|
||||
self.isbn10 = f"{isbn}{self._calculate_checksum()}"
|
||||
|
||||
def _calculate_checksum(self):
|
||||
tmp = sum(x * int(y) for x, y in enumerate(self.isbn10[:9], start=1)) % 11
|
||||
if tmp == 10:
|
||||
return "X"
|
||||
|
||||
return tmp
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.isbn10
|
||||
|
||||
|
||||
class InternationalStandardSerialNumber(EuropeanArticleNumber13):
|
||||
"""Initializes new ISSN barcode. This code is rendered as EAN-13
|
||||
by prefixing it with 977 and adding 00 between code and checksum.
|
||||
|
||||
:parameters:
|
||||
issn : String
|
||||
The issn number as string.
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
"""
|
||||
|
||||
name = "ISSN"
|
||||
|
||||
digits = 7
|
||||
|
||||
def __init__(self, issn, writer=None) -> None:
|
||||
issn = issn.replace("-", "")
|
||||
issn = issn[: self.digits]
|
||||
self.issn = issn
|
||||
self.issn = f"{issn}{self._calculate_checksum()}"
|
||||
super().__init__(self.make_ean(), writer)
|
||||
|
||||
def _calculate_checksum(self):
|
||||
tmp = (
|
||||
11
|
||||
- sum(x * int(y) for x, y in enumerate(reversed(self.issn[:7]), start=2))
|
||||
% 11
|
||||
)
|
||||
if tmp == 10:
|
||||
return "X"
|
||||
|
||||
return tmp
|
||||
|
||||
def make_ean(self):
|
||||
return f"977{self.issn[:7]}00{self._calculate_checksum()}"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.issn
|
||||
|
||||
|
||||
# Shortcuts
|
||||
ISBN13 = InternationalStandardBookNumber13
|
||||
ISBN10 = InternationalStandardBookNumber10
|
||||
ISSN = InternationalStandardSerialNumber
|
||||
76
venv/lib/python3.11/site-packages/barcode/itf.py
Normal file
76
venv/lib/python3.11/site-packages/barcode/itf.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""Module: barcode.itf
|
||||
|
||||
:Provided barcodes: Interleaved 2 of 5
|
||||
"""
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from barcode.base import Barcode
|
||||
from barcode.charsets import itf
|
||||
from barcode.errors import IllegalCharacterError
|
||||
|
||||
MIN_SIZE = 0.2
|
||||
MIN_QUIET_ZONE = 6.4
|
||||
|
||||
|
||||
class ITF(Barcode):
|
||||
"""Initializes a new ITF instance.
|
||||
|
||||
:parameters:
|
||||
code : String
|
||||
ITF (Interleaved 2 of 5) numeric string
|
||||
writer : barcode.writer Instance
|
||||
The writer to render the barcode (default: SVGWriter).
|
||||
narrow: Integer
|
||||
Width of the narrow elements (default: 2)
|
||||
wide: Integer
|
||||
Width of the wide elements (default: 5)
|
||||
wide/narrow must be in the range 2..3
|
||||
"""
|
||||
|
||||
name = "ITF"
|
||||
|
||||
def __init__(self, code, writer=None, narrow=2, wide=5) -> None:
|
||||
if not code.isdigit():
|
||||
raise IllegalCharacterError("ITF code can only contain numbers.")
|
||||
# Length must be even, prepend 0 if necessary
|
||||
if len(code) % 2 != 0:
|
||||
code = "0" + code
|
||||
self.code = code
|
||||
self.writer = writer or self.default_writer()
|
||||
self.narrow = narrow
|
||||
self.wide = wide
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.code
|
||||
|
||||
def get_fullcode(self):
|
||||
return self.code
|
||||
|
||||
def build(self):
|
||||
data = itf.START
|
||||
for i in range(0, len(self.code), 2):
|
||||
bars_digit = int(self.code[i])
|
||||
spaces_digit = int(self.code[i + 1])
|
||||
for j in range(5):
|
||||
data += itf.CODES[bars_digit][j].upper()
|
||||
data += itf.CODES[spaces_digit][j].lower()
|
||||
data += itf.STOP
|
||||
raw = ""
|
||||
for e in data:
|
||||
if e == "W":
|
||||
raw += "1" * self.wide
|
||||
if e == "w":
|
||||
raw += "0" * self.wide
|
||||
if e == "N":
|
||||
raw += "1" * self.narrow
|
||||
if e == "n":
|
||||
raw += "0" * self.narrow
|
||||
return [raw]
|
||||
|
||||
def render(self, writer_options, text=None):
|
||||
options = {
|
||||
"module_width": MIN_SIZE / self.narrow,
|
||||
"quiet_zone": MIN_QUIET_ZONE,
|
||||
}
|
||||
options.update(writer_options or {})
|
||||
return super().render(options, text)
|
||||
105
venv/lib/python3.11/site-packages/barcode/pybarcode.py
Normal file
105
venv/lib/python3.11/site-packages/barcode/pybarcode.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import barcode
|
||||
from barcode.version import version
|
||||
from barcode.writer import ImageWriter
|
||||
from barcode.writer import SVGWriter
|
||||
|
||||
IMG_FORMATS = ("BMP", "GIF", "JPEG", "MSP", "PCX", "PNG", "TIFF", "XBM")
|
||||
|
||||
|
||||
def list_types(args, parser=None):
|
||||
print("\npython-barcode available barcode formats:")
|
||||
print(", ".join(barcode.PROVIDED_BARCODES))
|
||||
print("\n")
|
||||
print("Available image formats")
|
||||
print("Standard: svg")
|
||||
if ImageWriter is not None:
|
||||
print("Pillow:", ", ".join(IMG_FORMATS))
|
||||
else:
|
||||
print("Pillow: disabled")
|
||||
print("\n")
|
||||
|
||||
|
||||
def create_barcode(args, parser):
|
||||
args.type = args.type.upper()
|
||||
if args.type != "SVG" and args.type not in IMG_FORMATS:
|
||||
parser.error(
|
||||
"Unknown type {type}. Try list action for available types.".format(
|
||||
type=args.type
|
||||
)
|
||||
)
|
||||
args.barcode = args.barcode.lower()
|
||||
if args.barcode not in barcode.PROVIDED_BARCODES:
|
||||
parser.error(
|
||||
"Unknown barcode {bc}. Try list action for available barcodes.".format(
|
||||
bc=args.barcode
|
||||
)
|
||||
)
|
||||
if args.type != "SVG":
|
||||
opts = {"format": args.type}
|
||||
writer = ImageWriter()
|
||||
else:
|
||||
opts = {"compress": args.compress}
|
||||
writer = SVGWriter()
|
||||
out = os.path.normpath(os.path.abspath(args.output))
|
||||
name = barcode.generate(args.barcode, args.code, writer, out, opts, args.text)
|
||||
print(f"New barcode saved as {name}.")
|
||||
|
||||
|
||||
def main():
|
||||
msg = []
|
||||
if ImageWriter is None:
|
||||
msg.append("Image output disabled (Pillow not found), --type option disabled.")
|
||||
else:
|
||||
msg.append(
|
||||
"Image output enabled, use --type option to give image "
|
||||
"format (png, jpeg, ...)."
|
||||
)
|
||||
parser = ArgumentParser(
|
||||
description="Create standard barcodes via cli.", epilog=" ".join(msg)
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--version", action="version", version="%(prog)s " + version
|
||||
)
|
||||
subparsers = parser.add_subparsers(title="Actions")
|
||||
create_parser = subparsers.add_parser(
|
||||
"create", help="Create a barcode with the given options."
|
||||
)
|
||||
create_parser.add_argument("code", help="Code to render as barcode.")
|
||||
create_parser.add_argument(
|
||||
"output", help="Filename for output without extension, e. g. mybarcode."
|
||||
)
|
||||
create_parser.add_argument(
|
||||
"-c",
|
||||
"--compress",
|
||||
action="store_true",
|
||||
help="Compress output, only recognized if type is svg.",
|
||||
)
|
||||
create_parser.add_argument(
|
||||
"-b", "--barcode", help="Barcode to use [default: %(default)s]."
|
||||
)
|
||||
create_parser.add_argument("--text", help="Text to show under the barcode.")
|
||||
if ImageWriter is not None:
|
||||
create_parser.add_argument(
|
||||
"-t", "--type", help="Type of output [default: %(default)s]."
|
||||
)
|
||||
list_parser = subparsers.add_parser(
|
||||
"list", help="List available image and code types."
|
||||
)
|
||||
list_parser.set_defaults(func=list_types)
|
||||
create_parser.set_defaults(
|
||||
type="svg", compress=False, func=create_barcode, barcode="code39", text=None
|
||||
)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
func = args.func
|
||||
except AttributeError:
|
||||
parser.error("You need to tell me what to do.")
|
||||
else:
|
||||
func(args, parser)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
115
venv/lib/python3.11/site-packages/barcode/upc.py
Normal file
115
venv/lib/python3.11/site-packages/barcode/upc.py
Normal file
@@ -0,0 +1,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
|
||||
4
venv/lib/python3.11/site-packages/barcode/version.py
Normal file
4
venv/lib/python3.11/site-packages/barcode/version.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# file generated by setuptools_scm
|
||||
# don't change, don't track in version control
|
||||
__version__ = version = '0.15.1'
|
||||
__version_tuple__ = version_tuple = (0, 15, 1)
|
||||
464
venv/lib/python3.11/site-packages/barcode/writer.py
Normal file
464
venv/lib/python3.11/site-packages/barcode/writer.py
Normal file
@@ -0,0 +1,464 @@
|
||||
import gzip
|
||||
import os
|
||||
import xml.dom
|
||||
from typing import BinaryIO
|
||||
|
||||
from barcode.version import version
|
||||
|
||||
try:
|
||||
import Image
|
||||
import ImageDraw
|
||||
import ImageFont
|
||||
except ImportError:
|
||||
try:
|
||||
from PIL import Image # lint:ok
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageFont
|
||||
except ImportError:
|
||||
import logging
|
||||
|
||||
log = logging.getLogger("pyBarcode")
|
||||
log.info("Pillow not found. Image output disabled")
|
||||
Image = ImageDraw = ImageFont = None # lint:ok
|
||||
|
||||
|
||||
def mm2px(mm, dpi=300):
|
||||
return (mm * dpi) / 25.4
|
||||
|
||||
|
||||
def pt2mm(pt):
|
||||
return pt * 0.352777778
|
||||
|
||||
|
||||
def _set_attributes(element, **attributes):
|
||||
for key, value in attributes.items():
|
||||
element.setAttribute(key, value)
|
||||
|
||||
|
||||
def create_svg_object(with_doctype=False):
|
||||
imp = xml.dom.getDOMImplementation()
|
||||
doctype = imp.createDocumentType(
|
||||
"svg",
|
||||
"-//W3C//DTD SVG 1.1//EN",
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd",
|
||||
)
|
||||
document = imp.createDocument(None, "svg", doctype if with_doctype else None)
|
||||
_set_attributes(
|
||||
document.documentElement, version="1.1", xmlns="http://www.w3.org/2000/svg"
|
||||
)
|
||||
return document
|
||||
|
||||
|
||||
SIZE = "{0:.3f}mm"
|
||||
COMMENT = f"Autogenerated with python-barcode {version}"
|
||||
PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class BaseWriter:
|
||||
"""Baseclass for all writers.
|
||||
|
||||
Initializes the basic writer options. Childclasses can add more
|
||||
attributes and can set them directly or using
|
||||
`self.set_options(option=value)`.
|
||||
|
||||
:parameters:
|
||||
initialize : Function
|
||||
Callback for initializing the inheriting writer.
|
||||
Is called: `callback_initialize(raw_code)`
|
||||
paint_module : Function
|
||||
Callback for painting one barcode module.
|
||||
Is called: `callback_paint_module(xpos, ypos, width, color)`
|
||||
paint_text : Function
|
||||
Callback for painting the text under the barcode.
|
||||
Is called: `callback_paint_text(xpos, ypos)` using `self.text`
|
||||
as text.
|
||||
finish : Function
|
||||
Callback for doing something with the completely rendered
|
||||
output.
|
||||
Is called: `return callback_finish()` and must return the
|
||||
rendered output.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
initialize=None,
|
||||
paint_module=None,
|
||||
paint_text=None,
|
||||
finish=None,
|
||||
) -> None:
|
||||
self._callbacks = {
|
||||
"initialize": initialize,
|
||||
"paint_module": paint_module,
|
||||
"paint_text": paint_text,
|
||||
"finish": finish,
|
||||
}
|
||||
self.module_width = 10
|
||||
self.module_height = 10
|
||||
self.font_path = os.path.join(PATH, "fonts", "DejaVuSansMono.ttf")
|
||||
self.font_size = 10
|
||||
self.quiet_zone = 6.5
|
||||
self.background = "white"
|
||||
self.foreground = "black"
|
||||
self.text = ""
|
||||
self.human = "" # human readable text
|
||||
self.text_distance = 5
|
||||
self.text_line_distance = 1
|
||||
self.center_text = True
|
||||
self.guard_height_factor = 1.1
|
||||
self.margin_top = 1
|
||||
self.margin_bottom = 1
|
||||
|
||||
def calculate_size(self, modules_per_line, number_of_lines):
|
||||
"""Calculates the size of the barcode in pixel.
|
||||
|
||||
:parameters:
|
||||
modules_per_line : Integer
|
||||
Number of modules in one line.
|
||||
number_of_lines : Integer
|
||||
Number of lines of the barcode.
|
||||
|
||||
:returns: Width and height of the barcode in pixel.
|
||||
:rtype: Tuple
|
||||
"""
|
||||
width = 2 * self.quiet_zone + modules_per_line * self.module_width
|
||||
height = (
|
||||
self.margin_bottom + self.margin_top + self.module_height * number_of_lines
|
||||
)
|
||||
number_of_text_lines = len(self.text.splitlines())
|
||||
if self.font_size and self.text:
|
||||
height += (
|
||||
pt2mm(self.font_size) / 2 * number_of_text_lines + self.text_distance
|
||||
)
|
||||
height += self.text_line_distance * (number_of_text_lines - 1)
|
||||
return width, height
|
||||
|
||||
def save(self, filename, output):
|
||||
"""Saves the rendered output to `filename`.
|
||||
|
||||
:parameters:
|
||||
filename : String
|
||||
Filename without extension.
|
||||
output : String
|
||||
The rendered output.
|
||||
|
||||
:returns: The full filename with extension.
|
||||
:rtype: String
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def register_callback(self, action, callback):
|
||||
"""Register one of the three callbacks if not given at instance
|
||||
creation.
|
||||
|
||||
:parameters:
|
||||
action : String
|
||||
One of 'initialize', 'paint_module', 'paint_text', 'finish'.
|
||||
callback : Function
|
||||
The callback function for the given action.
|
||||
"""
|
||||
self._callbacks[action] = callback
|
||||
|
||||
def set_options(self, options):
|
||||
"""Sets the given options as instance attributes (only
|
||||
if they are known).
|
||||
|
||||
:parameters:
|
||||
options : Dict
|
||||
All known instance attributes and more if the childclass
|
||||
has defined them before this call.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
for key, val in options.items():
|
||||
key = key.lstrip("_")
|
||||
if hasattr(self, key):
|
||||
setattr(self, key, val)
|
||||
|
||||
def packed(self, line):
|
||||
"""
|
||||
Pack line to list give better gfx result, otherwise in can
|
||||
result in aliasing gaps
|
||||
'11010111' -> [2, -1, 1, -1, 3]
|
||||
|
||||
This method will yield a sequence of pairs (width, height_factor).
|
||||
|
||||
:parameters:
|
||||
line: String
|
||||
A string matching the writer spec
|
||||
(only contain 0 or 1 or G).
|
||||
"""
|
||||
line += " "
|
||||
c = 1
|
||||
for i in range(0, len(line) - 1):
|
||||
if line[i] == line[i + 1]:
|
||||
c += 1
|
||||
else:
|
||||
if line[i] == "1":
|
||||
yield (c, 1)
|
||||
elif line[i] == "G":
|
||||
yield (c, self.guard_height_factor)
|
||||
else:
|
||||
yield (-c, self.guard_height_factor)
|
||||
c = 1
|
||||
|
||||
def render(self, code):
|
||||
"""Renders the barcode to whatever the inheriting writer provides,
|
||||
using the registered callbacks.
|
||||
|
||||
:parameters:
|
||||
code : List
|
||||
List of strings matching the writer spec
|
||||
(only contain 0 or 1 or G).
|
||||
"""
|
||||
if self._callbacks["initialize"] is not None:
|
||||
self._callbacks["initialize"](code)
|
||||
ypos = self.margin_top
|
||||
base_height = self.module_height
|
||||
for cc, line in enumerate(code):
|
||||
# Left quiet zone is x startposition
|
||||
xpos = self.quiet_zone
|
||||
bxs = xpos # x start of barcode
|
||||
text = {
|
||||
"start": [], # The x start of a guard
|
||||
"end": [], # The x end of a guard
|
||||
"xpos": [], # The x position where to write a text block
|
||||
# Flag that indicates if the previous mod was part of an guard block:
|
||||
"was_guard": False,
|
||||
}
|
||||
for mod, height_factor in self.packed(line):
|
||||
if mod < 1:
|
||||
color = self.background
|
||||
else:
|
||||
color = self.foreground
|
||||
|
||||
if text["was_guard"] and height_factor == 1:
|
||||
# The current guard ended, store its x position
|
||||
text["end"].append(xpos)
|
||||
text["was_guard"] = False
|
||||
elif not text["was_guard"] and height_factor != 1:
|
||||
# A guard started, store its x position
|
||||
text["start"].append(xpos)
|
||||
text["was_guard"] = True
|
||||
|
||||
self.module_height = base_height * height_factor
|
||||
# remove painting for background colored tiles?
|
||||
self._callbacks["paint_module"](
|
||||
xpos, ypos, self.module_width * abs(mod), color
|
||||
)
|
||||
xpos += self.module_width * abs(mod)
|
||||
else:
|
||||
if height_factor != 1:
|
||||
text["end"].append(xpos)
|
||||
self.module_height = base_height
|
||||
|
||||
bxe = xpos
|
||||
# Add right quiet zone to every line, except last line,
|
||||
# quiet zone already provided with background,
|
||||
# should it be removed completely?
|
||||
if (cc + 1) != len(code):
|
||||
self._callbacks["paint_module"](
|
||||
xpos, ypos, self.quiet_zone, self.background
|
||||
)
|
||||
ypos += self.module_height
|
||||
|
||||
if self.text and self._callbacks["paint_text"] is not None:
|
||||
if not text["start"]:
|
||||
# If we don't have any start value, print the entire ean
|
||||
ypos += self.text_distance
|
||||
xpos = bxs + (bxe - bxs) / 2.0 if self.center_text else bxs
|
||||
self._callbacks["paint_text"](xpos, ypos)
|
||||
else:
|
||||
# Else, divide the ean into blocks and print each block
|
||||
# in the expected position.
|
||||
text["xpos"] = [bxs - 4 * self.module_width]
|
||||
|
||||
# Calculates the position of the text by getting the difference
|
||||
# between a guard end and the next start
|
||||
text["start"].pop(0)
|
||||
for s, e in zip(text["start"], text["end"]):
|
||||
text["xpos"].append(e + (s - e) / 2)
|
||||
|
||||
# The last text block is always put after the last guard end
|
||||
text["xpos"].append(text["end"][-1] + 4 * self.module_width)
|
||||
|
||||
# Split the ean into its blocks
|
||||
self.text = self.text.split(" ")
|
||||
|
||||
ypos += pt2mm(self.font_size)
|
||||
|
||||
blocks = self.text
|
||||
for text_, xpos in zip(blocks, text["xpos"]):
|
||||
self.text = text_
|
||||
self._callbacks["paint_text"](xpos, ypos)
|
||||
|
||||
return self._callbacks["finish"]()
|
||||
|
||||
|
||||
class SVGWriter(BaseWriter):
|
||||
def __init__(self) -> None:
|
||||
BaseWriter.__init__(
|
||||
self, self._init, self._create_module, self._create_text, self._finish
|
||||
)
|
||||
self.compress = False
|
||||
self.with_doctype = True
|
||||
self._document = None
|
||||
self._root = None
|
||||
self._group = None
|
||||
|
||||
def _init(self, code):
|
||||
width, height = self.calculate_size(len(code[0]), len(code))
|
||||
self._document = create_svg_object(self.with_doctype)
|
||||
self._root = self._document.documentElement
|
||||
attributes = {
|
||||
"width": SIZE.format(width),
|
||||
"height": SIZE.format(height),
|
||||
}
|
||||
_set_attributes(self._root, **attributes)
|
||||
if COMMENT:
|
||||
self._root.appendChild(self._document.createComment(COMMENT))
|
||||
# create group for easier handling in 3rd party software
|
||||
# like corel draw, inkscape, ...
|
||||
group = self._document.createElement("g")
|
||||
attributes = {"id": "barcode_group"}
|
||||
_set_attributes(group, **attributes)
|
||||
self._group = self._root.appendChild(group)
|
||||
background = self._document.createElement("rect")
|
||||
attributes = {
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
"style": f"fill:{self.background}",
|
||||
}
|
||||
_set_attributes(background, **attributes)
|
||||
self._group.appendChild(background)
|
||||
|
||||
def _create_module(self, xpos, ypos, width, color):
|
||||
# Background rect has been provided already, so skipping "spaces"
|
||||
if color != self.background:
|
||||
element = self._document.createElement("rect")
|
||||
attributes = {
|
||||
"x": SIZE.format(xpos),
|
||||
"y": SIZE.format(ypos),
|
||||
"width": SIZE.format(width),
|
||||
"height": SIZE.format(self.module_height),
|
||||
"style": f"fill:{color};",
|
||||
}
|
||||
_set_attributes(element, **attributes)
|
||||
self._group.appendChild(element)
|
||||
|
||||
def _create_text(self, xpos, ypos):
|
||||
# check option to override self.text with self.human (barcode as
|
||||
# human readable data, can be used to print own formats)
|
||||
barcodetext = self.human if self.human != "" else self.text
|
||||
for subtext in barcodetext.split("\n"):
|
||||
element = self._document.createElement("text")
|
||||
attributes = {
|
||||
"x": SIZE.format(xpos),
|
||||
"y": SIZE.format(ypos),
|
||||
"style": "fill:{};font-size:{}pt;text-anchor:middle;".format(
|
||||
self.foreground,
|
||||
self.font_size,
|
||||
),
|
||||
}
|
||||
_set_attributes(element, **attributes)
|
||||
text_element = self._document.createTextNode(subtext)
|
||||
element.appendChild(text_element)
|
||||
self._group.appendChild(element)
|
||||
ypos += pt2mm(self.font_size) + self.text_line_distance
|
||||
|
||||
def _finish(self):
|
||||
if self.compress:
|
||||
return self._document.toxml(encoding="UTF-8")
|
||||
|
||||
return self._document.toprettyxml(
|
||||
indent=4 * " ", newl=os.linesep, encoding="UTF-8"
|
||||
)
|
||||
|
||||
def save(self, filename, output):
|
||||
if self.compress:
|
||||
_filename = f"{filename}.svgz"
|
||||
f = gzip.open(_filename, "wb")
|
||||
f.write(output)
|
||||
f.close()
|
||||
else:
|
||||
_filename = f"{filename}.svg"
|
||||
with open(_filename, "wb") as f:
|
||||
f.write(output)
|
||||
return _filename
|
||||
|
||||
def write(self, content, fp: BinaryIO):
|
||||
"""Write `content` into a file-like object.
|
||||
|
||||
Content should be a barcode rendered by this writer.
|
||||
"""
|
||||
fp.write(content)
|
||||
|
||||
|
||||
if Image is None:
|
||||
ImageWriter = None
|
||||
else:
|
||||
|
||||
class ImageWriter(BaseWriter): # type: ignore[no-redef]
|
||||
format: str
|
||||
mode: str
|
||||
dpi: int
|
||||
|
||||
def __init__(self, format="PNG", mode="RGB") -> None:
|
||||
"""Initialise a new write instance.
|
||||
|
||||
:params format: The file format for the generated image. This parameter can
|
||||
take any value that Pillow accepts.
|
||||
:params mode: The colour-mode for the generated image. Set this to RGBA if
|
||||
you wish to use colours with transparency.
|
||||
"""
|
||||
BaseWriter.__init__(
|
||||
self, self._init, self._paint_module, self._paint_text, self._finish
|
||||
)
|
||||
self.format = format
|
||||
self.mode = mode
|
||||
self.dpi = 300
|
||||
self._image = None
|
||||
self._draw = None
|
||||
|
||||
def _init(self, code):
|
||||
width, height = self.calculate_size(len(code[0]), len(code))
|
||||
size = (int(mm2px(width, self.dpi)), int(mm2px(height, self.dpi)))
|
||||
self._image = Image.new(self.mode, size, self.background)
|
||||
self._draw = ImageDraw.Draw(self._image)
|
||||
|
||||
def _paint_module(self, xpos, ypos, width, color):
|
||||
size = [
|
||||
(mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)),
|
||||
(
|
||||
mm2px(xpos + width, self.dpi) - 1,
|
||||
mm2px(ypos + self.module_height, self.dpi),
|
||||
),
|
||||
]
|
||||
self._draw.rectangle(size, outline=color, fill=color)
|
||||
|
||||
def _paint_text(self, xpos, ypos):
|
||||
font_size = int(mm2px(pt2mm(self.font_size), self.dpi))
|
||||
font = ImageFont.truetype(self.font_path, font_size)
|
||||
for subtext in self.text.split("\n"):
|
||||
pos = (
|
||||
mm2px(xpos, self.dpi),
|
||||
mm2px(ypos, self.dpi),
|
||||
)
|
||||
self._draw.text(
|
||||
pos, subtext, font=font, fill=self.foreground, anchor="md"
|
||||
)
|
||||
ypos += pt2mm(self.font_size) / 2 + self.text_line_distance
|
||||
|
||||
def _finish(self):
|
||||
return self._image
|
||||
|
||||
def save(self, filename, output):
|
||||
filename = f"{filename}.{self.format.lower()}"
|
||||
output.save(filename, self.format.upper())
|
||||
return filename
|
||||
|
||||
def write(self, content, fp: BinaryIO):
|
||||
"""Write `content` into a file-like object.
|
||||
|
||||
Content should be a barcode rendered by this writer.
|
||||
"""
|
||||
content.save(fp, format=self.format)
|
||||
Reference in New Issue
Block a user