ค้นหาแบบอักษรที่ดีที่สุดสำหรับการเรนเดอร์ codepoint


16

วิธีการค้นหาแบบอักษรที่เหมาะสมสำหรับการแสดงผล codepoints Unicode?

gnome-terminalพบว่าตัวละครเช่น«🉃⼼😻🕲🝤»สามารถแสดงผลด้วยแบบอักษรเช่น Symbola มากกว่าแบบอักษรเทอร์มินัลของฉันหรือทางเลือกทางเลือก codepoint-in-square (????) ได้อย่างไร


เกี่ยวข้อง: askubuntu.com/questions/27598/…
Nathaniel M. Beaver

คำตอบ:


14

นี่ไม่ใช่วิธีที่ดีที่สุดและแน่นอนว่าไม่เป็นมิตรกับผู้ใช้ แต่มันง่ายที่จะทำงาน: นี่คือสคริปต์ Python ที่จะทำ

ติดตั้งไลบรารีPython-fontconfig รับจากการแจกจ่ายของคุณ (เช่นsudo apt-get install python-fontconfigDebian และอนุพันธ์) หรือติดตั้งในโฮมไดเร็กตอรี่ของคุณ ( pip install --user python-fontconfig). จากนั้นคุณสามารถเรียกใช้สคริปต์นี้ (บันทึกไว้fc-search-codepointในไดเรกทอรีบนของคุณPATH, เช่นโดยทั่วไป~/bin, และทำให้มันทำงานได้):

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

ตัวอย่างการใช้งาน:

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

ฉันไม่มีแบบอักษรใด ๆ กับตัวละครเหล่านี้ทั้งหมด

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

1
นั่นเป็นสคริปต์ที่มีประโยชน์มาก! อย่างไรก็ตามมันเป็นเพียง python2 ที่เข้ากันได้และฉันคิดว่ามันค่อนข้างน่ารังเกียจที่จะทำแบบพกพา คุณจะคิดอย่างน้อยเปลี่ยน#!/usr/bin/env pythonไป#!/usr/bin/env python2ตาม PEP 394
Zulan

1
ขอบคุณสำหรับคำตอบนี้! มันมีประโยชน์มาก ฉันแน่ใจว่าระบบปฏิบัติการหรือไลบรารีระบบที่ใช้ฟอนต์ fallback กำลังทำสิ่งที่มีประสิทธิภาพมากกว่า แต่ก็ใช้งานได้ @Zulan มันสามารถทำงานได้ด้วยpython3เช่นกัน ฉันเพิ่งเขียนรุ่นเล็กกว่านี้ที่ด้านล่างของคำตอบนี้
ShreevatsaR

5

ใช้ fontconfig

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

เช่น

> fc-list ':charset=2713 2717'

จะแสดงชื่อไฟล์แบบอักษรใด ๆ ที่มี✓และ✗

เพื่อให้ codepoint สอดคล้องกับการใช้อักขระ (ตัวอย่าง)

> printf "%x" \'✓
2713>

นี้ใช้คุณลักษณะที่ค่อนข้างคลุมเครือ ของPOSIX printfยูทิลิตี้ :

หากอักขระนำหน้าเป็นเครื่องหมายคำพูดเดี่ยวหรือเครื่องหมายคำพูดคู่ค่าจะเป็นค่าตัวเลขในชุดโค้ดพื้นฐานของอักขระตามเครื่องหมายคำพูดเดี่ยวหรือเครื่องหมายคำพูดคู่

นำมารวมกัน

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

นี้ใช้xargs -Iธงเพื่อแทนที่ที่มีชื่อจาก{} stdinดังนั้นสิ่งนี้จึงมีผลอย่างมากถึง:

> fc-list ":charset=2713"

2
ทราบว่าคุณต้องรุ่นของfontconfigที่อยู่2.11.91หรือในภายหลัง
นาธาเนียลเอ็มบีเวอร์

