Tìm phông chữ tốt nhất để hiển thị một mật mã


16

Làm thế nào để tìm phông chữ thích hợp để hiển thị các điểm mã unicode?

gnome-terminalthấy rằng các ký tự như «⼼» có thể được hiển thị bằng các phông chữ như Symbola chứ không phải phông chữ đầu cuối của tôi hoặc dự phòng mã hóa trong quảng trường (????). Làm sao ?


Câu trả lời:


14

Đây không hẳn là phương pháp tốt nhất và chắc chắn nó không thân thiện với người dùng, nhưng thật dễ dàng để làm việc: đây là tập lệnh Python để thực hiện.

Cài đặt thư viện Python-fontconfig . Hoặc lấy nó từ bản phân phối của bạn (ví dụ: sudo apt-get install python-fontconfigtrên Debian và các công cụ phái sinh) hoặc cài đặt nó trong thư mục chính của bạn ( pip install --user python-fontconfig). Sau đó, bạn có thể chạy tập lệnh này (lưu nó như fc-search-codepointtrong một thư mục trên PATH, ví dụ ~/bin, và làm cho nó có thể thực thi được):

#!/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)

Ví dụ sử dụng:

$ fc-search-codepoint 🉃⼼😻🕲🝤
$ echo $?
1

Tôi không có bất kỳ phông chữ nào với tất cả các ký tự này.

$ fc-search-codepoint U+1F64D
/usr/share/fonts/truetype/unifont/unifont_upper.ttf
/usr/share/fonts/truetype/unifont/unifont_upper_csur.ttf

1
Đó là một kịch bản rất hữu ích! Tuy nhiên, nó chỉ tuân thủ python2 và tôi cho rằng sẽ hơi khó chịu khi thực hiện chính xác việc di động đó. Bạn sẽ nhớ ít nhất thay đổi #!/usr/bin/env pythonđể #!/usr/bin/env python2theo PEP 394.
Zulan

1
Cảm ơn câu trả lời này! Nó rất hữu ích. Tôi chắc rằng hệ điều hành hoặc thư viện hệ thống thực hiện dự phòng phông chữ đang làm việc gì đó hiệu quả hơn, nhưng điều này hoạt động. @Zulan Nó có thể được thực hiện để làm việc với python3quá; Tôi chỉ viết một phiên bản nhỏ hơn ở dưới cùng của câu trả lời này .
ShreevatsaR

5

Sử dụng fontconfig,

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

ví dụ

> fc-list ':charset=2713 2717'

sẽ hiển thị bất kỳ tên tệp phông chữ nào chứa ✓ và.

Để lấy mật mã tương ứng với việc sử dụng ký tự (ví dụ)

> printf "%x" \'✓
2713>

Điều này sử dụng một tính năng hơi khó hiểu của tiện ích POSIXprintf :

Nếu ký tự đầu là một trích dẫn đơn hoặc trích dẫn kép, giá trị sẽ là giá trị số trong bộ mã cơ bản của ký tự theo sau trích dẫn đơn hoặc trích dẫn kép.

Lấy nhau

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

Điều này sử dụng xargs -Icờ để thay thế {}bằng tên từ stdin. Vì vậy, điều này có hiệu quả sôi xuống:

> fc-list ":charset=2713"

2
Lưu ý rằng bạn cần một phiên bản fontconfigđó là 2.11.91hoặc muộn hơn .
Nathaniel M. Beaver

1
lưu ý rằng dấu gạch ngang printf/bin/printfkhông hỗ trợ điều đó
Steven Penny

1
Tuyệt vời! Tôi đã tìm kiếm thông tin về điều này trong một thời gian dài. Lưu ý rằng bạn cũng có thể chỉ định phạm vi cũng như các ký tự đơn, vì vậy, để tìm tất cả các phông chữ có tất cả các ký tự vẽ hộp, ví dụ:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew

3

Cuối cùng gnome-terminal sử dụng fontconfig để (trong số những thứ khác):

... hiệu quả và nhanh chóng tìm thấy các phông chữ bạn cần trong số các phông chữ bạn đã cài đặt, ngay cả khi bạn đã cài đặt hàng ngàn phông chữ ...

Trong tài liệu API, bạn có thể tìm thấy các hàm để truy vấn phạm vi ký tự phông chữ và cho các hoạt động trên phạm vi ký tự, nhưng tài liệu này rất khó hiểu đến nỗi tôi không bao giờ có thể hiểu được các bộ hàm khác nhau có liên quan với nhau như thế nào. Nếu tôi cần lặn sâu hơn, tôi sẽ xem xét các ví dụ về việc sử dụng trong phần mềm khác, có lẽ là vte (thư viện mô phỏng đầu cuối được sử dụng trong gnome-terminal).

Một thư viện khác ở giữa vtefontconfigpango "... một thư viện để bố trí và kết xuất văn bản, với trọng tâm là quốc tế hóa ..." . Bây giờ tôi nghĩ về nó, nó có vẻ như là thứ chứa hầu hết logic mà bạn theo đuổi.

Chức năng bao phủ ký tự trong pango được triển khai bằng các bản đồ vùng phủ sóng ( "Pango thường cần thiết để xác định xem một phông chữ cụ thể có thể đại diện cho một ký tự cụ thể hay không và nó có thể biểu thị ký tự đó tốt như thế nào. PangoCoverage là một cấu trúc dữ liệu được sử dụng để thể hiện thông tin đó. " ), nhưng có lẽ có nhiều chi tiết phức tạp hơn liên quan đến việc quyết định glyph sẽ kết xuất với phông chữ nào. Tôi đoán VTE dựa vào pango để kết xuất các chuỗi có phông chữ phù hợp trong khi pango sử dụng fontconfig (hoặc phụ trợ phông chữ được hỗ trợ khác) để tìm phông chữ phù hợp nhất dựa trên nhiều logic khác nhau trong chính pango và / hoặc phụ trợ.


1

Tôi đã thay đổi mã để kiểm tra xem một phông chữ có chứa tất cả các ký tự của một chuỗi nhất định hay không. Vì vậy, điều này có thể được gọi bởi fc-search-codepoint "$fontname" "$string"và nó trả về mã thoát 0 khi thành công hoặc 1 nếu không. Tên phông chữ có thể được lấy từ fc-query /path/to/FontSandMonoBoldOblique.ttfhoặc của Imagemagick convert -list font. Tôi sử dụng nó để kiểm tra xem một chuỗi người dùng đã chọn có thể được hiển thị với phông chữ do người dùng chọn hay không và nếu lệnh bị lỗi, phông chữ dự phòng sẽ được sử dụng.

#!/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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.