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

Django中如何将HTML模板转为单页PDF并生成JPG图片

解决方案

一、生成单页PDF

要避免Puppeteer自动分页,需调整配置并配合CSS强制单页:

1. 修改Puppeteer配置

移除pageRanges参数,设置足够大的自定义高度替代固定格式(如A4),同时开启preferCSSPageSize让HTML的CSS优先生效:

cmd_options={
    'height': '20000px',  # 设为足够容纳所有内容的高度,可根据实际调整
    'width': '210mm',     # 保持A4宽度,可选
    'scale': '1',
    'marginTop': '0',
    'marginLeft': '0',
    'marginRight': '0',
    'marginBottom': '0',
    'printBackground': True,
    'preferCSSPageSize': True,
    'output': output_temp_file,
}

2. 在HTML模板添加打印CSS

在模板的<style>标签中加入以下代码,强制打印时不分页:

@media print {
    body {
        height: auto !important;
        overflow: visible !important;
    }
    @page {
        size: auto;
        margin: 0;
    }
}

二、将单页PDF转为JPG

使用pdf2image库转换,需先安装依赖:

pip install pdf2image

同时安装系统依赖Poppler:

  • Ubuntu/Debian: sudo apt-get install poppler-utils
  • macOS: brew install poppler
  • Windows: 下载Poppler二进制包并添加到系统PATH

修改后的完整代码:

import os
from puppeteer_pdf import render_pdf_from_template
from pdf2image import convert_from_path
from django.conf import settings
from django.http import HttpResponse

def generate_pdf_invoice(invoice):
    context = {
        'invoice': invoice
    }
    output_temp_file = os.path.join(
        settings.BASE_DIR, 'static', 'temp.pdf')
    # 生成单页PDF
    render_pdf_from_template(
        input_template='shop/invoice_email_pdf.html',
        header_template='',
        footer_template='',
        context=context,
        cmd_options={
            'height': '20000px',
            'width': '210mm',
            'scale': '1',
            'marginTop': '0',
            'marginLeft': '0',
            'marginRight': '0',
            'marginBottom': '0',
            'printBackground': True,
            'preferCSSPageSize': True,
            'output': output_temp_file,
        }
    )
    # 转换PDF为JPG
    images = convert_from_path(output_temp_file)
    jpg_path = os.path.join(settings.BASE_DIR, 'static', 'temp.jpg')
    images[0].save(jpg_path, 'JPEG')

    # 返回JPG响应
    with open(jpg_path, 'rb') as f:
        response = HttpResponse(f.read(), content_type='image/jpeg')
        response['Content-Disposition'] = 'inline;filename=invoice.jpg'
    
    # 清理临时文件(可选)
    os.remove(output_temp_file)
    os.remove(jpg_path)
    return response

三、直接HTML转JPG的替代方案

跳过PDF转换步骤,直接生成JPG,更高效且保留CSS和图片:

方案1:使用Pyppeteer直接截图

Pyppeteer是Puppeteer的Python实现,支持全页面截图:

pip install pyppeteer

代码示例:

import asyncio
import os
from pyppeteer import launch
from django.conf import settings
from django.http import HttpResponse
from django.template.loader import render_to_string

async def html_to_jpg(html_content):
    browser = await launch(headless=True)
    page = await browser.newPage()
    await page.setContent(html_content)
    # 设置视口宽度,fullPage=True自动截取完整内容高度
    await page.setViewport({'width': 800, 'height': 100})
    screenshot = await page.screenshot({'fullPage': True, 'type': 'jpeg'})
    await browser.close()
    return screenshot

def generate_invoice_jpg(invoice):
    context = {'invoice': invoice}
    html_content = render_to_string('shop/invoice_email_pdf.html', context)
    
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    jpg_data = loop.run_until_complete(html_to_jpg(html_content))
    
    response = HttpResponse(jpg_data, content_type='image/jpeg')
    response['Content-Disposition'] = 'inline;filename=invoice.jpg'
    return response

方案2:使用html2image库

依赖Chrome/Chromium,配置简单:

pip install html2image

代码示例:

import os
from html2image import Html2Image
from django.conf import settings
from django.http import HttpResponse
from django.template.loader import render_to_string

def generate_invoice_jpg(invoice):
    context = {'invoice': invoice}
    html_content = render_to_string('shop/invoice_email_pdf.html', context)
    
    hti = Html2Image()
    # 若Chrome不在默认路径,需指定:hti.chrome_path = '/path/to/chrome'
    hti.screenshot(html_str=html_content, save_as='temp_invoice.jpg', size=(800, 0))
    
    with open('temp_invoice.jpg', 'rb') as f:
        response = HttpResponse(f.read(), content_type='image/jpeg')
        response['Content-Disposition'] = 'inline;filename=invoice.jpg'
    
    os.remove('temp_invoice.jpg')
    return response

内容的提问来源于stack exchange,提问作者Manoj Kamble

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:16:05