Генерация PostScript штрих-кодов (barcode). Часть 2

barcode

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

Буду рад, если данная статья кому-нибудь пригодится.

Ссылки: Zip, GitHub

Рейтинг
( 1 оценка, среднее 5 из 5 )
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

:) :D :( :o 8O :? 8) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen:
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.