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

Django生成PDF发票时如何嵌入动态SVG条形码?

Django渲染PDF时嵌入动态生成SVG条形码的解决方案

我之前也碰到过一模一样的问题——用Django+xhtml2pdf生成发票PDF,文本都正常显示,就是动态生成的SVG条形码死活出不来。试过直接传条形码对象、cid引用都没用,后来发现把SVG字节码转成base64编码的data URI嵌入HTML是最靠谱的办法,分享给你:

核心思路

xhtml2pdf对外部引用的SVG支持不太稳定,而且我们的SVG是动态生成的没存本地文件,cid引用还要处理附件逻辑特别麻烦。直接把SVG字节码转成base64编码的data URI,嵌入到HTML的img标签里,xhtml2pdf就能直接渲染出来,全程在内存里处理,不用存临时文件。

修改后的代码实现

1. 调整View中的条形码生成逻辑

把原来生成条形码对象的代码改成在内存中生成SVG字节码,再转成base64:

import base64
from io import BytesIO
import barcode
from barcode.writer import SVGWriter
from django.views.generic import View

class GenerateInvoicePdf(View):
    def get(self, request, *args, **kwargs):
        package = Package.objects.get(package_no=request.GET.get('package'))
        address = package.purchase.order_product.delivery_location
        
        # 1. 在内存中生成SVG条形码
        CODE128 = barcode.get_barcode_class('code128')
        svg_buffer = BytesIO()
        # 使用SVGWriter直接写入内存缓冲区
        barcode_obj = CODE128(package.package_no, writer=SVGWriter())
        barcode_obj.write(svg_buffer)
        
        # 2. 转成base64编码并拼接成data URI
        svg_base64 = base64.b64encode(svg_buffer.getvalue()).decode('utf-8')
        barcode_data_uri = f'data:image/svg+xml;base64,{svg_base64}'

        if request.user.display_username == seller.display_username:
            data = {
                'package': package,
                'address': address,
                'barcode_data_uri': barcode_data_uri,  # 把这个传给模板
            }
            pdf = render_to_pdf('pdf/invoice.html', data)
            if pdf:
                response = HttpResponse(pdf, content_type='application/pdf')
                filename = f"Invoice_{package.package_no}.pdf"
                content_disposition = "inline; filename='%s'" % filename
                if request.GET.get("download"):
                    content_disposition = "attachment; filename='%s'" % filename
                response['Content-Disposition'] = content_disposition
                return response
        return HttpResponse("Not found")

2. 优化PDF渲染函数(可选)

把编码换成UTF-8,避免一些特殊字符的解析问题:

from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa

def render_to_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html = template.render(context_dict)
    result = BytesIO()
    # 用UTF-8编码替代ISO-8859-1,适配更多字符场景
    pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
    if not pdf.err:
        return HttpResponse(result.getvalue(), content_type='application/pdf')
    return None

3. 修改HTML模板

把原来的条形码对象引用换成img标签,直接使用生成的data URI:

<body>
  <div class="container-fluid">
    <div class="row">
      <div class="col-6">
        <div class="row">
          <div class="col-12">
            <!-- 用data URI引用SVG条形码 -->
            <img src="{{ barcode_data_uri }}" 
                 alt="{{ package.package_no }}" 
                 style="height: 23mm; width: auto; display: block;" />
            <br>
            {{ package.package_no }}
            <!-- 其他发票内容 -->
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

为什么这个方法能行?

  • data URI把SVG的完整内容直接嵌入到HTML里,xhtml2pdf渲染时不需要读取外部文件,避免了文件路径、权限的问题
  • base64编码把二进制的SVG字节码转换成纯文本,不会和HTML的标签、特殊字符冲突
  • 全程在内存中处理,不需要临时文件,效率更高也更干净

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:17:40