我正在使用
dataTables
来呈现游泳队的最佳时间表。适用宇宙中有两个级别的资格时间,我用 unicode 星形符号在表中注释时间。 B 级 为轮廓,A 级 为实线。分别是U+2606
和U+2605
。浏览器视图符合预期:
但是,当我导出为 PDF 时,字形不会呈现。
我读到的内容表明,这是一个问题,因为
Roboto
中的默认字体pdfMake
不支持字形,并且要包含其他字体,我必须编辑vfs_fonts.js
文件并包括我想要包括的字体的 base-64 编码定义。这提出了自己的挑战,因为您需要给定字体的重新分发许可证。我发现很难确认给定的字体是否具有我需要的字形,并且我尝试使用我发现的免费字体产生了奇怪的错误。
$.ajax({
url: '/ttf/FreeSans-LrmZ.ttf' ,
success: function(result) {
window.pdfMake.vfs["FreeSans.ttf"] = btoa(unescape(encodeURIComponent(result))) ;
}
});
....
customize: function (doc) {
pdfMake.fonts = {
Roboto: {
normal: 'Roboto-Regular.ttf',
bold: 'Roboto-Medium.ttf',
italics: 'Roboto-Italic.ttf',
bolditalics: 'Roboto-MediumItalic.ttf'
},
freeSans: {
normal: 'FreeSans.ttf',
}
};
doc.defaultStyle.font = "freeSans";
....
embedded.js:15 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'advanceWidth')
我想我确实有两个问题:1)我如何找到合适的字体来正确呈现我需要的两个unicode字符? 2) 我如何正确合并它,以便解决我的
js
错误并成功导出正确渲染的 PDF?
我参考了以下问题,但无法解决我的问题:
我建议您一次只问一个具体问题。我认为你的两个问题很不同。
话虽如此,以下是一些部分答案:
1) 如何找到合适的字体来正确呈现我需要的两个 unicode 字符?
这是 Stack Overflow 的题外话 - 这不是一个编程问题。
另外,无论如何,我没有一个好的(偏离主题!)的答案给你。我在快速搜索中找到的所有“免费商业用途”可下载字体都不包含
★
和 ☆
符号。
这也包括您在问题中尝试使用的字体。尽管它是“免费”和“arial”,但它仍然具有一组有限的 Unicode 字符、符号和字形。不包括 Unicode Miscellaneous Symbols 块。
您可以使用这个免费供个人使用字体 - 但这显然不适合商业用途。
不过,它确实包括星星:
2)我如何正确合并它,以便解决我的js错误并成功导出正确渲染的PDF?
您问题中的JavaScript代码无法正确处理下载的二进制字体文件数据,导致无效的base-64字符串。
jQuery 没有直接的内置方法来处理二进制文件,尽管您可以在 Stack Overflow 中搜索一些方法。
在这种情况下,我发现使用纯 JavaScript 更简单,而不是 jQuery 的
ajax
。
FleReader.readAsDataUrl
,因为使用这种方法时:
属性包含...文件的数据作为base64编码的字符串。result
这就是我们想要的!
var req = new XMLHttpRequest();
req.open("GET", fontUrl, true);
req.responseType = "blob";
req.onload = function (event) {
const blob = req.response;
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
const base64data = reader.result.replace(/^data:.+;base64,/, '');
}
}
上面的代码基于类似问题的这个答案。
但是,这仍然无法解决 PDF 字体问题,因为(如上所述)您使用的特定字体不包含您需要的字形。
但尽管如此,这里是完整的 DataTables 代码,您可以自己复制并运行。
(这是使用最新版本的 DataTables (2.0.0),带有新引入的
layout
选项。您可能使用的是旧版本,没有该选项 - 但这对于 特定 基础并不重要您面临的 64 个问题可以使用旧的 DataTables dom
选项(如果您愿意)。)
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link href="https://cdn.datatables.net/2.0.5/css/dataTables.dataTables.css" rel="stylesheet">
<link href="https://cdn.datatables.net/buttons/3.0.2/css/buttons.dataTables.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/2.0.5/js/dataTables.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.2/js/dataTables.buttons.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.2/js/buttons.html5.js"></script>
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
</head>
<body>
<div style="margin: 20px;">
<table id="example" class="display dataTable cell-border" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office in Country</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61 ☆</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63 ★</td>
<td>2011/07/25</td>
<td>$170,750</td>
</tr>
<tr>
<td>Ashton Cox</td>
<td>Junior "Technical" Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
</tr>
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
$('#example').DataTable({
layout: {
topStart: {
buttons: [{
extend: 'pdfHtml5',
customize: function ( doc ) {
processDoc( doc );
}
}]
}
}
});
} );
function processDoc( doc ) {
const fontUrl = 'https://static.miraheze.org/argobdpwiki/5/5d/FreeSans-LrmZ.ttf';
var req = new XMLHttpRequest();
req.open("GET", fontUrl, true);
req.responseType = "blob";
req.onload = function (event) {
const blob = req.response;
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
const base64data = reader.result.replace(/^data:.+;base64,/, '');
pdfMake.vfs["FreeSans.ttf"] = base64data;
pdfMake.fonts = {
Roboto: {
normal: 'Roboto-Regular.ttf',
bold: 'Roboto-Medium.ttf',
italics: 'Roboto-Italic.ttf',
bolditalics: 'Roboto-MediumItalic.ttf'
},
FreeSans: {
normal: 'FreeSans.ttf',
bold: 'FreeSans.ttf',
italics: 'FreeSans.ttf',
bolditalics: 'FreeSans.ttf'
}
};
// modify the PDF to use a different default font:
doc.defaultStyle.font = "FreeSans";
}
};
req.send();
}
</script>
</body>
</html>
你可以在上面的代码中看到我使用的URL:
const fontUrl = 'https://static.miraheze.org/argobdpwiki/5/5d/FreeSans-LrmZ.ttf';
如果您找到包含所需字形且具有合适许可证的字体文件,您可以将我的演示 URL 更改为您想要使用的 URL。
(显然,您可以自己托管相关的字体文件 - 它不必是外部 URL,就像我的示例一样。它可以是特定于您的应用程序的 URL。)