246 lines
6 KiB
Python
246 lines
6 KiB
Python
# coding=utf-8
|
|
#
|
|
# Authored by Martin Owens <doctormo@gmail.com>
|
|
# Debugged by Ralf Heinecke & Martin Siepmann 2007-09-07
|
|
# Horst Schottky 2010-02-27
|
|
#
|
|
# Copyright (C) 2007 Martin Owens
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA.
|
|
#
|
|
"""
|
|
Renderer for Code128/EAN128 codes. Designed for use with Inkscape.
|
|
"""
|
|
|
|
import re
|
|
|
|
from .Base import Barcode
|
|
|
|
CODE_MAP = [
|
|
"11011001100",
|
|
"11001101100",
|
|
"11001100110",
|
|
"10010011000",
|
|
"10010001100",
|
|
"10001001100",
|
|
"10011001000",
|
|
"10011000100",
|
|
"10001100100",
|
|
"11001001000",
|
|
"11001000100",
|
|
"11000100100",
|
|
"10110011100",
|
|
"10011011100",
|
|
"10011001110",
|
|
"10111001100",
|
|
"10011101100",
|
|
"10011100110",
|
|
"11001110010",
|
|
"11001011100",
|
|
"11001001110",
|
|
"11011100100",
|
|
"11001110100",
|
|
"11101101110",
|
|
"11101001100",
|
|
"11100101100",
|
|
"11100100110",
|
|
"11101100100",
|
|
"11100110100",
|
|
"11100110010",
|
|
"11011011000",
|
|
"11011000110",
|
|
"11000110110",
|
|
"10100011000",
|
|
"10001011000",
|
|
"10001000110",
|
|
"10110001000",
|
|
"10001101000",
|
|
"10001100010",
|
|
"11010001000",
|
|
"11000101000",
|
|
"11000100010",
|
|
"10110111000",
|
|
"10110001110",
|
|
"10001101110",
|
|
"10111011000",
|
|
"10111000110",
|
|
"10001110110",
|
|
"11101110110",
|
|
"11010001110",
|
|
"11000101110",
|
|
"11011101000",
|
|
"11011100010",
|
|
"11011101110",
|
|
"11101011000",
|
|
"11101000110",
|
|
"11100010110",
|
|
"11101101000",
|
|
"11101100010",
|
|
"11100011010",
|
|
"11101111010",
|
|
"11001000010",
|
|
"11110001010",
|
|
"10100110000",
|
|
"10100001100",
|
|
"10010110000",
|
|
"10010000110",
|
|
"10000101100",
|
|
"10000100110",
|
|
"10110010000",
|
|
"10110000100",
|
|
"10011010000",
|
|
"10011000010",
|
|
"10000110100",
|
|
"10000110010",
|
|
"11000010010",
|
|
"11001010000",
|
|
"11110111010",
|
|
"11000010100",
|
|
"10001111010",
|
|
"10100111100",
|
|
"10010111100",
|
|
"10010011110",
|
|
"10111100100",
|
|
"10011110100",
|
|
"10011110010",
|
|
"11110100100",
|
|
"11110010100",
|
|
"11110010010",
|
|
"11011011110",
|
|
"11011110110",
|
|
"11110110110",
|
|
"10101111000",
|
|
"10100011110",
|
|
"10001011110",
|
|
"10111101000",
|
|
"10111100010",
|
|
"11110101000",
|
|
"11110100010",
|
|
"10111011110",
|
|
"10111101110",
|
|
"11101011110",
|
|
"11110101110",
|
|
"11010000100",
|
|
"11010010000",
|
|
"11010011100",
|
|
"11000111010",
|
|
"11",
|
|
]
|
|
|
|
|
|
def map_extra(data, chars):
|
|
"""Maps the data into the chars"""
|
|
result = list(data)
|
|
for char in chars:
|
|
result.append(chr(char))
|
|
result.append("FNC3")
|
|
result.append("FNC2")
|
|
result.append("SHIFT")
|
|
return result
|
|
|
|
|
|
# The map_extra method is used to slim down the amount
|
|
# of pre code and instead we generate the lists
|
|
CHAR_AB = list(" !\"#$%&'()*+,-./0123456789:;<=>?@" "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_")
|
|
CHAR_A = map_extra(CHAR_AB, range(0, 31)) # Offset 64
|
|
CHAR_B = map_extra(CHAR_AB, range(96, 127)) # Offset -32
|
|
|
|
|
|
class Code128(Barcode):
|
|
"""Main barcode object, generates the encoding bits here"""
|
|
|
|
def encode(self, text):
|
|
blocks = []
|
|
block = ""
|
|
|
|
# Split up into sections of numbers, or characters
|
|
# This makes sure that all the characters are encoded
|
|
# In the best way possible for Code128
|
|
for datum in re.findall(r"(?:(?:\d\d){2,})|(?:^\d\d)|.", text):
|
|
if len(datum) == 1:
|
|
block = block + datum
|
|
else:
|
|
if block:
|
|
blocks.append(self.best_block(block))
|
|
block = ""
|
|
blocks.append(["C", datum])
|
|
|
|
if block:
|
|
blocks.append(Code128.best_block(block))
|
|
block = ""
|
|
|
|
return Code128.encode_blocks(blocks)
|
|
|
|
@staticmethod
|
|
def best_block(block):
|
|
"""If this has characters above 63, select B over A"""
|
|
if any(ord(x) > 63 for x in block):
|
|
return ["B", block]
|
|
return ["A", block]
|
|
|
|
@staticmethod
|
|
def encode_blocks(blocks):
|
|
"""Encode the given blocks into A, B or C codes"""
|
|
encode = ""
|
|
total = 0
|
|
pos = 0
|
|
|
|
for block in blocks:
|
|
b_set = block[0]
|
|
datum = block[1]
|
|
|
|
# POS : 0, 1
|
|
# A : 101, 103
|
|
# B : 100, 104
|
|
# C : 99, 105
|
|
num = 0
|
|
if b_set == "A":
|
|
num = 103
|
|
elif b_set == "B":
|
|
num = 104
|
|
elif b_set == "C":
|
|
num = 105
|
|
|
|
i = pos
|
|
if pos:
|
|
num = 204 - num
|
|
else:
|
|
i = 1
|
|
|
|
total = total + num * i
|
|
encode = encode + CODE_MAP[num]
|
|
pos += 1
|
|
|
|
if b_set in ("A", "B"):
|
|
chars = CHAR_B
|
|
if b_set == "A":
|
|
chars = CHAR_A
|
|
|
|
for char in datum:
|
|
total = total + (chars.index(char) * pos)
|
|
encode = encode + CODE_MAP[chars.index(char)]
|
|
pos += 1
|
|
else:
|
|
for char in (datum[i : i + 2] for i in range(0, len(datum), 2)):
|
|
total = total + (int(char) * pos)
|
|
encode = encode + CODE_MAP[int(char)]
|
|
pos += 1
|
|
|
|
checksum = total % 103
|
|
encode = encode + CODE_MAP[checksum]
|
|
encode = encode + CODE_MAP[106]
|
|
encode = encode + CODE_MAP[107]
|
|
|
|
return encode
|