HTML页面导出为PDF

本文介绍了如何将HTML页面转换为PDF,通过使用html2canvas和jsPdf库进行实践操作,详细阐述了准备js文件、创建测试页面以及添加导出PDF功能的步骤,展示了点击按钮后生成的PDF效果。

交接的内容中涉及到了HTML页面导出为PDF这一功能需求,虽然之前由看过,但是为了防止自己忘记,还是自己再实践一下的好,嗯。

测试

1:准备两个js文件

jsPdf.debug.js  //选择合适你的版本
html2canvas.js  //选择合适你的版本
需要这样两个js文件,其中html2canvas.js文件主要用于将html文件转换为图片,而后jsPdf.debug.js文件负责将图片导成文件。

2:准备一个测试页面

3:增加一个按钮,导出pdf

代码部分:

	<script type="text/javascript" src="/xyjy/js/jquery-2.0.3.min.js" charset="utf-8">
        </script>
        <script type="text/javascript" src="/xyjy/js/jsPdf.debug.js" charset="utf-8">
        </script>
        <script type="text/javascript" src="/xyjy/js/html2canvas.js" charset="utf-8">
        </script>
	
        <script type="text/javascript">
              //这个是我增加的那个按钮
	      var downButton = document.getElementById("2pdf");
	
	      downButton.onclick = function() {
                   //将downPDF这个对象渲染成canvas
                   html2canvas(document.getElementById("downPDf"), {
	              onrendered:function(canvas) {
	
	                  var contentWidth = canvas.width;
	                  var contentHeight = canvas.height;
	
	                  //一页pdf显示html页面生成的canvas高度;
	                  var pageHeight = contentWidth / 592.28 * 841.89;
	                  //未生成pdf的html页面高度
	                  var leftHeight = contentHeight;
	                  //pdf页面偏移
	                  var position = 0;
	                  //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
	                  var imgWidth = 595.28;
	                  var imgHeight = 592.28/contentWidth * contentHeight;
	
	                  var pageData = canvas.toDataURL('image/jpeg', 1.0);
	
	                  var pdf = new jsPDF('', 'pt', 'a4');
	
	                  //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
	                  //当内容未超过pdf一页显示的范围,无需分页
	                  if (leftHeight < pageHeight) {
	                      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
	                  } else {
	                      while(leftHeight > 0) {
	                          pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
	                          leftHeight -= pageHeight;
	                          position -= 841.89;
	                          //避免添加空白页
	                          if(leftHeight > 0) {
	                              pdf.addPage();
	                          }
	                      }
	                  }
	
	                  pdf.save('html转pdf测试.pdf');
	              }
	          })
	      }
	   </script>

界面展示:

点击按钮后,弹出:

点击保存文件,打开这个文件后:

链接推荐
https://segmentfault.com/a/1190000009211079


