MathJax + mPDF SVG 方程不可见
MathJax + mPDF SVG Equations not visible
我在使用 mPDF 将 MathJax SVG 转换为 PDF 时遇到问题。
HTML 只是 mPDF 示例中的一个简单公式:
\[ \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \]
应呈现为:
当然,在最终的 PDF 文件中什么也没有。
HTML 由 POST 发送到 PHP 文件
$path = (getenv('MPDF_ROOT')) ? getenv('MPDF_ROOT') : __DIR__;
require_once $path . '/vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf(['debug' => false, 'allow_output_buffering' => true]);
$sizeConverter = new \Mpdf\SizeConverter($mpdf->dpi, $mpdf->default_font_size);
if (strpos($_REQUEST['bodydata'], 'id%3D%22MathJax_SVG_Hidden%22') === false) {
die('Hacking attempt');
}
$html = $_POST['bodydata'];
$html = urldecode($html);
preg_match('/<svg[^>]*>\s*(<defs.*?>.*?<\/defs>)\s*<\/svg>/', $html, $m);
$defs = $m[1];
$html = preg_replace('/<svg[^>]*>\s*<defs.*?<\/defs>\s*<\/svg>/', '', $html);
$html = preg_replace('/(<svg[^>]*>)/', "\1" . $defs, $html);
preg_match_all('/<svg([^>]*)style="(.*?)"/', $html, $m);
for ($i = 0; $i < count($m[0]); $i++) {
$style = $m[2][$i];
preg_match('/width: (.*?);/', $style, $wr);
$w = $sizeConverter->convert($wr[1], 0, $mpdf->FontSize) * $mpdf->dpi / 25.4;
preg_match('/height: (.*?);/', $style, $hr);
$h = $sizeConverter->convert($hr[1], 0, $mpdf->FontSize) * $mpdf->dpi / 25.4;
$replace = '<svg' . $m[1][$i] . ' width="' . $w . '" height="' . $h . '" style="' . $m[2][$i] . '"';
$html = str_replace($m[0][$i], $replace, $html);
}
if ($_POST['PDF'] === 'PDF') {
$stylesheet = '
img {
vertical-align: middle;
}
.MathJax_SVG_Display {
padding: 1em 0;
}
#mpdf-create {
display: none;
}
';
$mpdf->WriteHTML($stylesheet, 1);
$mpdf->WriteHTML($html);
$mpdf->Output();
}
exit;
它是 official mPDF example 的副本,非常有问题,在 POST 请求 JS 将 'width' 和 'height' 属性复制到 'styles' 属性之前,mPDF 可以正确阅读它。
生成的 SVG:
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="35.62ex" height="7.841ex" style="vertical-align: -3.082ex; width: 35.62ex; height: 7.841ex;" viewBox="0 -2049.4 15336.2 3376.2"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-61" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="748" y="-213"></use></g><g transform="translate(2609,0)"><use xlink:href="#MJMATHI-62" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="607" y="-213"></use></g></g><use xlink:href="#MJSZ4-29" x="4300" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="7202" y="2090"></use><use xlink:href="#MJMAIN-2264" x="5824" y="0"></use><g transform="translate(6880,0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-61" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="748" y="488"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="748" y="-463"></use></g></g><use xlink:href="#MJSZ4-29" x="3401" y="0"></use></g><g transform="translate(11241,0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-62" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="607" y="488"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="607" y="-463"></use></g></g><use xlink:href="#MJSZ4-29" x="3301" y="0"></use></g></g></svg>
当然还有警告:
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: x in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: y in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: w in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: h in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Warning: Division by zero in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Tag.php on line 4015
读取 viewBox 数据可能会出错,但即使使用严格的值,PDF 文件似乎也是空的。没有错误,只是忽略 SVG。从昨天开始我就一直坐着这个,我仍然在同一个地方。 MathJax 必须在这里。我正在考虑将 mPDF 更改为其他内容,但我宁愿避免使用它。
没有想法,我卡住了。
最新 MathJax /
mPDF v7.0.0 /
PHP: 7.1.1 /
PHP GD2 扩展已启用
所以,我想通了。如果有人正在寻找答案(我们现在正在谈论 mPDF MathJaxProcess.php 文件)
- SVG 中该死的 fill="currentColor" 属性在 mPDF 中不起作用。
示例完全损坏。
- 首先要避免 mPDF sizeConverter 中出现 NULL 错误和警告,您必须将 width 和 height 属性复制到内联 SVG 样式。在使用 html 发送表单之前,我是使用 JS 完成的。这实际上是示例中的错误而不是 lib 错误。
- 其次,第29行,$m[1][$i]破坏了一切。变量有它自己的 width 和 height 属性,未转换的值使用 ex 单位。这会与我们自己的 width 和 height 属性发生冲突,然后会出现 Undefined Index 和 出现被零除。
修复上述问题后,mPDF 应该可以正确地与 MathJax 一起使用。我还在发送表单之前清理 SVG。通过消毒我的意思是:
- 将样式属性复制到内联样式
- 删除可聚焦、aria-hidden、角色等属性。 (非数值)
- 将 g 标签的填充属性设置为 #000
- 删除 .MJX_Assistive_MathML class 元素以避免重复内容。
相当混乱的 JS 代码,但你会明白的。
我们将跳过循环中的第一个 SVG,那是因为它只有将直接复制到 PHP 脚本中的 SVG 标记中的定义。
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG">
MathJax.Hub.Register.StartupHook("End",function () {
var list = document.getElementsByTagName("svg");
for (var i = 1; i < list.length; i++) {
var w = list[i].getAttribute("width");
var h = list[i].getAttribute("height");
list[i].style.width = w;
list[i].style.height = h;
list[i].removeAttribute("focusable");
list[i].removeAttribute("aria-hidden");
list[i].removeAttribute("role");
}
var gList = document.getElementsByTagName("g");
for (var i = 0; i < gList.length; i++) {
gList[i].setAttribute("fill", "#000");
}
document.querySelectorAll(".MJX_Assistive_MathML").forEach(function(a){
a.remove()
});
document.getElementById("bodydata").value=encodeURIComponent(document.body.innerHTML);
var el = document.getElementById("pdfform");
el.submit();
});
</script>
编辑:
如果你在 chrome 或 firefox 中有损坏的 svg:
从 Firefox mPDF 呈现时需要参数 viewbox
从 Chrome mPDF 渲染时需要参数 viewBox
它区分大小写。我从一个星期开始就在寻找这个错误。
我在使用 mPDF 将 MathJax SVG 转换为 PDF 时遇到问题。
HTML 只是 mPDF 示例中的一个简单公式:
\[ \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \]
应呈现为:
当然,在最终的 PDF 文件中什么也没有。
HTML 由 POST 发送到 PHP 文件
$path = (getenv('MPDF_ROOT')) ? getenv('MPDF_ROOT') : __DIR__;
require_once $path . '/vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf(['debug' => false, 'allow_output_buffering' => true]);
$sizeConverter = new \Mpdf\SizeConverter($mpdf->dpi, $mpdf->default_font_size);
if (strpos($_REQUEST['bodydata'], 'id%3D%22MathJax_SVG_Hidden%22') === false) {
die('Hacking attempt');
}
$html = $_POST['bodydata'];
$html = urldecode($html);
preg_match('/<svg[^>]*>\s*(<defs.*?>.*?<\/defs>)\s*<\/svg>/', $html, $m);
$defs = $m[1];
$html = preg_replace('/<svg[^>]*>\s*<defs.*?<\/defs>\s*<\/svg>/', '', $html);
$html = preg_replace('/(<svg[^>]*>)/', "\1" . $defs, $html);
preg_match_all('/<svg([^>]*)style="(.*?)"/', $html, $m);
for ($i = 0; $i < count($m[0]); $i++) {
$style = $m[2][$i];
preg_match('/width: (.*?);/', $style, $wr);
$w = $sizeConverter->convert($wr[1], 0, $mpdf->FontSize) * $mpdf->dpi / 25.4;
preg_match('/height: (.*?);/', $style, $hr);
$h = $sizeConverter->convert($hr[1], 0, $mpdf->FontSize) * $mpdf->dpi / 25.4;
$replace = '<svg' . $m[1][$i] . ' width="' . $w . '" height="' . $h . '" style="' . $m[2][$i] . '"';
$html = str_replace($m[0][$i], $replace, $html);
}
if ($_POST['PDF'] === 'PDF') {
$stylesheet = '
img {
vertical-align: middle;
}
.MathJax_SVG_Display {
padding: 1em 0;
}
#mpdf-create {
display: none;
}
';
$mpdf->WriteHTML($stylesheet, 1);
$mpdf->WriteHTML($html);
$mpdf->Output();
}
exit;
它是 official mPDF example 的副本,非常有问题,在 POST 请求 JS 将 'width' 和 'height' 属性复制到 'styles' 属性之前,mPDF 可以正确阅读它。
生成的 SVG:
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="35.62ex" height="7.841ex" style="vertical-align: -3.082ex; width: 35.62ex; height: 7.841ex;" viewBox="0 -2049.4 15336.2 3376.2"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-61" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="748" y="-213"></use></g><g transform="translate(2609,0)"><use xlink:href="#MJMATHI-62" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="607" y="-213"></use></g></g><use xlink:href="#MJSZ4-29" x="4300" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="7202" y="2090"></use><use xlink:href="#MJMAIN-2264" x="5824" y="0"></use><g transform="translate(6880,0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-61" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="748" y="488"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="748" y="-463"></use></g></g><use xlink:href="#MJSZ4-29" x="3401" y="0"></use></g><g transform="translate(11241,0)"><use xlink:href="#MJSZ4-28"></use><g transform="translate(792,0)"><use xlink:href="#MJSZ2-2211" x="0" y="0"></use><g transform="translate(85,-1110)"><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-3D" x="521" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-31" x="1300" y="0"></use></g><use transform="scale(0.707)" xlink:href="#MJMATHI-6E" x="721" y="1627"></use><g transform="translate(1611,0)"><use xlink:href="#MJMATHI-62" x="0" y="0"></use><use transform="scale(0.707)" xlink:href="#MJMAIN-32" x="607" y="488"></use><use transform="scale(0.707)" xlink:href="#MJMATHI-6B" x="607" y="-463"></use></g></g><use xlink:href="#MJSZ4-29" x="3301" y="0"></use></g></g></svg>
当然还有警告:
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: x in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: y in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: w in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Notice: Undefined index: h in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Image\Svg.php on line 3027
[29-Dec-2017 21:42:39 UTC] PHP Warning: Division by zero in D:\Praca\ENVIROMENTS\laragon-apache\laragon\www\wp-content\plugins\szalpdf\pdf\vendor\mpdf\mpdf\src\Tag.php on line 4015
读取 viewBox 数据可能会出错,但即使使用严格的值,PDF 文件似乎也是空的。没有错误,只是忽略 SVG。从昨天开始我就一直坐着这个,我仍然在同一个地方。 MathJax 必须在这里。我正在考虑将 mPDF 更改为其他内容,但我宁愿避免使用它。
没有想法,我卡住了。
最新 MathJax / mPDF v7.0.0 / PHP: 7.1.1 / PHP GD2 扩展已启用
所以,我想通了。如果有人正在寻找答案(我们现在正在谈论 mPDF MathJaxProcess.php 文件)
- SVG 中该死的 fill="currentColor" 属性在 mPDF 中不起作用。
示例完全损坏。
- 首先要避免 mPDF sizeConverter 中出现 NULL 错误和警告,您必须将 width 和 height 属性复制到内联 SVG 样式。在使用 html 发送表单之前,我是使用 JS 完成的。这实际上是示例中的错误而不是 lib 错误。
- 其次,第29行,$m[1][$i]破坏了一切。变量有它自己的 width 和 height 属性,未转换的值使用 ex 单位。这会与我们自己的 width 和 height 属性发生冲突,然后会出现 Undefined Index 和 出现被零除。
修复上述问题后,mPDF 应该可以正确地与 MathJax 一起使用。我还在发送表单之前清理 SVG。通过消毒我的意思是:
- 将样式属性复制到内联样式
- 删除可聚焦、aria-hidden、角色等属性。 (非数值)
- 将 g 标签的填充属性设置为 #000
- 删除 .MJX_Assistive_MathML class 元素以避免重复内容。
相当混乱的 JS 代码,但你会明白的。
我们将跳过循环中的第一个 SVG,那是因为它只有将直接复制到 PHP 脚本中的 SVG 标记中的定义。
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG">
MathJax.Hub.Register.StartupHook("End",function () {
var list = document.getElementsByTagName("svg");
for (var i = 1; i < list.length; i++) {
var w = list[i].getAttribute("width");
var h = list[i].getAttribute("height");
list[i].style.width = w;
list[i].style.height = h;
list[i].removeAttribute("focusable");
list[i].removeAttribute("aria-hidden");
list[i].removeAttribute("role");
}
var gList = document.getElementsByTagName("g");
for (var i = 0; i < gList.length; i++) {
gList[i].setAttribute("fill", "#000");
}
document.querySelectorAll(".MJX_Assistive_MathML").forEach(function(a){
a.remove()
});
document.getElementById("bodydata").value=encodeURIComponent(document.body.innerHTML);
var el = document.getElementById("pdfform");
el.submit();
});
</script>
编辑: 如果你在 chrome 或 firefox 中有损坏的 svg: 从 Firefox mPDF 呈现时需要参数 viewbox 从 Chrome mPDF 渲染时需要参数 viewBox 它区分大小写。我从一个星期开始就在寻找这个错误。