参考文章: Chrome 103支持使用本地字体,纯前端导出PDF优化
@react-pdf/renderer动态创建pfd,使用中文时候,需要自己注册中文字体,否则会显示乱码。中文字体文件通常较大,生成pdf时加载速度慢,严重影响用户体验。尝试过预加载字体文件等方法,效果不理想。由于pdf内容是动态变化的,不是固定模版,压缩字体文件方式也不适用,也不想后台生成。所以想到了尝试使用本地字体的方案。
注意此方案目前只适用于Chrome浏览器,其他浏览器未进行过尝试。 chrome浏览器允许访问本地字体,但是需要用户授权,queryPermission方法用来查询用户是否已经授权使用本地字体。
const queryPermission = async () => {
/**
* "local-fonts" 不符合 TypeScript 中 PermissionName 类型的定义
*/
const permission: PermissionName = 'local-fonts' as unknown as PermissionName;
const { state } = await navigator.permissions.query({
name: permission,
});
return state;
};
返回值 state 为“granted“时代表已授权,其他状态需要在chrome浏览器“网站设置-》权限”标签找到字体权限,授权允许。
在授权后queryLocalFonts方法代码可以查询所有可用本地字体。
const queryLocalFonts = async () => {
if ('queryLocalFonts' in window) {
try {
const availableFonts = await (window as any).queryLocalFonts();
if (!availableFonts.length) {
return [];
}
return availableFonts;
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject('浏览器版本太低 or 网站不安全');
}
};
查询到的availableFonts数组每个元素都是一个FontData数据,
const url = URL.createObjectURL(
new Blob([await fontData.blob()], { type: 'application/octet-stream' }),
);
通过此方法创建本地字体文件访问的url。通过@react-pdf/renderer中的Font.register注册字体
Font.register({
family: '想要使用的字体名',
fonts:[
{
src: 上一步生成的url,
fontWeight: xxx,
}
]
});
完成以上过程,生成pdf时,基本可以使用本地字体了。
如有更好方案,欢迎讨论。