dompdf字符编码UTF-8

29

我正在尝试创建包含正确字符的 PDF 文件,但是出现了“?”字符。 我创建了一个测试 PHP 文件,在其中尝试找到最佳解决方案。如果在浏览器中打开 HTML 文件,则看起来没问题。

UTF-8 --> UTF-8 : X Ponuka číslo € černý Češký 

但是当我查看这个PDF时,我看到了这个。

UTF-8 --> UTF-8 : X Ponuka ?íslo € ?erný ?ešký 

这是我的全部代码:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>č s š Š</title>
</head>
<body>
<?php 

require_once("dompdf/dompdf_config.inc.php");
$tab = array("UTF-8", "ASCII", "Windows-1250", "ISO-8859-2", "ISO-8859-1", "ISO-8859-6", "CP1256"); 
$chain = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <style></style><title>č s š Š</title></head><body>';
foreach ($tab as $i) 
    { 
        foreach ($tab as $j) 
        { 
            $chain .= "<br> $i --> $j : ".iconv($i, $j, 'X Ponuka číslo € černý Češký <br>'); 
        } 
    } 
$chain .= '<p style="font-family: firefly, verdana, sans-serif;">??????X Ponuka číslo € černý Češký <br></p></body></html>';
echo $chain; 
echo 'X Ponuka číslo € černý Češký <br>'; 

$filename = 'pdf/_1.pdf';
$dompdf = new DOMPDF();
$dompdf->load_html($chain, 'UTF-8');
$dompdf->set_paper('a4', 'portrait'); // change these if you need to
$dompdf->render();
file_put_contents($filename, $dompdf->output());

?> 
</body>
</html>

