diff options
Diffstat (limited to 'lib/pubcode/code128.py')
-rw-r--r-- | lib/pubcode/code128.py | 283 |
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 |