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
相关产品推荐
相关产品推荐

