[轉]TrueType(TTF)字體文件裁剪(支持簡體中文,繁體中文TTF字體裁剪)

原文入口:php

TTF字體文件裁剪(支持簡體中文,繁體中文TTF字體裁剪)html

對於TrueType(TTF)字體格式的介紹能夠看:java

https://www.cnblogs.com/slysky/p/11315735.html 

提到的文章。git

Google開源的字體提取神器——sfntlygithub

sfnttool,官網地址是:https://code.google.com/p/sfntly/express

可用於編輯、建立和使用字體文件,主要針對OpenType,TrueType字體。apache

我在項目中,主要用於對漢字字體庫的裁剪(ttf字庫通常都很大10M以上),提取項目須要的一個漢字子集(subset)。app

環境準備:less

  • 首先、安裝好Java環境,jdk 1.8.x以上,以及ant編譯工具;
  • 而後、下載源碼https://github.com/googlei18n/sfntly;
  • 最後、編譯獲得sfnttool.jar包。

裁剪字體庫以及注意事項:ide

一、使用SfntToolGUI.jar或sfnttool.jar 提取指定字符子集(SfntToolGUI.jar是基於sfnttool.jar加了GUI界面)

java -jar sfnttool.jar -s '須要提取的字體' 源字體庫 導出的最終字體庫

  如:java -jar sfnttool.jar -s '01中國人' llk.ttf llk2.ttf

  java -jar SfntToolGUI.jar

  會有一個GUI界面能夠操做(SfntToolGUI.jar是網上下載的),使用這個GUI工具點擊肯定生成完成後,須要關閉這個軟件,新生成的ttf文件

才能預覽或使用FontCreator打開,不然它會提示生成的ttf格式錯誤。

二、 須要注意的事項:

a、 sfnttool 會根據當前系統使用的字符集編碼(GBK or BIG5等)把輸入的提取字符串轉換成Unicode碼,而後再去ttf查到到對應的字,進而提取。

  我第一次使用也是遇到一個坑:我使用的是簡體中文Windows系統(代碼頁936(chcp命令可查詢當前系統使用的代碼頁)),輸入GB2312編碼的簡體字符串,且輸入簡體中文黑體ttf字體,確實能夠裁剪到本身設定的子集ttf字體。

  因爲最近項目用到繁體中文,須要對繁體中文ttf進行裁剪,很直觀的想法就是輸入BIG5編碼的繁體字符串和輸入一個繁體字庫mingliu.ttf,直接使用sfnttool提取子集,發現提取出來的並非子集想要的。

  後來開始看sfnttool源代碼,發現sfnttool會根據當前系統使用的字符集編碼(個人系統使用GBK)把輸入的提取字符串轉換成Unicode碼。也就是說我輸入的是BIG5編碼的數據,而sfnttool把這些數據當作是GBK編碼的數據來轉成Unicode,這顯然是有問題的。

  一個最簡單的辦法把電腦系統的代碼頁切換到950(BIG5),即切換到繁體版Windows,而後從新再使用這個工具。把BIG5編碼的字符串輸入到sfnttool另一個辦法就是修改下sfnttool源代碼可配置當前輸入的是什麼編碼的數據,以及正確的轉成對應的Unicode。

b、 還有些細節

  mingliu.ttc,細黑體_0.ttc,ttc能夠使用FontCreator轉成mingliu_0.ttf,細黑體_0.ttf

  從 "mingliu_0.ttf" 提取字符子集,僅僅提取幾個字符就有4M多大小(源ttf有26M)。而提取經常使用漢字3000個左右,使用 "細黑體_0.ttf" 提取子集僅僅2.5M, 使用 "mingliu_0.ttf" 提取的子集有8.5M 。(估計是跟字體庫自己設置了什麼有關)

  另外網上還有一個TTF字體裁剪小工具「TTF字體庫裁剪轉換工具」:

  通過測試有部分字體不支持,也不支持繁體字體裁剪。工具下載地址:https://download.csdn.net/download/leichelle/10673940

參考資料:

【工具】在TTF字體中提取想要的文字,讓字體文件變迷你
https://blog.csdn.net/ldpjay/article/details/46561031

