跳转至

FreeType相关单位

计算示例

已知:

//已知
int em_size = face->units_per_EM; //2048。一个EM中占有2048个Font Units
int x = p.x();  //1000。p为字形轮廓上的一个点,其x轴的数值是1000,即1000个Font Units
int font_size = 12; //用户设置的字体大小是12pt(磅)
int dpi = 96;  //用户屏幕dpi是96(单位:像素个数/英寸)

那么,p.x是多少像素?

float x_em_ratio = x / em_size; //x占有em的比率
    //1000/2048 = 0.48828125

//转成:点单位大小
float x_point_size = x_em_ratio * font_size; 
    //0.48828125 * 12 = 5.859375

//转成:像素单位
float x_pixel_size = x_point_size * dpi / 72;
    //5.859375 * 96 / 72 = 7.8125
int x_pixel_size_int = FT_CEIL(x_pixel_size); //向上取整
    //8个像素

1英寸=2.54cm

\(1英寸 = 2.54cm\)

常见电脑显示屏大小

显示屏(英寸) 宽度(cm) 高度(cm)
19 41 31
21.5 47 27
23.8 54 30
27 60 34
32 70 40

  1. 电脑显示屏的英寸是指屏幕对角线的长度,而非单指高、宽的长度
  2. 不同的生产商和生产线,显示屏的高宽可能会有所不同
  3. 屏幕的宽高比例也会影响显示屏的大小。例如,16:9比例的显示屏会比4:3比例的显示屏更长而窄

dpi(一英寸的像素个数)

概念

打印工具中的DPI电子产品的屏幕分辨率DPI 是不同的

  1. dpi(dots per inch)原来专门指印刷中的计量单位。表示每英寸能印刷的网点数或线数,用来衡量打印机的打印精度,指输出分辨率
  2. ppi(pixels per inch)指图像分辨率,在图像中,每英寸能显示的像素数目。具体说是电脑操作系统和浏览器中常用的单位,但后来与DPI混用了

因此

  1. 在打印工具中,DPI是指每英寸的点数,指的是设备能够在每英寸的空间中输出或显示多少个点
  2. 在屏幕中,DPI是指每英寸的像素个数

在本文中,讨论的是计算机显示屏上的文字显示,因此全文语义是指“每英寸的像素个数”

例子

【打印机】在打印机中,DPI通常用于描述打印分辨率,表示打印机每英寸可以输出多少点,例如300 DPI表示每英寸可以输出300个点。DPI值越高,打印出来的图像质量就越好,但印刷成本也会相应提高

【图像】在图像设计中,DPI值通常用于指定输出图像的分辨率,以确保图像在打印或屏幕上的显示效果。例如,要输出一个300 DPI的打印图像,它的分辨率应该是至少300像素/英寸。

