Temukan font terbaik untuk rendering codepoint

16

Bagaimana menemukan font yang sesuai untuk rendering codepoint unicode?

gnome-terminalmenemukan bahwa karakter seperti Β«πŸ‰ƒ βΌΌ πŸ˜»πŸ•²πŸ€Β» dapat diterjemahkan dengan font seperti Symbola daripada font terminal saya atau fallback codepoint-in-square (????). Bagaimana?

Nggak
sumber
Terkait: askubuntu.com/questions/27598/…
Nathaniel M. Beaver

Jawaban:

14

Ini belum tentu metode terbaik, dan tentu saja tidak ramah pengguna, tetapi mudah untuk bekerja: inilah skrip Python untuk melakukannya.

Instal pustaka Python-fontconfig . Baik mendapatkannya dari distribusi Anda (misalnya sudo apt-get install python-fontconfigpada Debian dan turunannya) atau menginstalnya di direktori home Anda ( pip install --user python-fontconfig). Kemudian Anda dapat menjalankan skrip ini (simpan sebagai fc-search-codepointdalam direktori pada Anda PATH, mis. Biasanya ~/bin, dan membuatnya dapat dieksekusi):

#!/usr/bin/env python2
import re, sys
import fontconfig
if len(sys.argv) < 1:
    print('''Usage: ''' + sys.argv[0] + '''CHARS [REGEX]
Print the names of available fonts containing the code point(s) CHARS.
If CHARS contains multiple characters, they must all be present.
Alternatively you can use U+xxxx to search for a single character with
code point xxxx (hexadecimal digits).
If REGEX is specified, the font name must match this regular expression.''')
    sys.exit(0)
characters = sys.argv[1]
if characters.startswith('U+'):
    characters = unichr(int(characters[2:], 16))
else:
    characters = characters.decode(sys.stdout.encoding)
regexp = re.compile(sys.argv[2] if len(sys.argv) > 2 else '')

font_names = fontconfig.query()
found = False
for name in font_names:
    if not re.search(regexp, name): continue
    font = fontconfig.FcFont(name)
    if all(font.has_char(c) for c in characters):
        print(name)
        found = True

sys.exit(0 if found else 1)

Contoh penggunaan:

$ fc-search-codepoint πŸ‰ƒβΌΌπŸ˜»πŸ•²πŸ€
$ echo $?
1

Saya tidak memiliki font apa pun dengan semua karakter ini.

$ fc-search-codepoint U+1F64D
/usr/share/fonts/truetype/unifont/unifont_upper.ttf
/usr/share/fonts/truetype/unifont/unifont_upper_csur.ttf
Gilles 'SO- berhenti menjadi jahat'
sumber
1
Itu skrip yang sangat membantu! Namun, itu hanya python2 compliant, dan saya kira itu agak jahat untuk melakukan hal itu portabel. Apakah Anda keberatan setidaknya mengubah #!/usr/bin/env pythonuntuk #!/usr/bin/env python2sesuai PEP 394.
Zulan
1
Terima kasih atas jawaban ini! Itu sangat membantu. Saya yakin OS atau pustaka sistem yang mengimplementasikan font fallback melakukan sesuatu yang lebih efisien, tetapi ini berfungsi. @ Zulan Dapat dibuat untuk bekerja dengan python3juga; Saya baru saja menulis versi yang lebih kecil di bagian bawah jawaban ini .
ShreevatsaR
5

Menggunakan fontconfig,

> fc-list ':charset=<hex_code1> <hex_code2>'

misalnya

> fc-list ':charset=2713 2717'

akan menampilkan semua nama file font yang mengandung βœ“ dan βœ—.

Untuk mendapatkan codepoint yang sesuai dengan penggunaan karakter (misalnya)

> printf "%x" \'βœ“
2713>

Ini menggunakan fitur agak jelas dari POSIX printfutilitas :

Jika karakter utama adalah kuotasi tunggal atau kuotasi ganda, nilainya harus berupa nilai numerik dalam set kode yang mendasari karakter yang mengikuti kuotasi tunggal atau kuotasi ganda.

Diambil bersama-sama,

> printf '%x' \'βœ“ | xargs -I{} fc-list ":charset={}"