大坑已填,留個記念:裁剪ttf,讓其大小更適用於移動設備與網頁
https://blog.csdn.net/tianxiawuzhei/article/details/45720563

sfntly源代碼
https://github.com/googlei18n/sfntly
https://github.com/rillig/sfntly

谷歌開源的字體提取工具 sfntly 的正確打開方式
https://www.skiy.net/201706064777.html

中文漢字 | ASCII | Unicode互相轉換工具 - aTool在線工具
http://www.atool.org/chinese2unicode.php

----------------------------------------分割線---------------------------------------------

原文做者提供瞭如何利用谷歌的sfntly來精簡字體包,可是隻能以 

    java -jar sfnttool.jar -s ‘要進行提取的文案‘ 提取前的文件名.ttf 提取後的文件名.ttf  

  的形式來對命令行輸入的字符串生成字體包。 

  我在源代碼的基礎上加上了讀取文件的功能,使之能夠方便的將字符集配置在文本里。 

  下面是修改過的SfntTool.java源代碼,直接覆蓋原文件便可: 

  1 /*
  2  * Copyright 2011 Google Inc. All Rights Reserved.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  * http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package com.google.typography.font.tools.sfnttool;
 18 
 19 import com.google.typography.font.sfntly.Font;
 20 import com.google.typography.font.sfntly.FontFactory;
 21 import com.google.typography.font.sfntly.Tag;
 22 import com.google.typography.font.sfntly.data.WritableFontData;
 23 import com.google.typography.font.sfntly.table.core.CMapTable;
 24 import com.google.typography.font.tools.conversion.eot.EOTWriter;
 25 import com.google.typography.font.tools.conversion.woff.WoffWriter;
 26 import com.google.typography.font.tools.subsetter.HintStripper;
 27 import com.google.typography.font.tools.subsetter.RenumberingSubsetter;
 28 import com.google.typography.font.tools.subsetter.Subsetter;
 29 
 30 import java.io.File;
 31 import java.io.FileInputStream;
 32 import java.io.BufferedReader;
 33 import java.io.FileOutputStream;
 34 import java.io.InputStreamReader;
 35 import java.io.IOException;
 36 import java.util.ArrayList;
 37 import java.util.HashSet;
 38 import java.util.List;
 39 import java.util.Set;
 40 
 41 /**
 42  * @author Raph Levien
 43  */
 44 public class SfntTool {
 45   private boolean strip = false;
 46   private String subsetString = null;
 47   private boolean woff = false;
 48   private boolean eot = false;
 49   private boolean mtx = false;
 50 
 51   public static void main(String[] args) throws IOException {
 52     SfntTool tool = new SfntTool();
 53     File fontFile = null;
 54     File outputFile = null;
 55     boolean bench = false;
 56     int nIters = 1;
 57 
 58     for (int i = 0; i < args.length; i++) {
 59       String option = null;
 60       if (args[i].charAt(0) == '-') {
 61         option = args[i].substring(1);
 62       }
 63 
 64       if (option != null) {
 65         if (option.equals("help") || option.equals("?")) {
 66           printUsage();
 67           System.exit(0);
 68         } else if (option.equals("b") || option.equals("bench")) {
 69           nIters = 10000;
 70         } else if (option.equals("h") || option.equals("hints")) {
 71           tool.strip = true;
 72         } else if (option.equals("s") || option.equals("string")) {
 73           File filename = new File(args[i + 1]);
 74           InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
 75           BufferedReader br = new BufferedReader(reader);
 76           String line = br.readLine();
 77           tool.subsetString = line;
 78           br.close();
 79           // tool.subsetString = args[i + 1];
 80           i++;
 81         } else if (option.equals("w") || option.equals("woff")) {
 82           tool.woff = true;
 83         } else if (option.equals("e") || option.equals("eot")) {
 84           tool.eot = true;
 85         } else if (option.equals("x") || option.equals("mtx")) {
 86           tool.mtx = true;
 87         } else {
 88           printUsage();
 89           System.exit(1);
 90         }
 91       } else {
 92         if (fontFile == null) {
 93           fontFile = new File(args[i]);
 94         } else {
 95           outputFile = new File(args[i]);
 96           break;
 97         }
 98       }
 99     }
100 
101     if (tool.woff && tool.eot) {
102       System.out.println("WOFF and EOT options are mutually exclusive");
103       System.exit(1);
104     }
105 
106     if (fontFile != null && outputFile != null) {
107       tool.subsetFontFile(fontFile, outputFile, nIters);
108     } else {
109       printUsage();
110     }
111   }
112 
113   private static final void printUsage() {
114     System.out.println("Subset [-?|-h|-help] [-b] [-s string] fontfile outfile");
115     System.out.println("Prototype font subsetter");
116     System.out.println("\t-?,-help\tprint this help information");
117     System.out.println("\t-s,-string\t String to subset");
118     System.out.println("\t-b,-bench\t Benchmark (run 10000 iterations)");
119     System.out.println("\t-h,-hints\t Strip hints");
120     System.out.println("\t-w,-woff\t Output WOFF format");
121     System.out.println("\t-e,-eot\t Output EOT format");
122     System.out.println("\t-x,-mtx\t Enable Microtype Express compression for EOT format");
123   }
124 
125   public void subsetFontFile(File fontFile, File outputFile, int nIters) throws IOException {
126     FontFactory fontFactory = FontFactory.getInstance();
127     FileInputStream fis = null;
128     try {
129       fis = new FileInputStream(fontFile);
130       byte[] fontBytes = new byte[(int) fontFile.length()];
131       fis.read(fontBytes);
132       Font[] fontArray = null;
133       fontArray = fontFactory.loadFonts(fontBytes);
134       Font font = fontArray[0];
135       List<CMapTable.CMapId> cmapIds = new ArrayList<CMapTable.CMapId>();
136       cmapIds.add(CMapTable.CMapId.WINDOWS_BMP);
137       byte[] newFontData = null;
138       for (int i = 0; i < nIters; i++) {
139         Font newFont = font;
140         if (subsetString != null) {
141           Subsetter subsetter = new RenumberingSubsetter(newFont, fontFactory);
142           subsetter.setCMaps(cmapIds, 1);
143           List<Integer> glyphs = GlyphCoverage.getGlyphCoverage(font, subsetString);
144           subsetter.setGlyphs(glyphs);
145           Set<Integer> removeTables = new HashSet<Integer>();
146           // Most of the following are valid tables, but we don't renumber them yet, so strip
147           removeTables.add(Tag.GDEF);
148           removeTables.add(Tag.GPOS);
149           removeTables.add(Tag.GSUB);
150           removeTables.add(Tag.kern);
151           removeTables.add(Tag.hdmx);
152           removeTables.add(Tag.vmtx);
153           removeTables.add(Tag.VDMX);
154           removeTables.add(Tag.LTSH);
155           removeTables.add(Tag.DSIG);
156           removeTables.add(Tag.vhea);
157           // AAT tables, not yet defined in sfntly Tag class
158           removeTables.add(Tag.intValue(new byte[] { 'm', 'o', 'r', 't' }));
159           removeTables.add(Tag.intValue(new byte[] { 'm', 'o', 'r', 'x' }));
160           subsetter.setRemoveTables(removeTables);
161           newFont = subsetter.subset().build();
162         }
163         if (strip) {
164           Subsetter hintStripper = new HintStripper(newFont, fontFactory);
165           Set<Integer> removeTables = new HashSet<Integer>();
166           removeTables.add(Tag.fpgm);
167           removeTables.add(Tag.prep);
168           removeTables.add(Tag.cvt);
169           removeTables.add(Tag.hdmx);
170           removeTables.add(Tag.VDMX);
171           removeTables.add(Tag.LTSH);
172           removeTables.add(Tag.DSIG);
173           removeTables.add(Tag.vhea);
174           hintStripper.setRemoveTables(removeTables);
175           newFont = hintStripper.subset().build();
176         }
177 
178         FileOutputStream fos = new FileOutputStream(outputFile);
179         if (woff) {
180           WritableFontData woffData = new WoffWriter().convert(newFont);
181           woffData.copyTo(fos);
182         } else if (eot) {
183           WritableFontData eotData = new EOTWriter(mtx).convert(newFont);
184           eotData.copyTo(fos);
185         } else {
186           fontFactory.serializeFont(newFont, fos);
187         }
188       }
189     } finally {
190       if (fis != null) {
191         fis.close();
192       }
193     }
194   }
195 }
可輸入文件的優化代碼

 

