中文字体的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解析相关推荐

  1. 10种方法解析LOGO设计中的中文字体设计

    10种方法解析LOGO设计中的中文字体设计 1. 连接法--结合字体特征将笔画相连接的形式 2. 简化法--根据字体特点,利用视觉错觉合理地简化字体部分笔画的形式 3. 附加法--在字体外添加配合表现 ...

  2. 避免css中文字体在浏览器中解析成乱码

    许多童鞋在写CSS的时候,设置中文字体常常使用中文字符,例如font-family:"黑体",这样我们在浏览器中看到的是什么样子的呢 ? 如果不想自己写的界面在浏览器字体声明上有异 ...

  3. html font-family设置无效,css设置中文字体(font-family:黑体)后样式失效问题

    做项目时偶遇的一诡异问题,同样的代码,在ff和IE7以上页面显示正常,但IE6无论怎么改都不起作用,本来以为是IE6的某些浮动bug所致,结果弄了很长时间也不行,后来不经意间把原来设定的font-fa ...

  4. 字蛛(FontSpider,中文字体压缩器)网页自由引入中文字体

    之前看过设计师面试一位 Web 前端工程师,其中有一段这样的对话: "如果设计师希望用图片实现某个字体样式,而从技术的角度来说这样不合理,但设计师非常坚持,这时候你怎么办?" &q ...

  5. 使用 免费可商用的中文字体 解决CentOS Linux下Java生成图片水印中文乱码问题

    安装开源可商用的google-noto字体 [root@dev ~]# yum install google-noto-cjk-fonts Loaded plugins: fastestmirror ...

  6. 在Centos7.X上安装中文字体及相关配置

    在Centos7.X上安装中文字体及相关配置 文章目录 在Centos7.X上安装中文字体及相关配置 前言 一.查看系统字体 二.安装字体 三.检测linux上安装的中文字体 四.配置别名 前言 Li ...

  7. css设置中文字体后样式无效解决方法

    CSS编码设置问题: @charset "utf-8" IE6中问题:去掉CSS字体设置样式中的空格和双引号. 只要把 font-family: "黑体"; 改 ...

  8. linux增加中文字体,宋休

    #上传字体文件到/usr/share/fonts/chinese,然后刷新缓存 fc-cache -fv #配置别名 vim /etc/fonts/fonts.conf #查看中文字体列表 fc-li ...

  9. LVGL学习之路——基于lv_lib_freetype库的TTF字体文件动态加载中文字体(阿里普惠字体)

    前言   在学习lvgl中,在英文字体上很多人都用过,但是中文字体往往需要靠取模去实现.那么我就在想,如何像windows那样加载动态的字体呢,这样想做多大字体都行.于是就开始了字体的移植. 什么是t ...

  10. html font-family设置无效,HTML+CSS入门 CSS设置中文字体(font-family:黑体)后样式失效问题如何解决...

    本篇教程介绍了HTML+CSS入门 CSS设置中文字体(font-family:"黑体")后样式失效问题如何解决,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门. ...

最新文章

  1. centos7 安装mysql php_Centos7安装mysql与php的方法
  2. Linux服务器上zsh和bash的对比
  3. eclipse 创建maven web项目
  4. kafka 基础知识梳理及集群环境部署记录
  5. boost::hana::flip用法的测试程序
  6. jquery的2.0.3版本源码系列(2):21行-94行定义了一些变量和函数 jQuery=function(){}
  7. 为什么需要两个Survivor区?
  8. (4)FPGA JTAG接口连接(学无止境)
  9. .NetCore中EFCore的使用整理
  10. 河池学院计算机宿舍,河池学院宿舍条件,宿舍环境图片(10篇)
  11. android 快捷方式 未安装该应用程序,android,解决手动创建的桌面快捷方式无法跳转到制定的activity的问题,提示未安装应用程序...
  12. 传输分析_医院智能物流传输系统运营管理和效益分析
  13. 一封 Cloud Native 的来信……
  14. EasyBCD误删win10启动项后的修复方法
  15. android游戏开发方向初探
  16. windows使用小技巧 ━━ Windows 10 HEVC扩展要收费怎么办?教你怎么免费下载HEVC扩展
  17. 数字万用表常用功能使用
  18. python3 打点计时
  19. powershell中文乱码解决办法
  20. ps插件摹客iDoc使用技巧

热门文章

  1. OpenKM文档管理系统开源源码v6.3.9
  2. 蓝牙模块配置串口通讯
  3. 360 os3.0 android7.1,【360 N6 Pro】360OS安卓7.1系统V3.0.087付费纯净版ROOT刷机包
  4. react 项目使用qrcode.react生成二维码,并提供批量下载
  5. 制造行业相关名词释义
  6. 常用视频像素格式 YUV422 YUV420
  7. day04-商城后台搭建
  8. DIY_实现光敏电阻传感器简单控制LED
  9. WIFI计量插座之计量芯片选型
  10. bartend无法自动打印的问题