使用Django与xhtml2pdf生成阿拉伯语PDF遇乱码问题求助
Django + xhtml2pdf 生成阿拉伯语PDF显示黑方块问题解决
问题场景
使用Django结合xhtml2pdf库生成阿拉伯语PDF时,阿拉伯文字符显示为黑方块,已尝试添加字体链接和样式标签但无效。
用户现有代码
views.py
from django.views import View from django.http import HttpResponse from django.template.loader import get_template from io import BytesIO from xhtml2pdf import pisa from .models import أفراد # 假设模型名为أفراد class ViewPDF(View): def get(self, request, *args, **kwargs): name = أفراد.objects.get(رقم_شخصي="100056").الإسم data = {"name": name} pdf = render_to_pdf('pdf_template.html', data) return HttpResponse(pdf, content_type='application/pdf') def render_to_pdf(template_src, context_dict={}): template = get_template(template_src) html = template.render(context_dict) result = BytesIO() pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result) if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') return pdf
模板文件 pdf_template.html
{% load static%} <html dir="rtl"> <pdf:language name="arabic"/> <head> <title>ملف الشخصي</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Naskh+Arabic:400,700" rel="stylesheet"> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <style> @page { size: a4 portrait; @frame header_frame { /* Static Frame */ -pdf-frame-content: header_content; left: 50pt; width: 512pt; top: 50pt; height: 40pt; } @frame content_frame { /* Content Frame */ left: 50pt; width: 512pt; top: 90pt; height: 632pt; } @frame footer_frame { /* Another static Frame */ -pdf-frame-content: footer_content; left: 50pt; width: 512pt; top: 772pt; height: 20pt; } body { direction:rtl; } } </style> </head> <body> <!-- Content for Static Frame 'header_frame' --> <div id="header_content"> <h3>ملف الشخصي</h3> </div> For arabic it's not working <!-- Content for Static Frame 'footer_frame' --> <div id="footer_content">(c) - page <pdf:pagenumber> of <pdf:pagecount> </div> <h3>ملف الشخصي</h3> {{name}} </body> </html>
解决方案
1. 本地嵌入阿拉伯字体
xhtml2pdf对远程字体支持不佳,需下载字体文件到本地项目:
- 下载Noto Naskh Arabic字体文件(Regular和Bold版本),放到项目
static/fonts/目录下 - 在模板CSS中通过
@font-face引入本地字体:
@font-face { font-family: 'NotoNaskhArabic'; src: url('{% static "fonts/NotoNaskhArabic-Regular.ttf" %}') format('truetype'); font-weight: normal; } @font-face { font-family: 'NotoNaskhArabic'; src: url('{% static "fonts/NotoNaskhArabic-Bold.ttf" %}') format('truetype'); font-weight: bold; } body, h3, div { font-family: 'NotoNaskhArabic', sans-serif; direction: rtl; }
2. 修正CSS作用域
将body样式从@page块中移出,@page仅用于页面框架布局,元素样式需写在全局style区域。
3. 完善HTML语言设置
在html标签添加lang="ar"属性,确保语言标识正确:
<html dir="rtl" lang="ar">
4. 优化xhtml2pdf渲染参数
在render_to_pdf函数中添加编码配置和静态资源回调,确保本地字体被正确加载:
import os from django.conf import settings def link_callback(uri, rel): # 处理静态资源路径 if uri.startswith(settings.STATIC_URL): path = os.path.join(settings.STATIC_ROOT, uri.replace(settings.STATIC_URL, "")) elif uri.startswith(settings.MEDIA_URL): path = os.path.join(settings.MEDIA_ROOT, uri.replace(settings.MEDIA_URL, "")) else: path = uri return path def render_to_pdf(template_src, context_dict={}): template = get_template(template_src) html = template.render(context_dict) result = BytesIO() pdf = pisa.pisaDocument( BytesIO(html.encode("UTF-8")), result, encoding='UTF-8', link_callback=link_callback ) if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') return HttpResponse("PDF生成失败", status=500)
5. 验证字体嵌入
生成PDF后,查看文档属性中的字体列表,确认Noto Naskh Arabic已被成功嵌入,若未嵌入则检查字体路径是否正确。
内容的提问来源于stack exchange,提问作者mohamed mzoughi
相关产品推荐
相关产品推荐

