Оптимизация количества глифов шрифта для применения в 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