summaryrefslogtreecommitdiff
path: root/lib/pubcode/code128.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pubcode/code128.py')
-rw-r--r--lib/pubcode/code128.py283
1 files changed, 202 insertions, 81 deletions
diff --git a/lib/pubcode/code128.py b/lib/pubcode/code128.py
index 1c37f37..4fd7aed 100644
--- a/lib/pubcode/code128.py
+++ b/lib/pubcode/code128.py
@@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
from builtins import * # Use Python3-like builtins for Python2.
import base64
import io
+
try:
from PIL import Image
except ImportError:
@@ -34,74 +35,189 @@ class Code128(object):
# List of bar and space weights, indexed by symbol character values (0-105), and the STOP character (106).
# The first weights is a bar and then it alternates.
_val2bars = [
- '212222', '222122', '222221', '121223', '121322', '131222', '122213', '122312', '132212', '221213',
- '221312', '231212', '112232', '122132', '122231', '113222', '123122', '123221', '223211', '221132',
- '221231', '213212', '223112', '312131', '311222', '321122', '321221', '312212', '322112', '322211',
- '212123', '212321', '232121', '111323', '131123', '131321', '112313', '132113', '132311', '211313',
- '231113', '231311', '112133', '112331', '132131', '113123', '113321', '133121', '313121', '211331',
- '231131', '213113', '213311', '213131', '311123', '311321', '331121', '312113', '312311', '332111',
- '314111', '221411', '431111', '111224', '111422', '121124', '121421', '141122', '141221', '112214',
- '112412', '122114', '122411', '142112', '142211', '241211', '221114', '413111', '241112', '134111',
- '111242', '121142', '121241', '114212', '124112', '124211', '411212', '421112', '421211', '212141',
- '214121', '412121', '111143', '111341', '131141', '114113', '114311', '411113', '411311', '113141',
- '114131', '311141', '411131', '211412', '211214', '211232', '2331112'
+ "212222",
+ "222122",
+ "222221",
+ "121223",
+ "121322",
+ "131222",
+ "122213",
+ "122312",
+ "132212",
+ "221213",
+ "221312",
+ "231212",
+ "112232",
+ "122132",
+ "122231",
+ "113222",
+ "123122",
+ "123221",
+ "223211",
+ "221132",
+ "221231",
+ "213212",
+ "223112",
+ "312131",
+ "311222",
+ "321122",
+ "321221",
+ "312212",
+ "322112",
+ "322211",
+ "212123",
+ "212321",
+ "232121",
+ "111323",
+ "131123",
+ "131321",
+ "112313",
+ "132113",
+ "132311",
+ "211313",
+ "231113",
+ "231311",
+ "112133",
+ "112331",
+ "132131",
+ "113123",
+ "113321",
+ "133121",
+ "313121",
+ "211331",
+ "231131",
+ "213113",
+ "213311",
+ "213131",
+ "311123",
+ "311321",
+ "331121",
+ "312113",
+ "312311",
+ "332111",
+ "314111",
+ "221411",
+ "431111",
+ "111224",
+ "111422",
+ "121124",
+ "121421",
+ "141122",
+ "141221",
+ "112214",
+ "112412",
+ "122114",
+ "122411",
+ "142112",
+ "142211",
+ "241211",
+ "221114",
+ "413111",
+ "241112",
+ "134111",
+ "111242",
+ "121142",
+ "121241",
+ "114212",
+ "124112",
+ "124211",
+ "411212",
+ "421112",
+ "421211",
+ "212141",
+ "214121",
+ "412121",
+ "111143",
+ "111341",
+ "131141",
+ "114113",
+ "114311",
+ "411113",
+ "411311",
+ "113141",
+ "114131",
+ "311141",
+ "411131",
+ "211412",
+ "211214",
+ "211232",
+ "2331112",
]
class Special(object):
"""These are special characters used by the Code128 encoding."""
- START_A = '[Start Code A]'
- START_B = '[Start Code B]'
- START_C = '[Start Code C]'
- CODE_A = '[Code A]'
- CODE_B = '[Code B]'
- CODE_C = '[Code C]'
- SHIFT_A = '[Shift A]'
- SHIFT_B = '[Shift B]'
- FNC_1 = '[FNC 1]'
- FNC_2 = '[FNC 2]'
- FNC_3 = '[FNC 3]'
- FNC_4 = '[FNC 4]'
- STOP = '[Stop]'
-
- _start_codes = {'A': Special.START_A, 'B': Special.START_B, 'C': Special.START_C}
- _char_codes = {'A': Special.CODE_A, 'B': Special.CODE_B, 'C': Special.CODE_C}
+
+ START_A = "[Start Code A]"
+ START_B = "[Start Code B]"
+ START_C = "[Start Code C]"
+ CODE_A = "[Code A]"
+ CODE_B = "[Code B]"
+ CODE_C = "[Code C]"
+ SHIFT_A = "[Shift A]"
+ SHIFT_B = "[Shift B]"
+ FNC_1 = "[FNC 1]"
+ FNC_2 = "[FNC 2]"
+ FNC_3 = "[FNC 3]"
+ FNC_4 = "[FNC 4]"
+ STOP = "[Stop]"
+
+ _start_codes = {"A": Special.START_A, "B": Special.START_B, "C": Special.START_C}
+ _char_codes = {"A": Special.CODE_A, "B": Special.CODE_B, "C": Special.CODE_C}
# Lists mapping symbol values to characters in each character set. This defines the alphabet and Code128._sym2val
# is derived from this structure.
_val2sym = {
# Code Set A includes ordinals 0 through 95 and 7 special characters. The ordinals include digits,
# upper case characters, punctuation and control characters.
- 'A':
- [chr(x) for x in range(32, 95 + 1)] +
- [chr(x) for x in range(0, 31 + 1)] +
- [
- Special.FNC_3, Special.FNC_2, Special.SHIFT_B, Special.CODE_C,
- Special.CODE_B, Special.FNC_4, Special.FNC_1,
- Special.START_A, Special.START_B, Special.START_C, Special.STOP
- ],
+ "A": [chr(x) for x in range(32, 95 + 1)]
+ + [chr(x) for x in range(0, 31 + 1)]
+ + [
+ Special.FNC_3,
+ Special.FNC_2,
+ Special.SHIFT_B,
+ Special.CODE_C,
+ Special.CODE_B,
+ Special.FNC_4,
+ Special.FNC_1,
+ Special.START_A,
+ Special.START_B,
+ Special.START_C,
+ Special.STOP,
+ ],
# Code Set B includes ordinals 32 through 127 and 7 special characters. The ordinals include digits,
# upper and lover case characters and punctuation.
- 'B':
- [chr(x) for x in range(32, 127 + 1)] +
- [
- Special.FNC_3, Special.FNC_2, Special.SHIFT_A, Special.CODE_C,
- Special.FNC_4, Special.CODE_A, Special.FNC_1,
- Special.START_A, Special.START_B, Special.START_C, Special.STOP
- ],
+ "B": [chr(x) for x in range(32, 127 + 1)]
+ + [
+ Special.FNC_3,
+ Special.FNC_2,
+ Special.SHIFT_A,
+ Special.CODE_C,
+ Special.FNC_4,
+ Special.CODE_A,
+ Special.FNC_1,
+ Special.START_A,
+ Special.START_B,
+ Special.START_C,
+ Special.STOP,
+ ],
# Code Set C includes all pairs of 2 digits and 3 special characters.
- 'C':
- ['%02d' % (x,) for x in range(0, 99 + 1)] +
- [
- Special.CODE_B, Special.CODE_A, Special.FNC_1,
- Special.START_A, Special.START_B, Special.START_C, Special.STOP
- ],
+ "C": ["%02d" % (x,) for x in range(0, 99 + 1)]
+ + [
+ Special.CODE_B,
+ Special.CODE_A,
+ Special.FNC_1,
+ Special.START_A,
+ Special.START_B,
+ Special.START_C,
+ Special.STOP,
+ ],
}
# Dicts mapping characters to symbol values in each character set.
_sym2val = {
- 'A': {char: val for val, char in enumerate(_val2sym['A'])},
- 'B': {char: val for val, char in enumerate(_val2sym['B'])},
- 'C': {char: val for val, char in enumerate(_val2sym['C'])},
+ "A": {char: val for val, char in enumerate(_val2sym["A"])},
+ "B": {char: val for val, char in enumerate(_val2sym["B"])},
+ "C": {char: val for val, char in enumerate(_val2sym["C"])},
}
# How large the quiet zone is on either side of the barcode, when quiet zone is used.
@@ -121,13 +237,13 @@ class Code128(object):
"""
self._validate_charset(data, charset)
- if charset in ('A', 'B'):
+ if charset in ("A", "B"):
charset *= len(data)
- elif charset in ('C',):
- charset *= (len(data) // 2)
+ elif charset in ("C",):
+ charset *= len(data) // 2
if len(data) % 2 == 1:
# If there are an odd number of characters for charset C, encode the last character with charset B.
- charset += 'B'
+ charset += "B"
self.data = data
self.symbol_values = self._encode(data, charset)
@@ -148,13 +264,13 @@ class Code128(object):
if len(charset) > 1:
charset_data_length = 0
for symbol_charset in charset:
- if symbol_charset not in ('A', 'B', 'C'):
+ if symbol_charset not in ("A", "B", "C"):
raise Code128.CharsetError
- charset_data_length += 2 if symbol_charset is 'C' else 1
+ charset_data_length += 2 if symbol_charset is "C" else 1
if charset_data_length != len(data):
raise Code128.CharsetLengthError
elif len(charset) == 1:
- if charset not in ('A', 'B', 'C'):
+ if charset not in ("A", "B", "C"):
raise Code128.CharsetError
elif charset is not None:
raise Code128.CharsetError
@@ -182,10 +298,12 @@ class Code128(object):
if charset is not prev_charset:
# Handle a special case of there being a single A in middle of two B's or the other way around, where
# using a single shift character is more efficient than using two character set switches.
- next_charset = charsets[symbol_num + 1] if symbol_num + 1 < len(charsets) else None
- if charset == 'A' and prev_charset == next_charset == 'B':
+ next_charset = (
+ charsets[symbol_num + 1] if symbol_num + 1 < len(charsets) else None
+ )
+ if charset == "A" and prev_charset == next_charset == "B":
result.append(cls._sym2val[prev_charset][cls.Special.SHIFT_A])
- elif charset == 'B' and prev_charset == next_charset == 'A':
+ elif charset == "B" and prev_charset == next_charset == "A":
result.append(cls._sym2val[prev_charset][cls.Special.SHIFT_B])
else:
# This is the normal case.
@@ -193,7 +311,7 @@ class Code128(object):
result.append(cls._sym2val[prev_charset][charset_symbol])
prev_charset = charset
- nxt = cur + (2 if charset == 'C' else 1)
+ nxt = cur + (2 if charset == "C" else 1)
symbol = data[cur:nxt]
cur = nxt
result.append(cls._sym2val[charset][symbol])
@@ -206,9 +324,10 @@ class Code128(object):
@property
def symbols(self):
"""List of the coded symbols as strings, with special characters included."""
+
def _iter_symbols(symbol_values):
# The initial charset doesn't matter, as the start codes have the same symbol values in all charsets.
- charset = 'A'
+ charset = "A"
shift_charset = None
for symbol_value in symbol_values:
@@ -219,15 +338,15 @@ class Code128(object):
symbol = self._val2sym[charset][symbol_value]
if symbol in (self.Special.START_A, self.Special.CODE_A):
- charset = 'A'
+ charset = "A"
elif symbol in (self.Special.START_B, self.Special.CODE_B):
- charset = 'B'
+ charset = "B"
elif symbol in (self.Special.START_C, self.Special.CODE_C):
- charset = 'C'
+ charset = "C"
elif symbol in (self.Special.SHIFT_A,):
- shift_charset = 'A'
+ shift_charset = "A"
elif symbol in (self.Special.SHIFT_B,):
- shift_charset = 'B'
+ shift_charset = "B"
yield symbol
@@ -243,7 +362,7 @@ class Code128(object):
:rtype: string
"""
- return ''.join(map((lambda val: self._val2bars[val]), self.symbol_values))
+ return "".join(map((lambda val: self._val2bars[val]), self.symbol_values))
@property
def modules(self):
@@ -255,6 +374,7 @@ class Code128(object):
:rtype: list[int]
"""
+
def _iterate_modules(bars):
is_bar = True
for char in map(int, bars):
@@ -288,7 +408,9 @@ class Code128(object):
:return: A monochromatic image containing the barcode as black bars on white background.
"""
if Image is None:
- raise Code128.MissingDependencyError("PIL module is required to use image method.")
+ raise Code128.MissingDependencyError(
+ "PIL module is required to use image method."
+ )
modules = list(self.modules)
if add_quiet_zone:
@@ -296,7 +418,7 @@ class Code128(object):
modules = [1] * self.quiet_zone + modules + [1] * self.quiet_zone
width = len(modules)
- img = Image.new(mode='1', size=(width, 1))
+ img = Image.new(mode="1", size=(width, 1))
img.putdata(modules)
if height == 1 and module_width == 1:
@@ -305,7 +427,7 @@ class Code128(object):
new_size = (width * module_width, height)
return img.resize(new_size, resample=Image.NEAREST)
- def data_url(self, image_format='png', add_quiet_zone=True):
+ def data_url(self, image_format="png", add_quiet_zone=True):
"""Get a data URL representing the barcode.
>>> barcode = Code128('Hello!', charset='B')
@@ -327,22 +449,21 @@ class Code128(object):
# Using BMP can often result in smaller data URLs than PNG, but it isn't as widely supported by browsers as PNG.
# GIFs result in data URLs 10 times bigger than PNG or BMP, possibly due to lack of support for monochrome GIFs
# in Pillow, so they shouldn't be used.
- if image_format == 'png':
+ if image_format == "png":
# Unfortunately there is no way to avoid adding the zlib headers.
# Using compress_level=0 sometimes results in a slightly bigger data size (by a few bytes), but there
# doesn't appear to be a difference between levels 9 and 1, so let's just use 1.
- pil_image.save(memory_file, format='png', compress_level=1)
- elif image_format == 'bmp':
- pil_image.save(memory_file, format='bmp')
+ pil_image.save(memory_file, format="png", compress_level=1)
+ elif image_format == "bmp":
+ pil_image.save(memory_file, format="bmp")
else:
- raise Code128.UnknownFormatError('Only png and bmp are supported.')
+ raise Code128.UnknownFormatError("Only png and bmp are supported.")
# Encode the data in the BytesIO object and convert the result into unicode.
- base64_image = base64.b64encode(memory_file.getvalue()).decode('ascii')
+ base64_image = base64.b64encode(memory_file.getvalue()).decode("ascii")
- data_url = 'data:image/{format};base64,{base64_data}'.format(
- format=image_format,
- base64_data=base64_image
+ data_url = "data:image/{format};base64,{base64_data}".format(
+ format=image_format, base64_data=base64_image
)
return data_url