В первой части я попытался рассказать про библиотеку BWIPP, используемую для генерации штрих-кодов на PostScript. Вторая часть будет посвящена адаптации BWIPP под командную строку, дабы обеспечить более понятный и удобный доступ к библиотеке. Для этого напишем небольшой скрипт на Python 3.
Если вы читали первую часть темы, то в курсе, что для генерации баркода нам потребуются основные параметры, которые различаются от типа баркода. Чтобы не возиться лишний раз с комментариями к BWIPP в поиске этих параметров, я написал небольшой парсер, который соберет всю информацию по каждому штрих-коду.
bwipp_encoders.py:
import os import pickle encoder_begin = '% --BEGIN ENCODER' encoder_req = '% --REQUIRES' encoder_desc = '% --DESC:' encoder_exam = '% --EXAM:' encoder_exop = '% --EXOP:' encoder_rndr = '% --RNDR:' def gen_encoders(bwipp_path, info_path): if os.path.exists(bwipp_path): encoder_flag = False encoders = dict() with open(bwipp_path, 'r') as bwipp: for line in bwipp.readlines(): if encoder_begin in line: encoder_flag = True name = line[len(encoder_begin):].strip().strip('-').lower() encoders[name] = dict() continue if encoder_flag: if encoder_req in line: requires = line[len(encoder_req):].strip().strip('-') encoders[name]['requires'] = requires if requires else None elif encoder_desc in line: desc = line[len(encoder_desc):].strip().strip('-') encoders[name]['desc'] = desc if desc else None elif encoder_exam in line: exam = line[len(encoder_exam):].strip().strip('-') encoders[name]['exam'] = exam if exam else None elif encoder_exop in line: exop = line[len(encoder_exop):].strip().strip('-') encoders[name]['exop'] = exop if exop else None elif encoder_rndr in line: rndr = line[len(encoder_rndr):].strip().strip('-') encoders[name]['rndr'] = rndr if rndr else None encoder_flag = False with open(info_path, 'wb') as info: pickle.dump(encoders, info) return encoders
Парсер состоит из одной простой функции, которая принимает на вход два параметра: путь до bwipp и путь для сохранения информации по кодам. Руками его запускать не придется, стартовать он будет из головного скрипта, при отсутствии готового файла с описанием.
barcode.py:
import os import pickle import bwipp_encoders class Barcode: def __init__(self, encoder_name, code, more_option='', position=(50, 50), bwipp=r'data/barcode', header=r'data/header', footer=r'data/footer', encoders=r'data/encoders'): self.moveto = position self.bwipp = bwipp self.header = header self.footer = footer assert all(map(os.path.exists, (self.bwipp, self.header, self.footer))) self.encoders = encoders if os.path.exists(self.encoders): with open(self.encoders, 'rb') as info: self.encoders_info = pickle.load(info) else: self.encoders_info = bwipp_encoders.gen_encoders(self.bwipp, self.encoders) self.full_template = '{bwipp}nn{header}nn{pos_x} {pos_y} moveto ({code}) ({exop}{more_option})n/{encoder_name} /uk.co.terryburton.bwipp findresource execnn{footer}' self.encoder_name = encoder_name.lower() self.code = code self.more_option = ' ' + more_option if more_option else '' def render(self): return self.full_template.format(bwipp=open(self.bwipp).read(), header=open(self.header).read(), pos_x=self.moveto[0], pos_y=self.moveto[1], code=self.code, exop=self.encoders_info[encoder_name]['exop'], more_option=self.more_option, encoder_name=self.encoder_name, footer=open(self.footer).read()) import sys encoder_name, code, *more_option = sys.argv[1:] bCode = Barcode(encoder_name, code, more_option=' '.join(more_option)) sys.stdout.write(bCode.render()) sys.stdout.flush()
Головной скрипт принимает на вход из командной строки информацию о необходимом баркоде, далее собирает необходимые параметры и формирует вывод PostScript’а, который состоит из bwipp и вызова необходимого шаблона-генератора.
Пример создания баркода из первой части, который мы собрали вручную:
Python barcode.py issn "1234-5678 01 12345" issntextsize=9 textsize=9 height=0.6 guardwidth=5 guardheight=6 guardrightpos=6 guardrightypos=36.5 > myBarcode.ps
Возможно вам не потребуется использовать дополнительные параметры, тогда вызов упрощается до:
Python barcode.py issn "1234-5678 01 12345" > myBarcode.ps
Вывод скрипта необходимо перенаправить в нужный нам файл, в противном случае увидите весь PostScript у себя на экране, а это зрелище не из приятных (:
Немного пробегусь по параметрам вызова класса Barcode:
encoder_name — имя баркода (строка);
code — сам код (строка);
more_option — дополнительные опции генератора баркода (строка). Где их взять я писал в первой части;
position — координаты левого нижнего угла баркода, описывает его положение на листе (список). Если вы решите конвертировать PS в ePS, все пустое пространство будет удалено, останется только баркод, поэтому положение особой роли не играет, главное чтоб углы не провалились за границу;
bwipp, header и footer — пути до соответствующих файлов: библиотека BWIPP, шапка для вставки, подвал для вставки (строки);
encoders — путь до файла с описанием кодов — результат работы парсера bwipp_encoders.py (строка). Если по этому пути файл отсутствует, то парсер запустится автоматически и создаст его из BWIPP.
Скрипт делался для работы в shell-скрипте, где по определенным, изменяемым параметрам генерируется баркод.
Буду рад, если данная статья кому-нибудь пригодится.