<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      一文讀懂字體文件

      這篇文章是從0到1自定義富文本渲染的原理篇之一,此外你還可能感興趣:
      更多內容歡迎關注公眾號:非專業程序員Ping

      一、引言

      在開始閱讀本文之前,推薦先閱讀字符(Character)、字形(Glyph)、字體的區別理解基本概念。

      如果你對字符與Unicode的相關概念還不理解,推薦閱讀字符與編碼

      前文,我們介紹了字符(Character)、字形(Glyph)、字體的區別,這里我們再來實際分析一個字體文件中到底有什么,這有利于我們后續理解文字排版引擎的工作原理和流程。

      macOS上系統字體路徑一般為/System/Library/Fonts/,可以看到有文件后綴有ttcttf,二者有什么區別呢?

      1).ttf (TrueType Font)

      ttf表示這是一個單字體文件,每個 .ttf 文件通常只對應一個字體樣式(例如 Microsoft YaHei Regular

      2).ttc (TrueType Collection)

      ttc表示這是一個字體集合文件,內部可以包含多個 TrueType 字體(多個 .ttf 打包在一起),這些字體通常共享某些表(比如 glyph 輪廓、cmap),減少冗余,提高存儲效率,常用于一個 Typeface 的多個變體(Regular, Bold, Italic, Light…)

      上面提到了TrueType,與之對應的還有OpenType,二者其實都是字體類型標準,簡單理解就是OpenType是TrueType的擴展,OpenType支持更多的特性,比如:連字、RTL、上下標等。

      OpenType一般以otf為后綴,但也不能簡單的根據文件名后綴區分二者,文件擴展名只是習慣,并不能完全說明內部格式,真正的區別還是要看字體表結構,比如OpenType有GSUB、GPOS、GDEF等擴展表。

      下面,我們來真正解析一個字體文件,看里面有什么,可以通過如下命令行將字體解析成XML。

      # 對于ttf文件
      ttx NewYork.ttf
      # ttc文件是個字體集合,需要明確指明要提取哪個index的字體
      ttx -y 0 Times.ttc
      

      二、Font文件解析

      我們以NewYork.ttf文件為例,如下是NewYork.ttf中的表

      在這里插入圖片描述

      2.1 GlyphOrder

      <GlyphOrder>
      <GlyphID id="0" name=".notdef"/>
      <GlyphID id="1" name=".null"/>
      <GlyphID id="2" name="nonmarkingreturn"/>
      <GlyphID id="3" name="space"/>
      <GlyphID id="4" name="A"/>
      ...
      </GlyphOrder>
      

      GlyphOrder定義glyphID與glyphName的映射。

      2.2 head

      Font Header,存儲一些全局信息;關注幾個值:

      <head>
      <unitsPerEm value="2048"/>
      ...
      </head>
      

      1)unitsPerEm

      字體表里的數值一般都很大(見后文),其單位并不是像素值,而是 em unit<unitsPerEm value="2048"/>表示2048 units = 1 em = 設計的字高,比如當字體在屏幕上以 16px 渲染時,1 em = 16px,其他數值可按比例換算

      2.3 hhea

      Horizontal Typesetting Header,橫向排版信息,關注幾個值

      <hhea>
      <!-- MacOS一般使用hhea里的ascent、descent;OS_2表里還有幾個ascent、descent,一般在Windows或專業設計上使用 -->
      <ascent value="1950"/>
      <descent value="-494"/>
      <lineGap value="0"/>
      <advanceWidthMax value="2818"/>
      <minLeftSideBearing value="-693"/>
      <minRightSideBearing value="-693"/>
      ...
      </hhea>
      

      1)ascent & descent

      假設字體大小16,unitsPerEm如上為2048,則按比例換算:ascent = 1950/2048 * 16 ≈ 15.2descent ≈ 494/2048 * 16 ≈ 3.8

      需要注意,OS_2表中也有ascent、descent的定義,這是因為不同平臺會讀取不同表中的ascent、descent,比如macOS、iOS一般使用hhea中的值,Windows一般使用OS_2表中的usWinAscent、usWinDescent,專業排版軟件(如InDesign)一般用OS_2表中的sTypoAscender、sTypoDescender。

      Q:對于同一個Font,ascent、descent的值是固定的嗎?

      這個問題的答案需要加定語,對于同一個Font,在同一個平臺上,ascent、descent是固定的。

      Q:為什么descent值是負數?

      可以理解成規范,TrueType/OpenType的規范里,descent是負數,表示基線(baseline)以下延伸的高度。

      2.4 maxp

      <maxp>
      <numGlyphs value="1811"/>
      ...
      </maxp>
      

      定義字體里 glyph 的數量,以及一些最大值參數。

      2.5 OS_2

      <OS_2>
      <!-- 下標的大小和偏移 -->
      <ySubscriptXSize value="650"/>
      <ySubscriptYSize value="600"/>
      <ySubscriptXOffset value="0"/>
      <ySubscriptYOffset value="75"/>
      
      <!-- 上標的大小和偏移 -->
      <ySuperscriptXSize value="650"/>
      <ySuperscriptYSize value="600"/>
      <ySuperscriptXOffset value="0"/>
      <ySuperscriptYOffset value="350"/>
      
      <!-- 刪除線的粗細和垂直位置 -->
      <yStrikeoutSize value="12"/>
      <yStrikeoutPosition value="620"/>
      
      <!--
      ulUnicodeRange表示字體支持的Unicode范圍,用ulUnicodeRange1 … ulUnicodeRange4 這 4 個 32 位字段來表示,總共 128 個 bit,對應 128 個 Unicode Block,如果某 bit = 1,表示字體支持該區塊中的至少一些字符,
      映射表見:https://learn.microsoft.com/en-us/typography/opentype/spec/os2#ur
      -->
      <ulUnicodeRange1 value="10100001 00000000 00000010 11111111"/>
      <ulUnicodeRange2 value="00000010 00000000 00100000 01011110"/>
      <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
      <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
      
      <!-- 專業排版(比如 InDesign)一般使用sTypoAscender、sTypoDescender -->
      <sTypoAscender value="1950"/>
      <sTypoDescender value="-494"/>
      <sTypoLineGap value="0"/>
      
      <!-- Windows一般使用sTypoAscender、sTypoDescender -->
      <usWinAscent value="1950"/>
      <usWinDescent value="494"/>
      ...
      </OS_2>
      

      參見Apple文檔,關注幾個值:

      1)ySubscriptXSize & ySubscriptYSize & ySubscriptXOffset & ySubscriptYOffset

      下標的大小和偏移

      2)ySuperscriptXSize & ySuperscriptYSize & ySuperscriptXOffset & ySuperscriptYOffset

      上標的大小和偏移

      3)yStrikeoutSize & yStrikeoutPosition

      刪除線的粗細和垂直位置

      4)ulUnicodeRange1 & ulUnicodeRange2 & ulUnicodeRange3 & ulUnicodeRange4

      ulUnicodeRange表示該字體支持的Unicode范圍,用ulUnicodeRange1 … ulUnicodeRange4 這 4 個 32 位字段來表示,總共 128 個 bit,對應 128 個 Unicode Block,如果某 bit = 1,表示字體支持該區塊中的至少一些字符,映射表見:https://learn.microsoft.com/en-us/typography/opentype/spec/os2#ur

      Windows系統通常用 ulUnicodeRange 來看一個字體是否支持某Unicode;macOS/iOS系統一般用 cmap 表(精確的字符映射),ulUnicodeRange只作為輔助信息;瀏覽器排版一般直接查 cmap,但 ulUnicodeRange 有時也用于字體 fallback 策略。

      5)sTypoAscender & sTypoDescender & usWinAscent & usWinDescent

      如前文所述,不同系統會取不同的值作為ascent、descent

      2.6 hmtx

      <hmtx>
      <mtx name=".notdef" width="2048" lsb="199"/>
      <mtx name=".null" width="0" lsb="0"/>
      <mtx name="A" width="1244" lsb="-16"/>
      ...
      </hmtx>
      

      Horizontal Metrics,記錄每個 glyph 的 advance width 和left side bearing。

      簡單理解排版引擎繪制字形的流程是:將字形放在當前點 + lsb 偏移位置進行繪制,畫完后,將光標向右移動 advanceWidth,準備繪制下一個字形。

      2.7 cmap

      <cmap>
      <tableVersion version="0"/>
      <cmap_format_4 platformID="0" platEncID="3" language="0">
      <!-- A的Unicode code point是0x41 -->
      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
      <map code="0x47" name="G"/><!-- LATIN CAPITAL LETTER G -->
      <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
      ...
      </cmap_format_4>
      ...
      </cmap>
      

      Character to Glyph Mapping,定義 Unicode code point → glyph ID 的映射,cmap表中能精確的查到該Font支持哪些Unicode。

      2.8 glyf

      <glyf>
      <TTGlyph name="A" xMin="-16" yMin="0" xMax="1260" yMax="1444">
      <contour>
      <pt x="1086" y="213" on="1"/>
      <pt x="1113" y="137" on="0"/>
      <pt x="1161" y="50" on="0"/>
      <pt x="1219" y="9" on="0"/>
      <pt x="1260" y="1" on="1"/>
      <pt x="1260" y="0" on="1"/>
      <pt x="793" y="0" on="1"/>
      <pt x="793" y="1" on="1"/>
      <pt x="845" y="7" on="0"/>
      <pt x="897" y="54" on="0"/>
      <pt x="899" y="143" on="0"/>
      <pt x="874" y="213" on="1"/>
      <pt x="528" y="1200" on="1"/>
      <pt x="528" y="1200" on="1"/>
      <pt x="220" y="292" on="1"/>
      <pt x="184" y="186" on="0"/>
      <pt x="170" y="66" on="0"/>
      <pt x="224" y="11" on="0"/>
      <pt x="290" y="1" on="1"/>
      <pt x="290" y="0" on="1"/>
      <pt x="-16" y="0" on="1"/>
      <pt x="-16" y="1" on="1"/>
      <pt x="27" y="9" on="0"/>
      <pt x="89" y="59" on="0"/>
      <pt x="151" y="181" on="0"/>
      <pt x="193" y="297" on="1"/>
      <pt x="614" y="1444" on="1"/>
      <pt x="648" y="1444" on="1"/>
      </contour>
      <contour>
      <pt x="290" y="532" on="1"/>
      <pt x="294" y="544" on="1"/>
      <pt x="859" y="544" on="1"/>
      <pt x="860" y="532" on="1"/>
      </contour>
      <instructions/>
      </TTGlyph>
      ...
      </glyf>
      

      Glyph Data,真正的字形輪廓(矢量點、輪廓、控制點);cmap 表負責把 Unicode 字符映射到 glyphID,而 glyf 表告訴渲染系統該 glyph 的具體形狀。

      2.9 name

      <name>
      <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
      ? 2017-2024 Apple Inc. All rights reserved.
      </namerecord>
      <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
      .New York
      </namerecord>
      <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
      Regular
      </namerecord>
      <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
      .New York; 20.0d1e1; 2024-05-06
      </namerecord>
      <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
      .New York
      </namerecord>
      <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
      20.0d1e1
      </namerecord>
      <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
      .NewYork-Regular
      </namerecord>
      ...
      </name>
      

      name表中定義的是字體名稱、字體家族、PostScript Name、廠商信息等。

      nameID對應的含義如下:

      nameID 含義
      0 Copyright notice
      1 Font Family name(字體家族名,比如 New York
      2 Font Subfamily name(字重/樣式,比如 RegularBold
      3 Unique font identifier(唯一ID,通常包含廠商名+版本號)
      4 Full font name(family + subfamily,比如 New York Regular
      5 Version string
      6 PostScript name(唯一的、無空格的名字)
      ... ...

      這里需要重點介紹下PostScript Name:PostScript Name是字體在一個系統里的唯一標識,是單個字符串,不允許有空格,一般是 FamilyName-StyleName 形式,比如:.NewYork-RegularHelvetica-BoldNotoSansCJKsc-Regular等。

      在CoreText的API里,一般都要求傳PostScript Name,比如:CTFontCreateWithName

      2.10 GDEF

      Glyph Definition Table,簡單理解GDEF表就是是GPOS / GSUB的輔助表,比如GPOS和 GSUB需要知道「哪些字形是 mark、哪些能連接、哪些有變體」等信息,這些元數據就是放在GDEF 表里的。

      2.11 GPOS

      Glyph Positioning Table,控制字形的相對位置(如kerning、上下標等),比如「A + V」之間要減少間距,或者音標放在元音正上方等。

      2.12 GSUB

      Glyph Substitution Table,控制字形替換(連字、、阿拉伯文變體、直角引號換彎引號等),比如f + i?'quoteleft'等。

      2.13 HVAR & MVAR & avar & fvar & gvar...

      這幾個表是用于轉換可變字體的,可變字體不在本文范圍內,不再詳述。

      更多精彩內容歡迎關注??公眾號:非專業程序員Ping

      posted on 2025-10-21 23:17  非專業程序員Ping  閱讀(211)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: 中文 在线 日韩 亚洲 欧美| 久久91精品牛牛| 国产高跟黑色丝袜在线| 亚洲av无码一区二区三区网站| 狠狠五月深爱婷婷网| 狠狠噜天天噜日日噜无码| 久久久精品2019中文字幕之3| 一本久道久久综合狠狠躁av| 秋霞无码一区二区| 亚洲国产一区二区精品专| 天天澡日日澡狠狠欧美老妇| 国产在线高清视频无码| 色欲久久综合亚洲精品蜜桃| 成人午夜视频在线| 亚洲国产成人久久77| 亚洲乱熟女一区二区三区| 日韩中文字幕一二三视频| 精品国产成人一区二区| 精品国产综合成人亚洲区| 成人久久精品国产亚洲av| 久久精品国产99精品国产2021| 国产日韩一区二区四季| 蜜臀av一区二区三区不卡| 久久月本道色综合久久| 国产精品天天看天天狠| 国产一区二区亚洲一区二区三区| 中文字幕人成无码免费视频| 4虎四虎永久在线精品免费| 久国产精品韩国三级视频| 久久精品亚洲精品国产区| 亚洲人成网站18禁止无码| 久久国产免费观看精品3| 精品国产AV无码一区二区三区 | 人妻体内射精一区二区三四 | 国产偷自视频区视频| 日韩一区二区三区日韩精品| 色综合久久天天综线观看| 美女胸18大禁视频网站| 绯色蜜臀av一区二区不卡| 亚洲高潮喷水无码AV电影| 四虎在线播放亚洲成人|