ITEXT7 字体处理

  • 前言
  • 一、如何添加itext7 没有的字体?
  • 二、部分字体添加无效
  • 三、源码分析
  • 总结

前言

本文主要是用于解决itext7 添加字体时遇到的问题分析及解决方案。


一、如何添加itext7 没有的字体?

itext pdf 提供了多种对字体的添加,例如:

FontProvider fp = new FontProvider();
// 该方法为通过添加font的路径的方式让FontProvider对象自行加载字体列表
fp.addDirectory(prePath + "config\\fonts");
// 该方法的优点是便捷,缺点是对于字体的同族支持效果较差容易出现无效果
FontProvider fp = new FontProvider();
// 该方法类似于上面,可以根据设置的路径加载单个字体
fp.addFont(fontPath);
// fp里面的其他方法基本与addFont相同所添加的字体属性基本一致
FontProvider fp = new FontProvider();
// 该方法与第二种不同的在于可以设置alias
fp.getFontSet().addFont(prePath + "config\\fonts\\Times New Roman.ttf", null, "timesnewromanpsmt");

二、部分字体添加无效

添加字体的方法根据itext7的源码是有很多种的,但是有时候对于一些字体却没有效果,被设置成默认字体Helvetica。这时候可能是有多种情况

  1. 需要确认字体有没有在字体库里?
    没有的需要在网上检索对应字体,比如 宋体加粗下载、黑体加粗下载等等
  2. 需要确认字体是否为 ttf 格式?
    对于网上流传的字体,实际上格式是多种多样的,目前itext7支持 ttf 格式的字体,若是只有ttc格式的需要在网上检索字体转换进行处理。
  3. 需要确认字体名字是否为“英文”?
    对于中文和英文各类字体,实际上在字体使用的时候,需要根据字体信息再专门进行配置。对于该信息的查询可以查看FontProgramDescriptor.fontName,该属性即为该字体真正的名称。 该类在FontInfo字体里面,可以在addFont后,通过debug或序列化打印出来
  4. html2pdf 的时候字体无效
    该问题分为两种情况:一种是第三点描述的内容;另一种是 对于html文件 通常是由office软件另存得到的,再生成的html文件里会蕴含多种对字体样式的描述标签“font-family”、“mso-ascii-font-family”、“mso-fareast-font-family”等。对于html有用的类型为“font-family”,但是其他两种的字体由于某些操作下会与其不一致且office识别的是另外两种,所以造成字体在office里是正常的,但是html就变掉了。这种情况需要编写程序对整个文档进行梳理,自动使得三种字体一致(把“mso-ascii-font-family”的值设置到“font-family”上)。

三、源码分析

对于itext7来说,它是这样判断和选择字体的:

//该行为html文本转换为itext的对象代码
List<IElement> iElements = HtmlConverter.convertToElements(html, props);
//我们从对象iElements里面可以找到Text文本对象,该对象的properties里存放解析出来的改文本配置信息,
//比如 20-> 字体名称  95 ->加粗|正常  94-> 斜体 等信息,当我们发现一段文本字体显示异常,
//可以查看是否有20码,没有说明字体没有被正确识别,需要修改文本里的字体名称


然后我们再来看下在解析完成html后,如何加载字体信息

