You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中用Barcode库生成条码后添加商品名称的字体适配问题

解决Python Barcode库生成条码后添加商品名称的字体/尺寸问题

我用Python的Barcode库生成条码,核心代码如下:

barcodes = CompanyBarcodes.objects.filter(asn_id__asn_number=asn_id,
                                          company=company,
                                          product__asset_category__in=cat_ids
    ).prefetch_related('company', 'product', 'grn_id', 'asn_id', 'itemGroup')

items = []

for i in barcodes:
    items.append({'bar': i.barcode, 'name': str(i.product.name)
                  + " - " + str(i.product.sku)})

alist = []

for item in items:
    print("item", item)
    EAN = barcode.get_barcode_class('code128')
    d = {'module_width': 0.15,
         'module_height': 2.0,
         'quiet_zone': 0.5,
         'text_distance': 1.5,
         'font_size': 3,
         'text_line_distance': 3,
         'dpi': 900}
    w = ImageWriter(d)
    ean = EAN(item['bar'], writer=ImageWriter())
    a = ean.save(item['bar'], options=d)

现在需要把items里的商品名称(name字段)添加到生成的条码图片中,我尝试了以下代码,但添加的文字尺寸过小,且和条码自带的字体不一致:

with open(a, 'rb') as image:
    img = Image.open(image)

    # Create a drawing context on the image
    draw = ImageDraw.Draw(img)

    # Use the same font as the original barcode image
    font = ImageFont.load_default()

    # Set the font size
    font_size = 10  # You can adjust the font size as needed

    # Calculate the position to center the text
    text = item['name']
    text_width, text_height = draw.textsize(text, font=font)
    image_width, image_height = img.size
    text_x = (image_width - text_width) / 2
    text_y = image_height - text_height - 5  # Adjust the vertical position as needed

    # Draw the text on the image
    draw.text((text_x, text_y), text, fill=(0, 0, 0), font=font)  # You can adjust the fill color

    # Save the modified image
    img.save(a)  # Overwrite the original image with the changes
    encoded_image = base64.b64encode(open(a, 'rb').read()).decode('utf-8')
    alist.append({'image': encoded_image, **item})

解决方案

1. 匹配条码使用的字体

Barcode库默认使用FreeMono等宽字体(和条码下方数字的字体一致),不要用ImageFont.load_default()加载默认字体,直接指定同类型等宽字体即可。如果系统没有FreeMono,可替换为Courier New等系统自带的等宽字体。

2. 按DPI换算字体大小

因为生成条码时设置了dpi=900,字体大小需要按这个DPI换算(条码的font_size=3对应900DPI下的3*900/72≈38号字体),避免文字过小。

修改后的完整代码

将添加文字的代码替换为以下内容:

from PIL import Image, ImageDraw, ImageFont

# 获取条码生成时的DPI配置
dpi = d['dpi']
# 按DPI换算字体大小,和条码文字尺寸匹配
font_size = int(d['font_size'] * dpi / 72)

# 加载和条码一致的等宽字体
try:
    font = ImageFont.truetype("FreeMono.ttf", font_size)
except IOError:
    # 兜底用Courier New等宽字体
    font = ImageFont.truetype("Courier New", font_size)
except:
    # 极端情况用默认字体,但按DPI放大
    font = ImageFont.load_default(size=font_size)

with open(a, 'rb') as image:
    img = Image.open(image)
    draw = ImageDraw.Draw(img)
    text = item['name']
    
    # 计算文字位置:水平居中,垂直在条码下方预留足够间距
    text_width, text_height = draw.textsize(text, font=font)
    image_width, image_height = img.size
    text_x = (image_width - text_width) // 2
    # 按DPI换算偏移量,避免在不同分辨率下位置偏移
    text_y = image_height - text_height - int(10 * dpi / 72)
    
    # 绘制文字,颜色和条码文字保持一致(黑色)
    draw.text((text_x, text_y), text, fill=(0, 0, 0), font=font)
    
    # 保存时指定DPI,避免图片缩放变形
    img.save(a, dpi=(dpi, dpi))
    encoded_image = base64.b64encode(open(a, 'rb').read()).decode('utf-8')
    alist.append({'image': encoded_image, **item})

额外优化点

  • 生成条码时复用已定义的ImageWriter实例,避免参数不一致:
    ean = EAN(item['bar'], writer=w)  # 用之前定义的w,而非重新创建ImageWriter()
    a = ean.save(item['bar'], options=d)
    
  • 若商品名称过长,可添加自动换行逻辑:
    # 按图片宽度自动拆分文字
    def wrap_text(text, font, max_width):
        lines = []
        current_line = ""
        for word in text.split():
            test_line = current_line + word + " "
            test_width, _ = draw.textsize(test_line, font=font)
            if test_width <= max_width:
                current_line = test_line
            else:
                lines.append(current_line.strip())
                current_line = word + " "
        lines.append(current_line.strip())
        return lines
    
    # 应用换行逻辑,左右预留边距
    wrapped_lines = wrap_text(text, font, image_width - int(20 * dpi / 72))
    total_text_height = text_height * len(wrapped_lines)
    # 调整垂直位置,让所有换行文字居中
    text_y = image_height - total_text_height - int(10 * dpi / 72)
    
    # 逐行绘制文字
    for line in wrapped_lines:
        line_width, _ = draw.textsize(line, font=font)
        line_x = (image_width - line_width) // 2
        draw.text((line_x, text_y), line, fill=(0,0,0), font=font)
        text_y += text_height
    

内容的提问来源于stack exchange,提问作者Rahul Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 06:05:03