【屏幕】

  1. 如果单谈一个屏幕分辨率是1920x1080,其实我们是不知道它的长宽的,因为1920是指在水平方向上可以显示1920个像素,在垂直方向上显示1080个像素
  2. 但如果再加上DPI=96,我们就能算出长宽了。DPI=96意味着每英寸96个像素。那么,1920/96 = 20英寸,`1080/96 = 11.25英寸

点单位(磅,1/72英寸)

“点”单位,又称“磅”单位,英文point,缩写为ppt

  • “点”是点数制(又称,磅数制)的单位。是印刷行业常用的长度单位之一
  • 1点(即1磅)=1/72英寸=0.3528毫米,1英寸=72磅=25.3毫米,28磅大约为1cm,也就是28号字为1厘米大小
磅数(pt) 实际大小(英寸) 实际大小(厘米) 适用范围
8 0.11 0.28 特殊情况,如文本小标题或标注等
9 0.125 0.32 少量的注释或其他的细节
10 0.138 0.35 较小的文本段落,如注释或脚注等
11 0.153 0.39 大多数文本段落的正文
12 0.167 0.42 书面文档,如论文、报告等
14 0.194 0.49 标题或其他需要强调的文本段落
16 0.222 0.56 特定的设计需求或阅读障碍者需要的字体大小
18 0.25 0.64 海报、宣传册等需要吸引眼球的设计需求

点转成像素

如何将点单位的数值,转成像素单位?

\[ pixel\_size = point\_size * resolution / 72 \]
  1. point_size点大小,如12pt
  2. resolution屏幕分辨率,即屏幕的DPI
  3. pixel_size像素的个数

例如,记point_size = 12ptdpi=96

  1. 1pt = 1/72英寸 => 12pt = 12 / 72英寸 = 0.1667英寸
  2. 96dpi => 一英寸上有96个像素 => 12pt = 0.1667英寸 * 96像素/英寸 = 16个像素
  3. 因此pixel_size = 16个像素

EM(em square)

就像活字印刷术一样,每个字都在一个正方形方框内。在计算机中,也是如此,字体创建者会预先规定的一个正方形,并在这个正方形内设计所有的字符,这个正方形,称为EM正方形。

EM正方形(em sqaure),它是字体创建者所想象出来的虚拟正方形空间,所有字都在这个正方形中进行设计

  1. 通常,EM正方形是宽度是大写字母“M”的宽度
  2. 不同的字体,EM不同,因此EM的宽度也不同

字体大小

在使用Office相关软件时,你需要设置一个字体大小,如

  1. 小五(9pt)
  2. 六号(7.5pt)
  3. 七号(5.5pt)

这里的字体大小,其实就是在指定EM正方形的大小

  1. 小五(9pt) => EM正方形的长度 = 9pt

Font Units

Font Units也是一种单位,它是一种相对于EM长宽的单位

将EM正方形平均分成2048x2048个单元,每个单元就被称为一个“单位”,即一个Font Units(字体单位)

  • 不一定分割成2048,这个值越大,表示每个EM被划分的“单位数”越多,从而可以更精确地表示字形的大小和位置。这个值可以通过FT_FaceRec::units_per_EM查看
  • Font units是字体设计师在设计字形时使用的内部单位,这个单位是用EM正方形划分而来,是相对于EM正方形的单位,因此它没有特定的物理意义,并不能直接对应于显示器上的实际长度(或者像素个数)
  • 在字体文件中,每个字形都会以Font Units来存储它的轮廓信息

units_per_EM

FT_FaceRec::units_per_EM

  • 定义了一个EM所包含的Font units的数量
  • 例如,上面的例子,FT_FaceRec::units_per_EM=2048

转成物理单位

正如上所说,Font Units是一个相对于EM的单位,并不是具体的物理单位。
那么,如何将Font Units转成实际的物理数值呢?

例如,长度为1000Font Unit,是多少pt?是多少像素?

  • 这个和字体大小有关。如果你这时候设置的字体大小是12pt,我们来计算一下
// 已知
int length = 1000;  //1000pt
int font_size = 12; //用户将字体大小设置为12pt(即,一个EM = 12pt)

// 转成点单位
int em_ratio = length / face->units_per_EM; //占EM的比率
int point_size = font_size * em_ratio;      //单位:点大小

// 转成像素单位,需要知道屏幕的dpi
float pixel_size = point_size * dpi / 72;
int pixel_size_int = FT_CEIL(pixel_size); //向上取整

“26.6像素格式的固定点数”转成像素单位

Under FreeType, scaled pixel positions are all expressed in the 26.6 fixed float format (made of a 26-bit integer mantissa, and a 6-bit fractional part). In other words, all coordinates are multiplied by 64. The grid lines along the integer pixel positions, are multiples of 64, like (0,0), (64,0), (0,64), (128,128), etc., while the pixel centers lie at middle coordinates (32 modulo 64) like (32,32), (96,32), etc. ——An introduction to glyphs (fifi.org)

FT_Glyph_Metrics中的成员变量的单位 通常 都是“26.6像素格式的固定点数”,即一个像素的1/64

要将FT_Glyph_Metrics中的数值转为像素单位,需要用到FreeType库中的宏FT_CEIL()和`FT_ROUND()``。

  1. FT_CEIL()用于向上取整
  2. FT_ROUND()用于四舍五入

这两个宏的参数是一个 26.6像素格式的固定点数

  1. 将这个固定点数除以64(也就是右移6位),可以得到相应的像素值
  2. 然后可以用FT_CEIL()或FT_ROUND()将其转为整数像素值

例如,要将FT_Glyph_Metrics中的width转为整数像素值,可以使用如下代码:

#include <ft2build.h>
#include FT_FREETYPE_H

FT_Library library;
FT_Init_FreeType(&library);

FT_Face face;
FT_New_Face(library, "/path/to/font.ttf", 0, &face);

//获取了字形槽对象
FT_GlyphSlot slot = face->glyph; 

// 获取字形度量信息
FT_Glyph_Metrics metrics = slot->metrics;

// 将width转为像素单位
int width_pixels = FT_CEIL(metrics.width >> 6);

为什么不直接除以64:int width_pixels = metrics.width / 64;

  1. 避免使用浮点数运算,提高计算速度(在计算机内部,右移操作通常比除法运算更快,因为除法需要使用算法来计算商和余数,而右移只需要将数值移动到正确的位置上即可)
  2. FT_CEIL()宏可以将结果向上取整,确保结果总是比除以64后的数值更大,从而避免了取整过程中可能出现的误差