В первой части я попытался рассказать про библиотеку 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-скрипте, где по определенным, изменяемым параметрам генерируется баркод.
Буду рад, если данная статья кому-нибудь пригодится.