我做错了什么?我尝试了很多我找到的选项 :( 有任何想法吗?


大多数库不允许您加载与您明确告知库要加载的编码不同的数据。这通常会导致出现问号。所以我真的很想知道,为什么你认为使用DOMPDF会有所不同呢?此外,尝试所有选项可能适用于玩耍,但如果这种玩耍不能快速产生任何结果,您需要找到一种不同的策略来理解发生了什么。 - hakre
我做了几个选项,因为很难找到它的工作原理,字符集ISO-8859-2没有任何有用的信息,我谷歌了很多次,我想要UTF-8,每个字符都没问题! - lostika
1
是的,如果您想支持所有(在计算机系统上)已知的字符,则UTF-8是一个不错的选择。然而,在您上面的代码中,您在同一字符串中进行了多次编码。那样永远不会很好地工作。相反,最好找出您的字符串最初具有哪种编码方式。然后使用特定的编码将其转换为UTF-8。您应该只在此处执行单个重新编码。这个答案对您也可能很有趣:https://dev59.com/zW435IYBdhLWcg3w6EqF#5159071 - hakre
11个回答

54

你应该再次阅读Unicode How-to。主要问题在于你没有指定支持你的字符的字体。看起来你已经阅读了这篇指南,因为你正在使用该文档中的字体示例。然而,这个示例并不适用于任何文档,dompdf默认不包含firefly(一种中文字符字体)或Verdana。

如果您不指定字体,则dompdf会回退到其中一个核心字体(Helvetica、Times Roman、Courier),它们只支持Windows ANSI编码。所以一定要使用支持Unicode编码且具有您需要显示的字符的字体来设置文本样式。

对于dompdf 0.6.0,您可以使用包含的Deja Vu字体。因此以下内容应该有效(只需HTML):

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>
  body { font-family: DejaVu Sans, sans-serif; }
</style>
<title>č s š Š</title>
</head>
<body>
  <p>??????X Ponuka číslo € černý Češký <br></p>
</body>
</html>

版本为0.6.1。<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>并且在CSS和body标签中设置了字体:font-family: Helvetica,"Times New Roman", serif; - andreas-supersmart
1
@andreas-manusm 如果您直接使用该字符,则需要使用DejaVu字体。如果将其编码为&#0128;(Windows ANSI字符位置),内置字体应该能够显示该字符。 - BrianS
感谢您指导我使用DejaVu字体 - 这次我有一个精确的模板来完成。下一个项目的最佳实践是基于DejaVu字体创建模板/设计。 - andreas-supersmart
这在最新的dompdf(v0.7.0-beta2)中运行良好,可从https://github.com/dompdf/dompdf/tags下载。 - Xdg
1
@BrianS 我该如何添加自己的字体? - Alireza A2F
显示剩余3条评论

43

我用以下方法使UTF-8字符生效: 在将HTML传递给DOMpdf之前,请使用以下编码转换:

$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');

在您的css中使用DejaVu字体

*{ font-family: DejaVu Sans; font-size: 12px;}

请确保您在HTML的<head>标签中设置了UTF-8编码

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

现在所有特殊字符都能正常工作 "ľ š č ť ž ý á í é"


对我来说,指定 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 起作用了。 - Raphioly-San

27

只添加

  <style>
    *{ font-family: DejaVu Sans !important;}
  </style>

</head>之前,对我很有效。


将dompdf_config.inc.php文件中的SET def("DOMPDF_ENABLE_HTML5PARSER", false);更改为def("DOMPDF_ENABLE_HTML5PARSER", true);。 - Prasant Kumar

3

Dompdf不支持备用字体,因此如果您的喜爱字体不支持您的字符,您就不能使用它,并且您也不能将另一个字体设置为这些字符的备用字体,例如droid sans fallback

相反,您可以利用正则表达式Unicode脚本范围https://www.regular-expressions.info/unicode.html将那些文本块包装到span中并给它们提供备用字体。

示例:

$body = 'test 简化字 彝語/彝语 test číslo € černý Češký';

$cjk_scripts = 'Bopomofo|Han|Hiragana|Katakana';
$cjk_scripts = preg_replace('/[a-zA-Z_]+/', '\\p{$0}', $cjk_scripts);

// wrap the CJK characters into a span with it's own font
$body = preg_replace("/($cjk_scripts)+/isu", '<span class="cjk">$0</span>', $body);

// a font that supports CJK characters
$cjk_font_path = APP_PATH.'/fonts/DroidSansFallbackFull.ttf';

$html = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style type="text/css">
@font-face {
    font-family: 'DroidSansFallbackFull';
    font-style: normal;
    font-weight: 400;
    src: url('$cjk_font_path') format('truetype');
}
body {
    font-family: DejaVu Sans, sans-serif;;
}
.cjk {
    font-family: DroidSansFallbackFull, sans-serif;
}
</style>
</head>
<body>$body</body>
</html>
HTML;

$dompdf = new \DOMPDF();
$dompdf->set_paper('A4');
$dompdf->load_html($html);
$dompdf->render();

$dompdf->stream('test.pdf', ['Attachment'=>0]);

相关链接: https://github.com/dompdf/dompdf/issues/1508


2

在涉及德语翻译中,例如 ä 和 ü,utf8_decode() 对我非常有帮助。

echo utf8_decode('X Ponuka číslo € černý Češký <br>');

1
有时候中文字符会引起问题。 重要的是要有好的字体。这里是一个可以下载的列表。
我选择了第一个名为“楷体粗体”的字体,下载页面在这里。
然后将其放置在公共文件夹中的托管服务上。我把它放在了…
http://192.168.10.10/fonts/pdf/wts11.ttf

这是我的HTML示例

$html = <<<EOT
<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <style>
    @font-face {
      font-family: chinese;
        src: url('http://192.168.10.10/fonts/pdf/wts11.ttf') format('truetype');
    }
    .chineseLanguage { font-family: chinese; }
      body {font-family: DejaVu Sans, sans-serif;}
   </style>
</head>
<body>
    Chinese
    <div class='chineseLanguage'>
        忠烈祠
        中文 - 这工作<br> 
    </div>
    hello world <br> 
    Russian - русский текст <br>
    Greek - α,β,γ,δ,ε <br>
    chars - !@#$%^&* -=- €   <br><br>
    <br>
    Hebrew (iw)<br><br>
    דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה<br>
    <br>    
</body>
</html>
EOT;

PS. 有一定几率您可能需要这个设置:

ini_set("allow_url_fopen", true);

1

我试过所有提到的答案都没有帮助到我。经过几个小时的挣扎后,我转向使用niklasravnsborg/laravel-pdf,它几乎具有相同的语法和用法,并且一切都正常工作。


1
如果你不介意只有一个字符集,你可以在 dompdf_font_family_cache.dist.php 中更改每个字符集,就像这样:
<?php
$distFontDir = $rootDir . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR;
return array(
    'sans-serif' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'times' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'times-roman' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'courier' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'helvetica' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'zapfdingbats' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'symbol' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'serif' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'monospace' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'fixed' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'dejavu sans' =>
    array(
        'bold' => $distFontDir . 'DejaVuSans-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSans-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSans-Oblique',
        'normal' => $distFontDir . 'DejaVuSans'
    ),
    'dejavu sans mono' =>
    array(
        'bold' => $distFontDir . 'DejaVuSansMono-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSansMono-BoldOblique',
        'italic' => $distFontDir . 'DejaVuSansMono-Oblique',
        'normal' => $distFontDir . 'DejaVuSansMono'
    ),
    'dejavu serif' =>
    array(
        'bold' => $distFontDir . 'DejaVuSerif-Bold',
        'bold_italic' => $distFontDir . 'DejaVuSerif-BoldItalic',
        'italic' => $distFontDir . 'DejaVuSerif-Italic',
        'normal' => $distFontDir . 'DejaVuSerif'
    )
)
?>

我知道这不是最好的方式,但它可以节省很多时间。


那就是我的问题,我没有正确设置$rootDir!字体无法读取。 - Jan Matousek

0

我曾经遇到过类似的问题,最终使用了tcpdf。希望这对你有所帮助。 http://www.tcpdf.org/
问题出在我使用的字体上。我使用'freeserif'字体后得到了正确的输出结果。我猜想使用dompdf也可能得到相同的输出结果。

$pdf->SetFont('freeserif', '', 12);

这是我使用的样例。 tcpdf utf-8 样例
<?php
header('Content-type: text/html; charset=UTF-8') ;//chrome
require_once('tcpdf_include.php');

// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

$pdf->setFontSubsetting(true);

$pdf->SetFont('freeserif', '', 12);

$pdf->AddPage();

$utf8text = '
<html><head>  
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body>
<b>Ponuka číslo € černý Češký </b></br>
සිංහල  </br>
<u>தேமல </u> </br>
</body></html>';

$pdf->SetTextColor(0, 63, 127);

$pdf->writeHTML($utf8text, true, 0, true, true);

$pdf->Output('example_008.pdf', 'I');

?>

0

这里有很多答案,但很难找到一个能够可靠地提供跨语言支持的。我相信对于我们制作分布式软件的人来说,还有一些服务器设置块会阻止某些功能(例如@importsrc:url())在pdfdom中自动工作以嵌入字体。

以下解决方案已经在许多服务器和本地托管站点上运行,并且不需要命令行访问:

  1. 获取您要使用的字体作为.ttf文件(为了支持包括西里尔文、希腊文、天城文、拉丁文和越南文在内的语言,我们使用了Noto Sans并勾选了所有可选语言)
  2. 运行/内置以下脚本并仅执行一次PDFBuilder_install_font_family()(单个安装)

PDFBuilder_install_font_family()的Gist:https://gist.github.com/woodyhayday/f8dc36cc7ec922bc1894f33eb2b0e928


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接