Ini menggunakan xargs -Ibendera untuk menggantikan {}nama dari stdin. Jadi ini secara efektif bermuara pada:

> fc-list ":charset=2713"
David Baynard
sumber
2
Perhatikan bahwa Anda memerlukan versi fontconfigitu 2.11.91atau yang lebih baru .
Nathaniel M. Beaver
1
perhatikan tanda hubung itu printfdan /bin/printfjangan mendukungnya
Steven Penny
1
Luar biasa! Saya sudah mencari informasi tentang ini sejak lama. Perhatikan bahwa Anda juga dapat menentukan rentang serta karakter tunggal, jadi untuk menemukan semua font yang memiliki semua karakter menggambar kotak, misalnya:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew
3

Akhirnya gnome-terminal menggunakan fontconfig untuk (antara lain):

... efisien dan cepat menemukan font yang Anda butuhkan di antara set font yang telah Anda instal, bahkan jika Anda telah menginstal ribuan font ...

Dalam dokumentasi API Anda dapat menemukan fungsi untuk menanyakan rentang karakter font dan untuk operasi pada rentang karakter, tetapi dokumentasinya sangat samar sehingga saya tidak pernah bisa mengetahui bagaimana rangkaian fungsi yang berbeda saling berhubungan. Jika saya perlu menyelam lebih dalam, saya lebih suka melihat contoh penggunaan dalam perangkat lunak lain, mungkin vte (perpustakaan emulasi terminal yang digunakan di gnome-terminal).

Perpustakaan lain di antara vte dan fontconfig adalah pango "... perpustakaan untuk meletakkan dan rendering teks, dengan penekanan pada internasionalisasi ..." . Sekarang saya memikirkannya, itu terdengar sebagai yang mengandung sebagian besar logika yang Anda cari.

Fungsi cakupan karakter dalam pango diimplementasikan oleh peta cakupan ( "Sering kali perlu di Pango untuk menentukan apakah font tertentu dapat mewakili karakter tertentu, dan juga seberapa baik itu dapat mewakili karakter itu. PangoCoverage adalah struktur data yang digunakan untuk merepresentasikan informasi itu. " ), tetapi mungkin ada detail yang lebih rumit yang terlibat dalam memutuskan mesin terbang apa yang harus dirender dengan font apa. Saya kira VTE bergantung pada pango untuk membuat string dengan font yang sesuai sementara pango menggunakan fontconfig (atau backend font yang didukung lainnya) untuk menemukan font yang paling tepat berdasarkan berbagai potongan logika dalam pango itu sendiri dan / atau backend.

artm
sumber
1

Saya mengubah kode untuk memeriksa apakah font berisi semua karakter dari string tertentu. Jadi ini bisa dipanggil oleh fc-search-codepoint "$fontname" "$string"dan mengembalikan kode keluar 0 jika berhasil atau 1 sebaliknya. Nama font dapat diambil dari fc-query /path/to/FontSandMonoBoldOblique.ttfatau Imagemagick convert -list font. Saya menggunakannya untuk memeriksa apakah string yang dipilih pengguna dapat dirender dengan font yang dipilih pengguna dan jika perintah gagal, font fallback digunakan.

#!/usr/bin/env python2
import re
import sys
import os
import fontconfig
if len(sys.argv) < 3:
    print("Usage: " + sys.argv[0] + " 'Fontname-Bold' 'String to check'")
    sys.exit(0)

font_name = sys.argv[1].decode('utf-8')
string = sys.argv[2].decode('utf-8')

if '-' in font_name:
        font_name = font_name.split('-')
        font_style = font_name[-1]
        font_name = ''.join(font_name[:-1])
else:
        font_style = ""

font_names = fontconfig.query()
for name in font_names:
    font = fontconfig.FcFont(name)
    if not len(font.family) > 0:
        continue
    for item in font.family:
        if item[1] == unicode(font_name):
            if len(font_style) == 0:
                match = "yes"
            else:
                for item in font.style:
                    if item[1] == unicode(font_style):
                        match = "yes"
            try:
                match
            except NameError:
                continue
            if all(font.has_char(c) for c in string):
                sys.exit(0)
            else:
                sys.exit(1)
print >> sys.stderr, "font not found: " + font_name + " " + font_style
sys.exit(1)
Ladiko
sumber