1
โปรดทราบว่าขีดกลางprintfและ/bin/printfไม่สนับสนุนนั้น
Steven Penny

1
! น่ากลัว ฉันหาข้อมูลนี้มานานแล้ว โปรดทราบว่าคุณยังสามารถระบุช่วงเช่นเดียวกับตัวอักษรเดียวดังนั้นเพื่อค้นหาแบบอักษรทั้งหมดที่มีอักขระวาดกล่องเช่น:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew

3

ในที่สุด gnome-terminal ใช้fontconfigเพื่อ (เหนือสิ่งอื่นใด):

... ค้นหาฟอนต์ที่คุณต้องการได้อย่างมีประสิทธิภาพและรวดเร็วในชุดฟอนต์ที่คุณติดตั้งแม้ว่าคุณจะติดตั้งฟอนต์หลายพัน ...

ในเอกสาร APIคุณสามารถค้นหาฟังก์ชั่นเพื่อสอบถามช่วงตัวอักษรแบบอักษรและสำหรับการดำเนินการกับช่วงตัวอักษร แต่เอกสารนั้นเป็นความลับที่ฉันไม่สามารถหาได้ว่าชุดของฟังก์ชั่นที่แตกต่างกันเกี่ยวข้องกันอย่างไร หากฉันต้องการดำน้ำลึกฉันอยากจะดูตัวอย่างการใช้งานในซอฟต์แวร์อื่นบางทีvte (ไลบรารีการจำลองเทอร์มินัลที่ใช้ใน gnome-terminal)

ห้องสมุดในระหว่างอีกVTEและfontconfigเป็นPango "... ห้องสมุดสำหรับการออกวางและการแสดงผลของข้อความด้วยการเน้นความเป็นสากลแล้ว ..." ตอนนี้ฉันคิดว่ามันฟังดูเหมือนจะมีเหตุผลส่วนใหญ่ที่คุณมีอยู่

ฟังก์ชั่นการครอบคลุมตัวละครใน pango นั้นถูกนำไปใช้โดยแผนที่ครอบคลุม ( "มันมักจะจำเป็นใน Pango เพื่อตรวจสอบว่าแบบอักษรเฉพาะสามารถเป็นตัวแทนของตัวละครที่เฉพาะเจาะจงและวิธีที่มันสามารถเป็นตัวแทนของตัวละครนั้นได้ดีเพียงใด PangoCoverage เพื่อแสดงข้อมูลนั้น " ) แต่อาจมีรายละเอียดที่ซับซ้อนมากขึ้นในการตัดสินใจว่า glyph สามารถแสดงผลด้วยแบบอักษรใดได้บ้าง ฉันเดาว่าVTE นั้นพึ่งพาpangoในการเรนเดอร์สตริงด้วยฟอนต์ที่เหมาะสมในขณะที่pangoใช้fontconfig (หรือแบ็กเอนด์ตัวอักษรอื่น ๆ ที่รองรับ) เพื่อค้นหาฟอนต์ที่เหมาะสมที่สุดโดยอิงตามตรรกะต่างๆในpangoเองและ / หรือแบ็กเอนด์


1

ฉันเปลี่ยนรหัสเพื่อตรวจสอบว่าแบบอักษรมีอักขระทั้งหมดของสตริงที่แน่นอนหรือไม่ ดังนั้นสิ่งนี้สามารถถูกเรียกใช้โดยfc-search-codepoint "$fontname" "$string"และส่งคืนโค้ดออก 0 เมื่อสำเร็จหรือ 1 เป็นอย่างอื่น ชื่อตัวอักษรสามารถเรียกข้อมูลจากfc-query /path/to/FontSandMonoBoldOblique.ttfหรือ convert -list fontImageMagick ฉันใช้มันเพื่อตรวจสอบว่าสตริงที่ผู้ใช้เลือกสามารถแสดงผลด้วยแบบอักษรที่ผู้ใช้เลือกและหากคำสั่งล้มเหลวจะใช้แบบอักษรสำรอง

#!/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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.