<think>我们正在处理用户的问题:将Django生成的HTML页面导出PDF格式。 根据之前的对话历史,用户可能已经尝试过一些方法,但我们需要提供一个清晰的解决方案。 在Django中,将HTML页面导出PDF通常有以下几种方式: 1. 使用第三方库如WeasyPrint、xhtml2pdfpdfkit(基于wkhtmltopdf)等。 2. 使用Django的模板渲染,然后将渲染后的HTML转换为PDF。 3. 考虑使用浏览器的打印功能(前端实现),但用户明确要求后端生成。 根据引用[3]中提到的“自定义响应类处理PDF头信息”,我们可以参考这个思路,使用一个视图来返回PDF响应。 这里我们选择WeasyPrint作为示例,因为它支持现代CSS,且易于使用。 步骤: 1. 安装WeasyPrint:`pip install WeasyPrint` 2. 创建一个视图,使用WeasyPrint将渲染的HTML模板转换为PDF,并返回HTTP响应。 注意:如果用户有复杂的CSS(尤其是需要网络加载的资源),可能需要配置BASE_URL以确保正确加载资源。 另外,根据引用[2]中关于静态资源的配置,确保在生成PDF时能够正确访问静态资源(如图片、CSS等)。在开发环境中,可以使用本地文件路径,但在生产环境中可能需要不同的处理。 下面是一个示例视图: ```python from django.template.loader import render_to_string from django.http import HttpResponse from weasyprint import HTML import os def export_pdf(request): # 渲染模板 context = {'some_key': 'some_value'} # 传递上下文数据 html_string = render_to_string('my_template.html', context) # 创建HTML对象 # 注意:如果使用文件路径,需要设置base_url以访问静态文件 # 这里假设在开发环境中,我们使用本地文件系统提供静态文件 base_url = request.build_absolute_uri('/') # 获取当前站点的根URL,用于加载静态资源 # 生成PDF pdf = HTML(string=html_string, base_url=base_url).write_pdf() # 创建响应 response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="exported_page.pdf"' return response ``` 但是,上述方法可能会遇到静态资源路径问题,因为WeasyPrint需要访问CSS和图片等资源。在开发环境中,由于DEBUG=True,静态资源由Django提供,所以使用base_url为网站根路径可以工作。但在生产环境中,静态资源通常由Nginx等服务器提供,且可能不在同一个域名下,或者有访问控制,这可能导致WeasyPrint无法获取静态资源。 解决方案: - 在生成PDF时,确保base_url正确指向静态资源的位置。 - 或者,将静态资源内联到HTML中(例如,使用base64编码图片),但这样会增加HTML大小。 另外,如果用户需要处理大文件或高并发,可能需要考虑异步任务,但这超出了当前问题的范围。 根据引用[3]中提到的“使用生成器函数实现内存友好的流式处理”,我们可以考虑使用流式响应,但WeasyPrint本身是一次性生成整个PDF的。 另一种方案:使用xhtml2pdf,它也是常用的库,但CSS支持不如WeasyPrint。 考虑到用户可能已经有一个完整的HTML页面(包括CSS),我们优先推荐WeasyPrint。 如果用户需要处理权限(如引用[3]中的部门隔离),可以在视图函数中添加权限检查。 示例:在视图函数开始处检查用户权限,例如: ```python from django.contrib.auth.decorators import login_required @login_required def export_pdf(request): # 检查用户权限,例如只有特定部门的用户才能访问 if not request.user.has_perm('app.export_pdf'): # 处理无权限的情况 return HttpResponseForbidden("You don't have permission to export PDF.") # ... 其余代码同上 ``` 或者使用基于类的视图(如引用[3]中的DepartmentAccessMixin)来集成权限控制。 因此,我们可以提供一个集成了权限控制的基于类的视图示例: ```python from django.views import View from django.contrib.auth.mixins import LoginRequiredMixin from your_app.mixins import DepartmentAccessMixin # 假设用户已经实现了部门隔离的Mixin class ExportPDFView(LoginRequiredMixin, DepartmentAccessMixin, View): def get(self, request, *args, **kwargs): # 渲染模板 context = self.get_context_data(**kwargs) html_string = render_to_string('my_template.html', context) base_url = request.build_absolute_uri('/') pdf = HTML(string=html_string, base_url=base_url).write_pdf() response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="exported_page.pdf"' return response def get_context_data(self, **kwargs): # 在这里准备上下文数据,可以重写以添加更多数据 context = super().get_context_data(**kwargs) # 添加额外的上下文数据 context['some_key'] = 'some_value' return context ``` 注意:DepartmentAccessMixin需要根据用户的具体模型进行调整。 另外,如果用户需要传递参数(如要导出的文档ID),可以在URL中捕获,并在视图中处理。 最后,记得在urls.py中配置该视图的URL。 总结步骤: 1. 安装WeasyPrint 2. 创建模板(确保模板中的静态资源使用绝对路径,或者能被base_url正确解析) 3. 编写视图函数或视图类,处理权限和业务逻辑,将模板渲染为PDF 4. 配置URL 注意事项: - 如果CSS中使用@import或外部资源,确保这些资源在生成PDF时可访问。 - 生产环境中,静态资源可能通过CDN或反向代理提供,需要确保base_url设置正确,或者考虑使用文件系统路径(如果静态文件在服务器本地)。 如果用户遇到CSS问题,建议先简化模板,逐步测试。 根据用户的问题,我们提供了使用WeasyPrint的解决方案,并考虑了权限控制和资源访问问题。 生成相关问题: 1. 如何解决WeasyPrint生成PDF时CSS加载失败的问题? 2. 除了WeasyPrint,还有哪些Django生成PDF的库? 3. 如何将Django中的动态图表(如通过JavaScript生成)导出PDF? 4. 如何提高生成PDF的性能(针对大文档或高并发场景)? 5. 如何将生成的PDF直接通过电子邮件发送?</think>在 Django 中将 HTML 页面导出PDF 有多种实现方案,以下是三种主流方法的详细实现和对比: ### 方案一:使用 WeasyPrint(推荐) ```python # views.py from django.template.loader import render_to_string from django.http import HttpResponse from weasyprint import HTML def export_pdf(request): # 1. 渲染HTML模板 context = {'data': '动态数据'} html_string = render_to_string('template.html', context) # 2. 生成PDF pdf = HTML(string=html_string, base_url=request.build_absolute_uri()).write_pdf() # 3. 创建PDF响应 response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="export.pdf"' return response ``` **优点**: - 支持现代CSS3(Flexbox/Grid) - 自动处理分页和布局 - 开源免费(BSD许可证) **安装**: ```bash pip install weasyprint ``` ### 方案二:使用 xhtml2pdf ```python # views.py from django.http import HttpResponse from django.template.loader import get_template from xhtml2pdf import pisa def export_pdf(request): template = get_template('template.html') html = template.render({'data': '动态数据'}) response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="export.pdf"' # 转换HTMLPDF pisa_status = pisa.CreatePDF(html, dest=response) if pisa_status.err: return HttpResponse('PDF生成错误') return response ``` **注意**: - CSS支持有限(推荐使用内联样式) - 需要安装依赖:`pip install xhtml2pdf` ### 方案三:使用 wkhtmltopdf ```python # views.py from django.http import HttpResponse from django.template.loader import get_template import pdfkit def export_pdf(request): template = get_template('template.html') html = template.render({'data': '动态数据'}) options = { 'page-size': 'A4', 'encoding': "UTF-8", } pdf = pdfkit.from_string(html, False, options=options) response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="export.pdf"' return response ``` **安装**: 1. 系统安装wkhtmltopdf: ```bash # Ubuntu sudo apt-get install wkhtmltopdf # MacOS brew install wkhtmltopdf ``` 2. Python封装: ```bash pip install pdfkit ``` --- ### 关键优化技巧 1. **静态资源处理**: ```python # 在设置中指定静态文件URL HTML(string=html, base_url=request.build_absolute_uri('/')) ``` 2. **权限控制**(参考引用[3]): ```python class PDFExportView(DepartmentAccessMixin, View): def get(self, request): # 自动应用部门隔离 # ...生成PDF代码... ``` 3. **大文件优化**: ```python # 使用临时文件避免内存溢出 with tempfile.NamedTemporaryFile(delete=True) as tmp: HTML(string=html).write_pdf(tmp.name) response = FileResponse(open(tmp.name, 'rb')) ``` 4. **自定义响应头**(参考引用[3]): ```python response['Content-Disposition'] = 'inline; filename="preview.pdf"' # 浏览器内预览 ``` --- ### 性能对比表 | 方案 | CSS支持 | 渲染速度 | 内存占用 | 安装复杂度 | |--------------|-------------|----------|----------|------------| | **WeasyPrint** | ★★★★★ | ★★★☆ | ★★☆ | ★★☆ | | **xhtml2pdf** | ★★☆ (PISA) | ★★★★ | ★★★☆ | ★☆ | | **wkhtmltopdf**| ★★★★ | ★★☆ | ★★★★ | ★★★★ (需二进制) | > **推荐选择**:中小型项目选 WeasyPrint,企业级应用选 wkhtmltopdf --- ### 完整工作流程 1. 创建模板文件 `templates/export.html`: ```html <!DOCTYPE html> <html> <head> <style> @page { size: A4; margin: 1cm; } body { font-family: Arial; } </style> </head> <body> <h1>{{ data.title }}</h1> <table>...</table> </body> </html> ``` 2. 配置URL路由: ```python # urls.py from .views import export_pdf urlpatterns = [ path('export-pdf/', export_pdf, name='export_pdf'), ] ``` 3. 前端调用: ```html <a href="{% url 'export_pdf' %}?id=123" class="btn"> 导出PDF </a> ``` --- ### 常见问题解决 **Q:中文乱码怎么办?** A:添加字体配置: ```css @font-face { font-family: "NotoSansSC"; src: url("/static/fonts/NotoSansSC-Regular.otf"); } body { font-family: "NotoSansSC"; } ``` **Q:CSS样式不生效?** A: 1. 使用内联样式:`<p style="color:red">` 2. 在WeasyPrint中启用额外CSS: ```python HTML(string=html).write_pdf(stylesheets=[CSS('static/css/pdf.css')]) ``` **Q:如何添加页眉页脚?** A:使用CSS打印模块: ```css @page { @top-center { content: "公司名称"; } @bottom-right { content: "第 " counter(page) " 页"; } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值