替換完畢後,仍是用ant來編譯jar包,編譯好後用以下命令行語句來精簡字體包:

java -jar sfnttool.jar -s "filter.txt" Font_old.ttf Font_new.ttf

原文:https://blog.csdn.net/xp406181/article/details/79232571

 

----------------------------------------分割線---------------------------------------------

附經常使用漢字2500多個

一乙二十丁廠七卜人入八九幾兒了力乃刀又三於幹虧士工土才寸下大丈與萬上小口巾山千乞川億個勺久凡及夕丸麼廣亡門義之屍弓己已子衛也女飛刃習叉馬鄉豐王井開夫天無元專雲扎藝木五支廳不太犬區歷尤友匹車巨牙屯比互切瓦止少日中岡貝內水見午牛手毛氣升長仁什片僕化仇幣仍僅斤爪反介父從今兇分乏公倉月氏勿欠風丹勻烏鳳勾文六方火爲鬥憶訂計戶認心尺引醜巴孔隊辦以允予勸雙書幻玉刊示末未擊打巧正撲扒功扔去甘世古節本術可丙左厲右石布龍平滅軋東卡北佔業舊帥歸且旦目葉甲申叮電號田由史只央兄叼叫另叨嘆四生失禾丘付仗代仙們儀白仔他斥瓜乎叢令用甩印樂句匆冊犯外處冬鳥務包飢主市立閃蘭半汁匯頭漢寧穴它討寫讓禮訓必議訊記永司尼民出遼奶奴加召皮邊發孕聖對臺矛糾母幼絲式刑動扛寺吉扣考託老執鞏圾擴掃地揚場耳共芒亞芝朽樸機權過臣再協西壓厭在有百存而頁匠誇奪灰達列死成夾軌邪劃邁畢至此貞師塵尖劣光當早吐嚇蟲曲團同吊吃因吸嗎嶼帆歲回豈剛則肉網年朱先丟舌竹遷喬偉傳乒乓休伍伏優伐延件任傷價份華仰仿夥僞自血向似後行舟全會殺合兆企衆爺傘創肌朵雜危旬旨負各名多爭色壯衝冰莊慶亦劉齊交次衣產決充妄閉問闖羊並關米燈州汗污江池湯忙興宇守宅字安講軍許論農諷設訪尋那迅盡導異孫陣陽收階陰防奸如婦好她媽戲羽觀歡買紅纖級約紀馳巡壽弄麥形進戒吞遠違運扶撫壇技壞擾拒找批扯址走抄壩貢攻赤折抓扮搶孝均拋投墳抗坑坊抖護殼志扭塊聲把報卻劫芽花芹芬蒼芳嚴蘆勞克蘇杆槓杜材村杏極李楊求更束豆兩麗醫辰勵否還殲來連步堅旱盯呈時吳助縣裏呆園曠圍呀噸足郵男困吵串員聽吩吹嗚吧吼別崗賬財針釘告我亂利禿秀私每兵估體何但伸做伯伶傭低你住位伴身皁佛近徹役返餘希坐谷妥含鄰岔肝肚腸龜免狂猶角刪條卵島迎飯飲系言凍狀畝況牀庫療應冷這序辛棄冶忘閒間悶判竈燦弟汪沙汽沃泛溝沒沈沉懷憂快完宋宏牢究窮災良證啓評補初社識訴診詞譯君靈即層尿尾遲局改張忌際陸阿陳阻附妙妖妨努忍勁雞驅純紗納綱駁縱紛紙紋紡驢紐奉玩環武青責現表規抹攏拔揀擔坦押抽拐拖拍者頂拆擁抵拘勢抱垃拉攔拌幸招坡披撥擇擡其取苦若茂蘋苗英範直茄莖茅林枝杯櫃析板鬆槍構傑述枕喪或畫臥事刺棗雨賣礦碼廁奔奇奮態歐壟妻轟頃轉斬輪軟到非叔肯齒些虎虜腎賢尚旺具果味昆國昌暢明易昂典固忠咐呼鳴詠呢岸巖帖羅幟嶺凱敗販購圖釣制知垂牧物乖刮稈和季委佳侍供使例版侄偵側憑僑佩貨依的迫質欣徵往爬彼徑所舍金命斧爸採受乳貪念貧膚肺肢腫脹朋股肥服脅周昏魚兔狐忽狗備飾飽飼變京享店夜廟府底劑郊廢淨盲放刻育閘鬧鄭券卷單炒炊炕炎爐沫淺法泄河沾淚油泊沿泡注瀉泳泥沸波潑澤治怖性怕憐怪學寶宗定宜審宙官空簾實試郎詩肩房誠襯衫視話誕詢該詳建肅錄隸居屆刷屈弦承孟孤陝降限妹姑姐姓始駕參艱線練組細駛織終駐駝紹經貫奏春幫珍玻毒型掛封持項垮挎城撓政赴趙擋挺括拴拾挑指墊掙擠拼挖按揮挪某甚革薦巷帶草繭茶荒茫蕩榮故胡南藥標枯柄棟相查柏柳柱柿欄樹要鹹威歪研磚釐厚砌砍面耐耍牽殘殃輕鴉皆背戰點臨覽豎省削嘗是盼眨哄顯啞冒映星昨畏趴胃貴界虹蝦蟻思螞雖品咽罵譁咱響哈咬咳哪炭峽罰賤貼骨鈔鍾鋼鑰鉤卸缸拜看矩怎牲選適秒香種秋科重複竿段便倆貸順修保促侮儉俗俘信皇泉鬼侵追俊盾待律很須敘劍逃食盆膽勝胞胖脈勉狹獅獨狡獄狠貿怨急饒蝕餃餅彎將獎哀亭亮度跡庭瘡瘋疫疤姿親音帝施聞閥閣差養美姜叛送類迷前首逆總煉炸炮爛剃潔洪灑澆濁洞測洗活派洽染濟洋洲渾濃津恆恢恰惱恨舉覺宣室宮憲突穿竊客冠語扁襖祖神祝誤誘說誦墾退既屋晝費陡眉孩除險院娃姥姨姻嬌怒架賀盈勇怠柔壘綁絨結繞驕繪給絡駱絕絞統耕耗豔泰珠班素蠶頑盞匪撈栽捕振載趕起鹽捎捏埋捉捆捐損都哲逝撿換挽熱恐壺挨恥耽恭蓮莫荷獲晉惡真框桂檔桐株橋桃格校覈樣根索哥速逗慄配翅辱脣夏礎破原套逐烈殊顧轎較頓斃致柴桌慮監緊黨曬眠曉鴨晃晌暈蚊哨哭恩喚啊唉罷峯圓賊賄錢鉗鑽鐵鈴鉛缺氧特犧造乘敵秤租積秧秩稱祕透筆笑筍債借值倚傾倒倘俱倡候俯倍倦健臭射躬息徒徐艦艙般航途拿爹愛頌翁脆脂胸胳髒膠腦狸狼逢留皺餓戀槳漿衰高席準座脊症病疾疼疲效離唐資涼站剖競部旁旅畜閱羞瓶拳粉料益兼烤烘煩燒燭煙遞濤浙澇酒涉消浩海塗浴浮流潤浪浸漲燙涌悟悄悔悅害寬家宵宴賓窄容宰案請朗諸讀扇襪袖袍被祥課誰調冤諒談誼剝懇展劇屑弱陵陶陷陪娛娘通能難預桑絹繡驗繼球理捧堵描域掩捷排掉堆推掀授教掏掠培接控探據掘職基著勒黃萌蘿菌菜萄菊萍菠營械夢梢梅檢梳梯桶救副票戚爽聾襲盛雪輔輛虛雀堂常匙晨睜眯眼懸野啦晚啄距躍略蛇累唱患惟崖嶄崇圈銅鏟銀甜梨犁移笨籠笛符第敏作袋悠償偶偷您售停偏假得銜盤船斜盒鴿悉欲彩領腳脖臉脫象夠猜豬獵貓猛餡館湊減毫麻癢痕廊康庸鹿盜章竟商族旋望率着蓋粘粗粒斷剪獸清添淋淹渠漸混漁淘液淡深婆梁滲情惜慚悼懼惕驚慘慣寇寄宿窯密謀謊禍謎逮敢屠彈隨蛋隆隱婚嬸頸績緒續騎繩維綿綢綠琴斑替款堪搭塔越趁趨超提堤博揭喜插揪搜煮援裁擱摟攪握揉斯期欺聯散惹葬葛董葡敬蔥落朝辜葵棒棋植森椅椒棵棍棉棚棕惠惑逼廚廈硬確雁殖裂雄暫雅輩悲紫輝敞賞掌晴暑最量噴晶喇遇喊景踐跌跑遺蛙蛛蜓喝喂喘喉幅帽賭賠黑鑄鋪鏈銷鎖鋤鍋鏽鋒銳短智毯鵝剩稍程稀稅筐等築策篩筒答筋箏傲傅牌堡集焦傍儲奧街懲御循艇舒番釋禽臘脾腔魯猾猴然饞裝蠻就痛童闊善羨普糞尊道曾焰港湖渣溼溫渴滑灣渡遊滋溉憤慌惰愧愉慨割寒富竄窩窗遍裕褲裙謝謠謙屬屢強粥疏隔隙絮嫂登緞緩編騙緣瑞魂肆攝摸填搏塌鼓擺攜搬搖搞塘攤蒜勤鵲藍墓幕蓬蓄蒙蒸獻禁楚想槐榆樓概賴酬感礙碑碎碰碗碌雷零霧雹輸督齡鑑睛睡睬鄙愚暖盟歇暗照跨跳跪路跟遣蛾蜂嗓置罪罩錯錫鑼錘錦鍵鋸矮辭稠愁籌籤簡毀舅鼠催傻像躲微愈遙腰腥腹騰腿觸解醬痰廉新韻意糧數煎塑慈煤煌滿漠源濾濫滔溪溜滾濱粱灘慎譽塞謹福羣殿闢障嫌嫁疊縫纏靜碧璃牆撇嘉摧截誓境摘摔聚蔽慕暮蔑模榴榜榨歌遭酷釀酸磁願需弊裳顆嗽蜻蠟蠅蜘賺鍬鍛舞穩算籮管僚鼻魄貌膜膊膀鮮疑饅裹敲豪膏遮腐瘦辣竭端旗精歉熄熔漆漂漫滴演漏慢寨賽察蜜譜嫩翠熊凳騾縮慧撕撒趣趟撐播撞撤增聰鞋蕉蔬橫槽櫻橡飄醋醉震黴瞞題暴瞎影踢踏踩蹤蝶蝴囑墨鎮靠稻黎稿稼箱箭篇僵躺僻德艘膝膛熟摩顏毅糊遵潛潮懂額慰劈操燕薯薪薄顛橘整融醒餐嘴蹄器贈默鏡贊籃邀衡膨雕磨凝辨辯糖糕燃澡激懶壁避繳戴擦鞠藏霜霞瞧蹈螺穗繁辮贏糟糠燥臂翼驟鞭覆蹦鐮翻鷹警攀蹲顫瓣爆疆壤耀躁嚼嚷籍魔灌蠢霸露囊罐翎qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890《》?!,。嫵媚曳鎏怡廓滄
View Code

字體推薦: 
蘋果PingHei三款 
騰祥嘉麗細圓簡 
蘋方字體 
微軟雅黑light 
漢儀旗黑H2312F45

推薦連接:

http://www.zhaozi.cn/html/fonts/china/riben/2010-11-18/21992.html 
https://www.zhihu.com/question/20727176 
http://daily.zhihu.com/story/3630127 
http://www.epinv.com/post/5740.html 
https://sanwen8.cn/p/3a5dO2X.html 
https://www.zhihu.com/question/20922638 
http://www.fontke.com/font/10552118/ 
https://www.zhihu.com/question/24878730 
http://blog.sina.com.cn/s/blog_62c692fd0100fjtn.html

相關文章
相關標籤/搜索