Оптимізація кількості гліфів шрифту для використання у web
Необхідні пакети apt install fontforge и pip install fonttools.
Визначимося з необхідними гліфами, потрібна латиниця, кирилиця, спецсимволи, включаючи деякі грецькі символи (ΣΩαβγμ), аналоги грецького, схожі в накресленні, але такі, що мають інші коди (∆∑µ), і ще трохи, які можуть десь використовуватися в тексті або як елементи, що замінюють графіку (♪♫♬).
Чому декілька варіантів гліфів з різними кодами?
Тому що символ µ (mu U+00b5) та грецька літера μ (mu U+03bc) у розширених шрифтах можуть мати свій гліф з різним накресленням, або навпаки, загальний гліф, де схожі символи з начерку посилаються на один гліф.
Або, наприклад, грецька Σ (Sigma U+03a3) не те саме, що символ ∑ (summation U+2211).
Але можливо, у вас на екрані ці символи виглядають однаково.
Варіант з підготовленими наборами символів у unicode
nano make_menu.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #!/bin/bash OPTS=`getopt -o I:O:S:L: --long in:,out:,subset:,layout: -n 'parse-options' -- "$@"` ; EC="$?" eval set -- "$OPTS" while true; do case "$1" in -I | --in ) in=$2; shift 2 ;; -O | --out) out=$2; shift 2 ;; -S | --subset) subset=$2; shift 2 ;; -L | --layout) layout=$2; shift 2 ;; -- ) shift; break ;; * ) break ;; esac done printf 'Read: %s\n' "${in}" printf 'Write: %s\n' "${out}" base="U+20-7E,U+A1-B7,U+B9-BE,U+C0,U+C1,U+C8,U+C9,\ U+CC,U+CD,U+D2,U+D3,U+D7,U+D9,U+DA,U+E0,U+E1,U+E8,U+E9,U+EB-ED,\ U+EF,U+F2,U+F3,U+F7-FA,U+131,U+2BB,U+2BC,U+2C6,U+2DA,U+2DC,U+400,U+401,\ U+403-408,U+410-451,U+453-458,U+45C-45F,U+490,U+491,U+4B0,U+4B1,\ U+2011,U+2018-201F,U+2022-2026,U+2030-203A,U+2041,U+2043,U+2044,\ U+204B,U+2052,U+2053,U+2074,U+20AC,U+2116,U+2122,U+2191,U+2193,U+2212,U+2215" base_ext="U+20-7E,U+A1-B7,U+B9-BE,U+C0,U+C1,U+C8,U+C9,\ U+CC,U+CD,U+D2,U+D3,U+D7,U+D9,U+DA,U+E0,U+E1,U+E8,U+E9,\ U+EB-ED,U+EF,U+F2,U+F3,U+F7-FA,U+131,U+192,U+2BB,U+2BC,U+2C6,U+2C7,\ U+2D9,U+2DA,U+2DC,U+394,U+3A9,U+3C0,U+400,U+401,U+403-408,U+410-451,\ U+453-458,U+45C-45F,U+462,U+463,U+490,U+491,U+4B0,U+4B1,U+2011,\ U+2018-201F,U+2022-2026,U+2030-203A,U+2041,U+2043,U+2044,U+204B,\ U+2052,U+2053,U+2074,U+2081-2084,U+20AC,U+20B4,U+20BD,U+20BF,\ U+2116,U+2122,U+212E,U+2191,U+2193,U+2211,U+2212,U+2215,U+221A,U+221E,\ U+222B,U+2248,U+2260,U+2264,U+2265" menu="U+20-7E,U+A3,U+A5,U+A7,U+A9,U+AB,U+AD,U+AE,U+B0,U+B4,U+B5,U+BB,\ U+C0,U+C1,U+C8,U+C9,U+CC,U+CD,U+D2,U+D3,U+D7,U+D9,U+DA,U+E0,U+E1,\ U+E8,U+E9,U+EB-ED,U+EF,U+F2,U+F3,U+F7-FA,U+131,U+192,\ U+2BB,U+2BC,U+2C6,U+2C7,U+2D9,U+2DA,\U+2DC,U+400,U+401,U+403-408,U+410-451,\ U+453-458,U+45C-45F,U+462,U+463,U+490,U+491,U+4B0,U+4B1,U+2011,U+2018-201F,\ U+2022-2026,U+2030-2037,U+2039,U+203A,U+2041,U+2043,U+2052,U+2053,U+20AC,U+20B4,\ U+20BD,U+20BF,U+2116,U+2122,U+2191,U+2193,U+221A,U+221E,U+222B,U+2248,U+2260,U+2264,U+2265" menu_textonly="U+20-7E,U+A9,U+AB,U+AD,U+AE,U+B0,U+B4,U+BB,U+C0,U+C1,U+C8,U+C9,U+CC,U+CD,\ U+D2,U+D3,U+D9,U+DA,U+E0,U+E1,U+E8,U+E9,U+EB-ED,U+EF,U+F2,U+F3,U+F9,U+FA,U+131,U+400,U+401,U+403-408,U+410-451,\ U+453-458,U+45C-45E,U+490,U+491,U+2024-2026,U+2039,U+203A,U+20AC,U+20B4,U+20BD,U+20BF" if [[ "$subset" == "base" ]]; then subset_list=$base fi if [[ "$subset" == "base_ext" ]]; then subset_list=$base_ext fi if [[ "$subset" == "menu" ]]; then subset_list=$menu fi if [[ "$subset" == "menu_textonly" ]]; then subset_list=$menu_textonly fi layout_add="kern,liga,clig,calt,ccmp,locl,mark,mkmk,onum,pnum,smcp,c2sc,lnum,tnum,subs,sups,cswh,dlig,ss01,ss03,zero" layout_rem="dnom,numr" if [[ "$layout" == "web" ]]; then layout_add="kern,liga,clig,calt,ccmp,locl,mark,mkmk,lnum,tnum,cswh,dlig,ss01,ss03,zero" layout_rem="dnom,numr,frac,onum,pnum,smcp,c2sc,subs,sups" fi /usr/bin/pyftsubset "${in}" --output-file="${out}" \ --unicodes="${subset_list}" \ --layout-features+="${layout_add}" \ --layout-features-="${layout_rem}" # --flavor=woff2 \ # --no-hinting \ # --desubroutinize \ |
nano ff-conv.sh
1 2 3 4 5 6 7 8 | #!/usr/bin/fontforge Open($1) Generate($1:r + ".otf") Generate($1:r + ".svg") Generate($1:r + ".woff") Generate($1:r + ".woff2") Generate($1:r + ".eot") Generate($1:r + ".ttf") |
На цьому сайті використовується латиниця, але не з усіма символами, наприклад діакритичними, а ще кирилиця, і деякі спеціальні символи.
Символьне представлення юнікод-символів
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # base_ext !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¹ º»¼½¾ÀÁÈÉÌÍÒÓ×ÙÚàáèéëìíïòó÷øùúıƒʻʼˆˇ˙˚˜ΔΩπЀЁЃЄЅІЇЈАБВГДЕЖЗИ ЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёѓє ѕіїјќѝўџѢѣҐґҰұ‑‘’‚‛“”„‟•‣․‥…‰‱′″‴‵‶‷‸‹›⁁⁃⁄⁋⁒⁓⁴₁₂₃₄€₴₽₿№™℮ ↑↓∑−∕√∞∫≈≠≤≥ # base_unicode !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¹ º»¼½¾ÀÁÈÉÌÍÒÓ×ÙÚàáèéëìíïòó÷øùúıʻʼˆ˚˜ЀЁЃЄЅІЇЈАБВГДЕЖЗИЙКЛМНО ПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёѓєѕіїјќѝ ўџҐґҰұ‑‘’‚‛“”„‟•‣․‥…‰‱′″‴‵‶‷‸‹›⁁⁃⁄⁋⁒⁓⁴€№™↑↓−∕ # menu !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~£¥§©«®°´µ»ÀÁÈÉÌÍÒÓ×ÙÚàá èéëìíïòó÷øùúıƒʻʼˆˇ˙˚˜ЀЁЃЄЅІЇЈАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭ ЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёѓєѕіїјќѝўџѢѣҐґҰұ‑‘’‚‛“” „‟•‣․‥…‰‱′″‴‵‶‷‹›⁁⁃⁒⁓€₴₽₿№™↑↓√∞∫≈≠≤≥ # menu_textonly !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~©«®°´»ÀÁÈÉÌÍÒÓÙÚàáèéëìí ïòóùúıЀЁЃЄЅІЇЈАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклм нопрстуфхцчшщъыьэюяѐёѓєѕіїјќѝўҐґ․‥…‹›€₴₽₿ |
Генеруємо шрифти
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ./make_menu.sh --subset "base_ext" \ --in PTSansNarrowRegular_original.ttf \ --out original/PTSansNarrowRegular_subset.ttf ./ff-conv.sh original/PTSansNarrowRegular_subset.ttf ./make_menu.sh --subset "base_ext" \ --in FiraSansExtraCondensedLight_original.ttf \ --out original/FiraSansExtraCondensedLight_subset.ttf ./ff-conv.sh original/FiraSansExtraCondensedLight_subset.ttf ./make_menu.sh --subset "base_ext" \ --in LiberationMonoRegular_original.ttf \ --out original/LiberationMonoRegular_subset.ttf ./ff-conv.sh original/LiberationMonoRegular_subset.ttf ./make_menu.sh --subset "menu_textonly" \ --in ShantellSansNormalRegular_original.otf \ --out original/ShantellSansNormalRegular_subset.otf ./ff-conv.sh original/ShantellSansNormalRegular_subset.otf |
Оригінальний шрифт PTSansNarrowRegular_original.ttf 230K
1 2 3 4 5 6 7 | 87K PTSansNarrowRegular_subset.afm 44K PTSansNarrowRegular_subset.eot 71K PTSansNarrowRegular_subset.otf 129K PTSansNarrowRegular_subset.svg 101K PTSansNarrowRegular_subset.ttf 52K PTSansNarrowRegular_subset.woff 40K PTSansNarrowRegular_subset.woff2 |
Деякі шрифти можуть використовувати один гліф для певних комбінацій символів,
для латиниці це часто комбінації fi fl ff ft.
Найчастіше веб-сервіси генерації шрифтів видаляють ці гліфи.
Якщо у вас така проблема, її можна вирішити просто додавши CSS правило
letter-spacing:-0.1pt;
font-glyph-fl-fi-ft.png
font-fl-fi-ft-errore.png
Варіант із вибором кодів вручну
Відкриваємо .ttf у fontforge і починаємо вибирати та копіювати потрібні числові коди гліфів у файл.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # latin range awk 'BEGIN{for(i=32;i<127;i++)printf "%c",i}' > glyph-symbols # cyrillic range awk 'BEGIN{for(i=1040;i<1106;i++)printf "%c",i}' >> glyph-symbols # special range awk 'BEGIN{for(i=8216;i<8223;i++)printf "%c",i}' >> glyph-symbols # special A="160 161 166 167 169 171 173 174 176 177 178 179 180 181 183 185 187 \ 188 189 190 198 215 216 230 247 248 402 729 730 732 733 916 931 937 \ 945 946 947 948 949 955 956 957 960 966 968 969 1025 1027 1028 1030 \ 1031 1037 1107 1108 1110 1111 1122 1123 1168 1169 8240 8226 8230 8240 \ 8242 8243 8249 8250 8356 8364 8372 8381 8470 8482 8486 8494 8592 8593 \ 8594 8595 8596 8597 8710 8721 8722 8725 8730 8734 8747 8776 8800 8804 \ 8805 9834 9835 9836" ; awk -v var="${A[*]}" 'BEGIN{split(var,list," "); \ for (i=1;i<=length(list);i++) printf "%c", list[i]}' \ >> glyph-symbols |
pyftsubset PTSansNarrow-Regular.ttf --output-file=PTSans-sub.ttf --text-file=glyph-symbols
Універсальний css стиль для шрифту та fallback з коригуванням розмірів
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | @font-face { font-family: "ShantellSansNormalRegular"; src: url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.eot"); /* IE9 Compat Modes */ src: url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */ url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.woff2") format("woff2"), /* Modern Browsers */ url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.woff") format("woff"), /* Modern Browsers */ url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.ttf") format("truetype"), /* Safari, Android, iOS */ url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.svg#ShantellSansNormal-Regular") format("svg"); /* Legacy iOS */ src: url("/assets/css/fonts/original/ShantellSansNormalRegular_subset.otf") format(opentype) tech(incremental-range); /* Open Type Font */ font-weight:normal; font-style:normal; font-display:block; unicode-range:U+20-7E,U+A9,U+AB,U+AD,U+AE,U+B0,U+B4,U+BB,U+C0,U+C1,U+C8,U+C9,U+CC,U+CD,U+D2,U+D3,U+D9,U+DA,U+E0,U+E1,U+E8,U+E9,U+EB-ED,U+EF,U+F2,U+F3,U+F9,U+FA,U+131,U+400,U+401,U+403-408,U+410-451,U+453-458,U+45C-45E,U+490,U+491,U+2024-2026,U+2039,U+203A,U+20AC,U+20B4,U+20BD,U+20BF;} @font-face { font-family: "fallbackShantellComic"; src: local("Comic Sans MS"); size-adjust: 98%; ascent-override: 107%; descent-override: 25%; line-gap-override: 5%; } @font-face { font-family: "fallbackShantellArial"; src: local("Arial"); size-adjust: 105%; ascent-override: 100%; descent-override: 29%; line-gap-override: 5%; } p {font-family:"ShantellSansNormalRegular", "fallbackShantellComic", "fallbackShantellArial", "Comic Sans MS", sans-serif;} |
І ще трошки
Підраховуємо кількість гліфів в оригінальному файлі та зробленому самостійно.
1 2 3 4 5 6 7 8 9 10 11 | fontforge -lang=ff -c 'Open($1); SelectWorthOutputting(); Print($selection)' \ "PTSansNarrowRegular_original.ttf" 2>/dev/null | \ tr -d '][' | tr , '\n' | grep -c 1 723 fontforge -lang=ff -c 'Open($1); SelectWorthOutputting(); Print($selection)' \ "PTSansNarrowRegular_subset.ttf" 2>/dev/null | \ tr -d '][' | tr , '\n' | grep -c 1 292 |
Для svg це можна зробити наприклад так:
cat PTSansNarrow.svg | grep "glyph-name" | wc -l
723
cat PTSansNarrow_subset.svg | grep "glyph-name" | wc -l
292
Слід зазначити, що гліфів в отриманих шрифтах може бути менше, ніж символів для вибірки, тому що в конкретному шрифті може бути не гліфів для деяких символів, скрипт містить розширений набір символів (кодів) для вибірки з різних шрифтів, але головне, що він не містить не потрібних символів. Проте, все ж таки правильніше буде відкривати конкретний шрифт у редакторі і вибирати потрібні з наявних гліфів.
Якщо планується використовувати шрифт тільки для тексту, який іноді навіть не передбачає додаткових символів до alphanumeric, крім крапки та коми, то кількість гліфів можна скоротити ще більше.
1 2 3 4 5 6 7 8 9 | # latin awk 'BEGIN{for(i=32;i<127;i++)printf "%c",i}' > short-glyphs # кирилиця awk 'BEGIN{for(i=1040;i<1106;i++)printf "%c",i}' >> short-glyphs A="1025 1028 1030 1031 1108 1110 1111 1168 1169" ; awk -v var="${A[*]}" 'BEGIN{split(var,list," "); for (i=1;i<=length(list);i++) printf "%c", list[i]}' >> short-glyphs pyftsubset Caveat-Regular.ttf \ --output-file=Caveat-Regular-short.ttf \ --text-file=short-glyphs |
Оригінальний пост на SecOps.it Blog • Оптимізація кількості гліфів шрифту для використання у web