这里我们可以看到,它从Text文本里提取字体名称,然后在同个文件里的2461行,设置是否加粗、加斜

    FontCharacteristics createFontCharacteristics() {FontCharacteristics fc = new FontCharacteristics();//粗if (this.hasProperty(Property.FONT_WEIGHT)) {fc.setFontWeight((String) this.<Object>getProperty(Property.FONT_WEIGHT));}// 斜if (this.hasProperty(Property.FONT_STYLE)) {fc.setFontStyle((String) this.<Object>getProperty(Property.FONT_STYLE));}return fc;}

这里是为了构建字体选择器,用于下一步获取字体内容

    public FontSelector(Collection<FontInfo> allFonts, List<String> fontFamilies, FontCharacteristics fc) {this.fonts = new ArrayList<>(allFonts);//Possible issue in .NET, virtual protected member in constructor.Collections.sort(this.fonts, getComparator(fontFamilies, fc));}

在实例化FontSelector对象的时候,会对目前加载的所有字体进行排序,该排序是通过计算所有的字体与当前字体的信息吻合度,谁吻合度最高,谁排第一个。便于下一步的字体对象获取。

if (!fontFamilySetByCharacteristics) {// if alias is set, fontInfo's descriptor should not be checkedif (!"".equals(fontFamily)&& (null == fontInfo.getAlias()&& null != fontDescriptor.getFamilyNameLowerCase()&& fontDescriptor.getFamilyNameLowerCase().equals(fontFamily)|| (null != fontInfo.getAlias() && fontInfo.getAlias().toLowerCase().equals(fontFamily)))) {score += FONT_FAMILY_EQUALS_AWARD;} else {if (!isLastFontFamilyToBeProcessed) {return score;}}}

在FontSelector类201行可以看到排序时,会判断字体名称,要是字体名称一样就加分。在字体名称不一样的情况下字体alias名一样也可以加分。 所以我们上面在添加字体的时候,设置字体别名就是为了让字体族(粗、斜和粗斜)可以加分,排到前面(第一)。
该判断下面是判断当前字体是否加粗 加斜,吻合也加分从而让最一致的字体项得分最高。

可以看到,这边是根据排序后的字体列表进行循环的。由于文字在字体里面基本都是存在的,所以排在第一个的几乎就会被设置为当前字体。这里之所以说几乎,是因为对于外国字体,他是没有汉字的,所以单出现汉字被设置为外国字体或开始的时候没识别到字体时(默认字体不支持中文),这边就会根据排序依次往下判断哪个比较吻合(粗、斜和粗斜)且包含中文的,找到一个替代字体进行显示。在图片中也可以看到itext对于字体是按字提取,需要哪个提取哪个,不是全部都提取,保障了生成的pdf不会太大。


总结

通过上述内容,应该是可以比较清楚的了解了itext7是如何获取对应字体和如何设置代替字体的。有问题欢迎交流~

itext7 字体问题解答与相应源代码分析相关推荐

  1. Media Player Classic - HC 源代码分析 6:MediaInfo选项卡 (CPPageFileMediaInfo)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  2. LAV Filter 源代码分析 1: 总体结构

    LAV Filter 是一款视频分离和解码软件,他的分离器封装了FFMPEG中的libavformat,解码器则封装了FFMPEG中的libavcodec.它支持十分广泛的视音频格式. 源代码位于Gi ...

  3. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  4. 《LINUX3.0内核源代码分析》第一章:内存寻址

    https://blog.csdn.net/ekenlinbing/article/details/7613334 摘要:本章主要介绍了LINUX3.0内存寻址方面的内容,重点对follow_page ...

  5. Scrapy源代码分析-经常使用的爬虫类-CrawlSpider(三)

    CrawlSpider classscrapy.contrib.spiders.CrawlSpider 爬取一般站点经常使用的spider.其定义了一些规则(rule)来提供跟进link的方便的机制. ...

  6. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  7. Android应用程序进程启动过程的源代码分析(1)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  8. AFNetworking 源代码分析

    关于其他 AFNetworking 源代码分析的其他文章: AFNetworking 概述(一) AFNetworking 的核心 AFURLSessionManager(二) 处理请求和响应 AFU ...

  9. Hadoop源代码分析 - MapReduce(转载)

    1. Hadoop源代码分析(MapReduce概论) http://caibinbupt.javaeye.com/blog/336467

最新文章

  1. 为什么我们使用Nginx而不是Apache?
  2. 知识图谱 ppt_PPT|知识图谱的关键技术及其智能应用
  3. 金蝶mysql_金蝶财务软件中的数据库如何进入?
  4. web前端开发最佳实践--(笔记之JavaScript最佳实践)
  5. 给matrix重新列名_如何认真升级Mac终端(甚至给它一个Matrix主题)
  6. Linux 进程间通信(IPC)---大总结
  7. php 时间段 mysql 存储_php – 在MySQL解决方案中存储日期范围
  8. win10定时语音提醒
  9. 计算机相关知识——前端Base64编码解码的基础使用
  10. Python货币转换
  11. 【python】启动客户端报错:OSError: [WinError 740] 请求的操作需要提升。
  12. Linux 常用命令(后台web开发)
  13. 牛客练习赛50 F.tokitsukaze and Another Protoss and Zerg(分治+NTT)(模板题)
  14. python顺时针旋转_python中的绕点旋转(矩阵)
  15. 使用存储过程返回结果集
  16. 人生感悟哲理的名言句子
  17. mysql安装2503,无法安装msi格式软件提示错误代码2502、2503怎么办?
  18. USB的DCP、CDP、SDP的区别
  19. 华为云服务器重装java环境
  20. vscode 开启大小写区分

热门文章

  1. 【图神经网络】Pytorch图神经网络库——PyG异构图学习
  2. 【2015/4/17】学习servlet笔记1--servlet生命周期函数
  3. 程序员为什么是吃青春饭,而不是像医生律师一样越老越值钱?
  4. linux suds 只能在当前目录,使用Python和suds 0.4的SAXParseException?
  5. 什么是闭包以及闭包有什么作用
  6. 读书笔记 -《Python 黑帽子》 ( 一 )
  7. 七种方案!探讨Redis分布式锁的正确使用姿势
  8. 安装LLVM+Clang教程
  9. Unity 状态机 委托 AI巡逻与追逐 Auto切换
  10. P2P产品 -自动投标业务详解