绘制条形码在 plot window 中的显示方式与在保存的 .pdf 中的显示方式不同
Plotting barcode displays differently in plot window than in saved .pdf
我在正确保存我的 pdf 文件时遇到了一些问题。我正在尝试绘制条形码标签,然后将其另存为 pdf,如以下代码所示。我在 windows 上安装了 code128.ttf 字体。此外,我已尝试将 .savefig dpi 参数设置为 fig.dpi,如 this post.
中所述
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
def draw_label(label, label_dimensions_x=3.8189, label_dimensions_y=1.41732):
# import barcode code128 font
fpath = os.path.join("path", "to", "font", "code128.ttf")
prop = fm.FontProperties(fname=fpath, size=58)
fig, ax = plt.subplots(1, figsize=(label_dimensions_x,
label_dimensions_y))
plt.axis('off')
plt.xticks([], [])
plt.yticks([], [])
plt.tight_layout()
plt.xlim(0, label_dimensions_x)
plt.ylim(0, label_dimensions_y)
# plot barcode
plt.text(label_dimensions_x / 2, label_dimensions_y / 2, label,
ha='center', va='bottom',
fontproperties=prop)
plt.show()
try:
plt.savefig(os.path.join("path", "to", "output", label + '.pdf'),
dpi=plt.gcf().dpi)
except PermissionError:
logging.warning("Close the current label pdf's before running this script.")
plt.close()
return
draw_label('123456789')
This 是图中输出的内容 window.
This 是 .pdf 保存文件中的输出,所有类型的标签都会出现这种情况 - 这并不是说数字 1 到 9 除了 8 不可打印。
编辑:如果我用普通文本字体(在本例中为 Frutiger Roman)代替 code128.ttf,并设置 plt.axis('on') 文本不会被剪裁,请参阅 this .承认,它不漂亮,不太适合,但它仍然应该是可读的。
萨姆,
首先,您的条形码不会按原样扫描。该字符串需要为 Code128B 添加起始字符、校验和和停止字符。所以,就是这样。
我建议更改为 Code 39 字体(不需要校验和,开始和结束字符相同:“*”)或编写代码来生成校验和并进一步了解 Code 128在 Code 128 Wiki.
其次,我怀疑在转换为 PDF 的过程中图形的边界框存在问题。正在转换的那一小段条形码看起来更像是字符串中数字 9 的一部分。我怀疑正在进行一些图像剪辑。
尝试替换为常规文本字体以确保条形码图像不会在转换过程中丢失。
编辑答案以包含使用 PNG 而不是 PDF 的建议。
如果您输出为 PNG 格式,我设法让软件工作。我知道,现在问题变成了如何将 PNG 转换为 PDF。您可以从调查此处提到的一些库开始:Create PDF from a list of images
简而言之,我建议您创建图形文件,然后将它们嵌入到文档文件中。
我还添加了构建带有开始字符、校验和和停止字符的条形码所需的代码:
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
def draw_label(label, label_dimensions_x=3.8189, label_dimensions_y=1.41732):
# import barcode code128 font
fpath = os.path.join("./", "code128.ttf")
prop = fm.FontProperties(fname=fpath, size=32)
fig, ax = plt.subplots(1, figsize=(label_dimensions_x,
label_dimensions_y))
plt.axis('off')
plt.xticks([], [])
plt.yticks([], [])
plt.tight_layout()
plt.xlim(0, label_dimensions_x)
plt.ylim(0, label_dimensions_y)
# calc checksum THEN plot barcode
weight = 1
chksum = 104
for x in label:
chksum = chksum + weight*(ord(x)-32)
weight = weight + 1
chksum = chksum % 103
chkchar = chr(chksum+32)
label128 = "%s%s%s%s" % ('Ñ', label, chkchar, 'Ó')
plt.text(label_dimensions_x / 2, label_dimensions_y / 2, label128,
ha='center', va='bottom',
fontproperties=prop)
try:
plt.savefig(os.path.join("./", label + '.png'))
except PermissionError:
logging.warning("Close the current label pdf's before running this script.")
return
draw_label('123456789')
draw_label('987654321')
draw_label('Test&Show')
你使用 matplotlib 和字体使事情过于复杂。直接生成图片并保存为PDF文件并不复杂,也更加可靠。
如 所述,仅对字符串中的字符进行编码是不够的。您需要添加一个起始码、一个校验和和一个终止码来制作一个完整的条形码。下面的函数 code128_codes
执行此操作,将转换为图像作为一个单独的步骤。
from PIL import Image
def list_join(seq):
''' Join a sequence of lists into a single list, much like str.join
will join a sequence of strings into a single string.
'''
return [x for sub in seq for x in sub]
_code128B_mapping = dict((chr(c), [98, c+64] if c < 32 else [c-32]) for c in range(128))
_code128C_mapping = dict([(u'%02d' % i, [i]) for i in range(100)] + [(u'%d' % i, [100, 16+i]) for i in range(10)])
def code128_codes(s):
''' Code 128 conversion to a list of raw integer codes.
Only encodes ASCII characters, does not take advantage of
FNC4 for bytes with the upper bit set. Control characters
are not optimized and expand to 2 characters each.
Coded for
'''
if s.isdigit() and len(s) >= 2:
# use Code 128C, pairs of digits
codes = [105] + list_join(_code128C_mapping[s[i:i+2]] for i in range(0, len(s), 2))
else:
# use Code 128B and shift for Code 128A
codes = [104] + list_join(_code128B_mapping[c] for c in s)
check_digit = (codes[0] + sum(i * x for i,x in enumerate(codes))) % 103
codes.append(check_digit)
codes.append(106) # stop code
return codes
_code128_patterns = '''
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 1100011101011'''.split()
def code128_img(s, height=100, bar_width=1):
''' Generate a Code 128 barcode image.
Coded for
'''
codes = code128_codes(s)
pattern = ''.join(_code128_patterns[c] for c in codes)
pattern = '00000000000' + pattern + '00000000000'
width = bar_width * len(pattern)
color, bg = (0, 0, 0), (255, 255, 255)
im = Image.new('RGB', (width, height), bg)
ld = im.load()
for i, bar in enumerate(pattern):
if bar == '1':
for y in range(height):
for x in range(i * bar_width, (i + 1) * bar_width):
ld[x, y] = color
return im
>>> im = code128_img('AM-H-10-01-1')
>>> im.save(r'c:\temp\temp.pdf')
我在正确保存我的 pdf 文件时遇到了一些问题。我正在尝试绘制条形码标签,然后将其另存为 pdf,如以下代码所示。我在 windows 上安装了 code128.ttf 字体。此外,我已尝试将 .savefig dpi 参数设置为 fig.dpi,如 this post.
中所述import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
def draw_label(label, label_dimensions_x=3.8189, label_dimensions_y=1.41732):
# import barcode code128 font
fpath = os.path.join("path", "to", "font", "code128.ttf")
prop = fm.FontProperties(fname=fpath, size=58)
fig, ax = plt.subplots(1, figsize=(label_dimensions_x,
label_dimensions_y))
plt.axis('off')
plt.xticks([], [])
plt.yticks([], [])
plt.tight_layout()
plt.xlim(0, label_dimensions_x)
plt.ylim(0, label_dimensions_y)
# plot barcode
plt.text(label_dimensions_x / 2, label_dimensions_y / 2, label,
ha='center', va='bottom',
fontproperties=prop)
plt.show()
try:
plt.savefig(os.path.join("path", "to", "output", label + '.pdf'),
dpi=plt.gcf().dpi)
except PermissionError:
logging.warning("Close the current label pdf's before running this script.")
plt.close()
return
draw_label('123456789')
This 是图中输出的内容 window.
This 是 .pdf 保存文件中的输出,所有类型的标签都会出现这种情况 - 这并不是说数字 1 到 9 除了 8 不可打印。 编辑:如果我用普通文本字体(在本例中为 Frutiger Roman)代替 code128.ttf,并设置 plt.axis('on') 文本不会被剪裁,请参阅 this .承认,它不漂亮,不太适合,但它仍然应该是可读的。
萨姆,
首先,您的条形码不会按原样扫描。该字符串需要为 Code128B 添加起始字符、校验和和停止字符。所以,就是这样。
我建议更改为 Code 39 字体(不需要校验和,开始和结束字符相同:“*”)或编写代码来生成校验和并进一步了解 Code 128在 Code 128 Wiki.
其次,我怀疑在转换为 PDF 的过程中图形的边界框存在问题。正在转换的那一小段条形码看起来更像是字符串中数字 9 的一部分。我怀疑正在进行一些图像剪辑。
尝试替换为常规文本字体以确保条形码图像不会在转换过程中丢失。
编辑答案以包含使用 PNG 而不是 PDF 的建议。
如果您输出为 PNG 格式,我设法让软件工作。我知道,现在问题变成了如何将 PNG 转换为 PDF。您可以从调查此处提到的一些库开始:Create PDF from a list of images
简而言之,我建议您创建图形文件,然后将它们嵌入到文档文件中。
我还添加了构建带有开始字符、校验和和停止字符的条形码所需的代码:
import os import matplotlib.pyplot as plt from matplotlib import font_manager as fm def draw_label(label, label_dimensions_x=3.8189, label_dimensions_y=1.41732): # import barcode code128 font fpath = os.path.join("./", "code128.ttf") prop = fm.FontProperties(fname=fpath, size=32) fig, ax = plt.subplots(1, figsize=(label_dimensions_x, label_dimensions_y)) plt.axis('off') plt.xticks([], []) plt.yticks([], []) plt.tight_layout() plt.xlim(0, label_dimensions_x) plt.ylim(0, label_dimensions_y) # calc checksum THEN plot barcode weight = 1 chksum = 104 for x in label: chksum = chksum + weight*(ord(x)-32) weight = weight + 1 chksum = chksum % 103 chkchar = chr(chksum+32) label128 = "%s%s%s%s" % ('Ñ', label, chkchar, 'Ó') plt.text(label_dimensions_x / 2, label_dimensions_y / 2, label128, ha='center', va='bottom', fontproperties=prop) try: plt.savefig(os.path.join("./", label + '.png')) except PermissionError: logging.warning("Close the current label pdf's before running this script.") return draw_label('123456789') draw_label('987654321') draw_label('Test&Show')
你使用 matplotlib 和字体使事情过于复杂。直接生成图片并保存为PDF文件并不复杂,也更加可靠。
如 code128_codes
执行此操作,将转换为图像作为一个单独的步骤。
from PIL import Image
def list_join(seq):
''' Join a sequence of lists into a single list, much like str.join
will join a sequence of strings into a single string.
'''
return [x for sub in seq for x in sub]
_code128B_mapping = dict((chr(c), [98, c+64] if c < 32 else [c-32]) for c in range(128))
_code128C_mapping = dict([(u'%02d' % i, [i]) for i in range(100)] + [(u'%d' % i, [100, 16+i]) for i in range(10)])
def code128_codes(s):
''' Code 128 conversion to a list of raw integer codes.
Only encodes ASCII characters, does not take advantage of
FNC4 for bytes with the upper bit set. Control characters
are not optimized and expand to 2 characters each.
Coded for
'''
if s.isdigit() and len(s) >= 2:
# use Code 128C, pairs of digits
codes = [105] + list_join(_code128C_mapping[s[i:i+2]] for i in range(0, len(s), 2))
else:
# use Code 128B and shift for Code 128A
codes = [104] + list_join(_code128B_mapping[c] for c in s)
check_digit = (codes[0] + sum(i * x for i,x in enumerate(codes))) % 103
codes.append(check_digit)
codes.append(106) # stop code
return codes
_code128_patterns = '''
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 1100011101011'''.split()
def code128_img(s, height=100, bar_width=1):
''' Generate a Code 128 barcode image.
Coded for
'''
codes = code128_codes(s)
pattern = ''.join(_code128_patterns[c] for c in codes)
pattern = '00000000000' + pattern + '00000000000'
width = bar_width * len(pattern)
color, bg = (0, 0, 0), (255, 255, 255)
im = Image.new('RGB', (width, height), bg)
ld = im.load()
for i, bar in enumerate(pattern):
if bar == '1':
for y in range(height):
for x in range(i * bar_width, (i + 1) * bar_width):
ld[x, y] = color
return im
>>> im = code128_img('AM-H-10-01-1')
>>> im.save(r'c:\temp\temp.pdf')