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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:47:08