中文字体的FontMetrics解析
中文字体的FontMetrics解析
因行业对字体大小要求严格参考相关规范,因此对通过渲染引擎绘制的文本字体把控严格。
而在Skia/openGL/Qt等主流渲染引擎中,所有设置字体大小(FontSize),都是以英文字体大小作为标准的,准确来说,对应的应该是FontMetrics中的CapHeight作为英文字体高度。
笔者发现在网络上相关资料中,很少有关于中文字符的FontMetrics解析。通过多日研究后,在此详细解析一下中文字体的FontMetrics。
一、FontMetrics标准解析
研究发现,基本所有的渲染引擎都采用以下的字体绘制结构,以下简称标准
这里各个属性都已经描述的很清楚了,网络上其余各个版本的,都不太正确。
为了对比,我使用Skia渲染引擎绘制了同样的文字来做对比,效果如下:
实际上实测的效果还是与网上流传的示意图有一定差异的。
1、大部分字体,字符的顶部触碰不到AscentLine。AscentLine用于带上标的字符、拉丁文字符等
2、对于输入的字符不同,计算的Top、Bottom位置并非不变的。(例如斜体单个字符h的Top、Bottom就要比非斜体jEh要窄些)
大体上都参考标准,研究得出几条结论:
1、英文正常高度为Baseline到CapHeight线
2、最低位置到Descent线处
3、带上标的字符最高到Ascent线处
4、斜体并不改变字体高度
二、中文字符的FontMetrics
绘制引擎就是按照英文字符构造来设计的几条线,压根没考虑中文字符的感受。
假设设置字体高度为100像素,绘制出来的英文字体为100个像素,对于中文来说,往往是会放大。所有的字体的中文的字符都不会在CapHeight内
以宋体和等线体为例:
注:与上图英文字符的绘制线一样,绿色的Ascent与Descent和Top与Bottom几条线重合了,因此绿色看不出来是绿色了。
可以清楚的看到,无论哪种字体,中文字符都不在CapHeight和BaseLine之间。而且并不与任一条线接触。
理论上来说,我们需要将中文字符的高度改成我们设置的高度,就需要缩放。
公式为:
因此,想要知道需要设置的字体高度,公式为:
其中,中文字符应有高度为100像素,当前设置字体高度为100像素,所以只需要量算出中文字符当前高度,就能计算出这个应设置的字体高度。
但是目测量算的都不准确,应该使用FontMetrics中有的属性来确定真实值。
经过多测量算、推演,得出以下规律:
1、以宋体、仿宋体等为代表的标准中文字体类型:
上下两条紫色线为中文字符上下限高度
中文字符下限为UnderLinePos,上限为 Capheight + DescentLine
是的没有看错,上线是DescentLine(即BaseLine到DescentLine的距离),而不是AscentLine。
实际上AscentLine与Top重合了,是要比DescentLine要大一点
至于为什么是DescentLine实际上我也不明白,但能肯定的是这不是偶然。无论如何缩放这个值始终是能和中文字符上线重合,一定存在规律。
2、以等线体为代表的的中英文字体类型:
这类字体非常奇怪,首先英文字符的下限并没有到Descent,甚至没有到UnderLine,与纯英文字体如Times NewRoman等规律就不同。
中文字符也是不能符合上面宋体的规律。
但经过多次推算(不同尺度下),发现一个规律:
中文字符高度 = CapHeight + UnderLinePos
能得出这个结论我也是比较疑惑的,没有任何API、文献资料能证明这条规律,但事实上它就是如此。
得出中文字符高度后,再带入公式,求出应该设置的FontSize,再设置新FontSize,绘制出来的中文字符,就是我们想要的字体高度了。
至此,中文字符高度的计算工作完毕。
期间使用到的代码:
1.绘制字体基准线代码
paint.setStyle(SkPaint::kStroke_Style);paint.setStrokeWidth(3);paint.setColor(0xffff0000);//红色为fTop\fBottom\BaseLinedouble y = p.y();canvas->drawLine(p.x(), y, p.x() + length, y, paint);y = p.y() - font_m.fTop;canvas->drawLine(p.x(), y, p.x() + length, y, paint);y = p.y() - font_m.fBottom;canvas->drawLine(p.x(), y, p.x() + length, y, paint);paint.setStrokeWidth(0);paint.setColor(0xff00ff00);//绿色为Ascent\Descenty = p.y() - font_m.fAscent;canvas->drawLine(p.x(), y, p.x() + length, y, paint);y = p.y() - font_m.fDescent;canvas->drawLine(p.x(), y, p.x() + length, y, paint);paint.setColor(0xffffff00);//黄色为fCapHeighty = p.y() + font_m.fCapHeight;canvas->drawLine(p.x(), y, p.x() + length, y, paint);paint.setColor(0xffff00ff);//紫色为fUnderlinePosition、宋体、仿宋体等中文字符顶部y = p.y() - font_m.fUnderlinePosition;canvas->drawLine(p.x(), y, p.x() + length, y, paint);y = p.y() + font_m.fCapHeight + std::fabs(font_m.fDescent);canvas->drawLine(p.x(), y, p.x() + length, y, paint);//paint.setColor(0xffffffff);//白色为fStrikeoutPosition//y = p.y() + font_m.fCapHeight + font_m.fDescent;//canvas->drawLine(p.x(), y, p.x() + length, y, paint);
2.判断是否中文类字体(目前只用字体名判断,希望能有其他方法)
bool _isSpecialZhFamily(const dan::SGString& fontName){if(fontName == "宋体" || fontName == "仿宋"){return true;}return false;}
3.按照中文标准高度换算应设置的字体高度
auto text_height = std::fabs(font_m.fCapHeight);//英文标高,所有字体的英文标高都是CapHeightif(this->isFontSizeOnZhChar()) //中标高为准{//对于部分中文字体,需要用其他修正方式text_height = std::fabs(font_m.fCapHeight) + std::fabs(font_m.fUnderlinePosition);if(_isSpecialZhFamily(_paint->font().family())){text_height += std::fabs(font_m.fDescent);}length /= TEXT_LENGTH_RESIZE_CONST;//长度修正,中文标高不需要修正}double scale = font_size / text_height;auto scaled_fontsize = font_size * scale;//缩放后的文本大小skFont.setSize(scaled_fontsize);
中文字体的FontMetrics解析相关推荐
- 10种方法解析LOGO设计中的中文字体设计
10种方法解析LOGO设计中的中文字体设计 1. 连接法--结合字体特征将笔画相连接的形式 2. 简化法--根据字体特点,利用视觉错觉合理地简化字体部分笔画的形式 3. 附加法--在字体外添加配合表现 ...
- 避免css中文字体在浏览器中解析成乱码
许多童鞋在写CSS的时候,设置中文字体常常使用中文字符,例如font-family:"黑体",这样我们在浏览器中看到的是什么样子的呢 ? 如果不想自己写的界面在浏览器字体声明上有异 ...
- html font-family设置无效,css设置中文字体(font-family:黑体)后样式失效问题
做项目时偶遇的一诡异问题,同样的代码,在ff和IE7以上页面显示正常,但IE6无论怎么改都不起作用,本来以为是IE6的某些浮动bug所致,结果弄了很长时间也不行,后来不经意间把原来设定的font-fa ...
- 字蛛(FontSpider,中文字体压缩器)网页自由引入中文字体
之前看过设计师面试一位 Web 前端工程师,其中有一段这样的对话: "如果设计师希望用图片实现某个字体样式,而从技术的角度来说这样不合理,但设计师非常坚持,这时候你怎么办?" &q ...
- 使用 免费可商用的中文字体 解决CentOS Linux下Java生成图片水印中文乱码问题
安装开源可商用的google-noto字体 [root@dev ~]# yum install google-noto-cjk-fonts Loaded plugins: fastestmirror ...
- 在Centos7.X上安装中文字体及相关配置
在Centos7.X上安装中文字体及相关配置 文章目录 在Centos7.X上安装中文字体及相关配置 前言 一.查看系统字体 二.安装字体 三.检测linux上安装的中文字体 四.配置别名 前言 Li ...
- css设置中文字体后样式无效解决方法
CSS编码设置问题: @charset "utf-8" IE6中问题:去掉CSS字体设置样式中的空格和双引号. 只要把 font-family: "黑体"; 改 ...
- linux增加中文字体,宋休
#上传字体文件到/usr/share/fonts/chinese,然后刷新缓存 fc-cache -fv #配置别名 vim /etc/fonts/fonts.conf #查看中文字体列表 fc-li ...
- LVGL学习之路——基于lv_lib_freetype库的TTF字体文件动态加载中文字体(阿里普惠字体)
前言 在学习lvgl中,在英文字体上很多人都用过,但是中文字体往往需要靠取模去实现.那么我就在想,如何像windows那样加载动态的字体呢,这样想做多大字体都行.于是就开始了字体的移植. 什么是t ...
- html font-family设置无效,HTML+CSS入门 CSS设置中文字体(font-family:黑体)后样式失效问题如何解决...
本篇教程介绍了HTML+CSS入门 CSS设置中文字体(font-family:"黑体")后样式失效问题如何解决,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门. ...
最新文章
- centos7 安装mysql php_Centos7安装mysql与php的方法
- Linux服务器上zsh和bash的对比
- eclipse 创建maven web项目
- kafka 基础知识梳理及集群环境部署记录
- boost::hana::flip用法的测试程序
- jquery的2.0.3版本源码系列(2):21行-94行定义了一些变量和函数 jQuery=function(){}
- 为什么需要两个Survivor区?
- (4)FPGA JTAG接口连接(学无止境)
- .NetCore中EFCore的使用整理
- 河池学院计算机宿舍,河池学院宿舍条件,宿舍环境图片(10篇)
- android 快捷方式 未安装该应用程序,android,解决手动创建的桌面快捷方式无法跳转到制定的activity的问题,提示未安装应用程序...
- 传输分析_医院智能物流传输系统运营管理和效益分析
- 一封 Cloud Native 的来信……
- EasyBCD误删win10启动项后的修复方法
- android游戏开发方向初探
- windows使用小技巧 ━━ Windows 10 HEVC扩展要收费怎么办?教你怎么免费下载HEVC扩展
- 数字万用表常用功能使用
- python3 打点计时
- powershell中文乱码解决办法
- ps插件摹客iDoc使用技巧
热门文章
- OpenKM文档管理系统开源源码v6.3.9
- 蓝牙模块配置串口通讯
- 360 os3.0 android7.1,【360 N6 Pro】360OS安卓7.1系统V3.0.087付费纯净版ROOT刷机包
- react 项目使用qrcode.react生成二维码,并提供批量下载
- 制造行业相关名词释义
- 常用视频像素格式 YUV422 YUV420
- day04-商城后台搭建
- DIY_实现光敏电阻传感器简单控制LED
- WIFI计量插座之计量芯片选型
- bartend无法自动打印的问题