如何确定字体是符号字体还是文本字体

时间:2017-12-30 01:50:59

标签: python fonts kivy python-imaging-library

我正在构建一个kivy应用程序,需要包含一个字体选择器。由于我找不到一个kivy,我正在建立自己的。但我找不到一种方法来判断一个字体是否对我有用(也就是说,我可以用它来制作一个句子而不是一串符号)。我正在使用Pillow ImageFont。有没有办法在python中区分符号和文本字体?

2 个答案:

答案 0 :(得分:1)

一直在努力,我现在对自己的工作感到高兴。仍然不完美,但以下代码只给我一个误报,支持我的Ubuntu盒子上的文字字体:

def isValidFont(f, fontNum=0, debug=False):
    """
    Determine if a font is a valid font for displaying text

    This code makes a best guess as to whether the font supports text.
    It does this by writing a 'W' using the font, and inspecting the result.

    :param f: full path to the font file
    :param fontNum: index into the font file (for a file containing a collection of fonts)
    :param debug: If True, files will be written for each font with information useful for debugging
    :return: True if font appears to support text, False otherwise
    """

    # size of test image
    width = 40
    height = 40

    font = ImageFont.truetype(f, index=fontNum, size=height-6)
    fontName = font.getname()
    tmpImg = Image.new('1', (width,height)) #default fill is 0 (black)

    # draw a single 'W' into the test image (sized and positioned to fit inside test image)
    # this codes depends on the character drawn being a 'W'
    dr = ImageDraw.Draw(tmpImg)
    dr.text((3, 3), 'W', font=font, fill=(1))

    if debug:
        # save test image for this font
        fname = str(fontName) + '.bmp'
        tmpImg.save(fname)

    # get the data from the image as a list of 1's and 0's (one value per pixel)
    img_data = list(tmpImg.getdata())

    if debug:
        # write the image data to a file
        fname = str(fontName) + '.txt'
        fd = open(fname, mode='w')
        for row in range(height):
            fd.write(str(img_data[row*width : (row+1)*width]) + '\n')
        fd.close()

    # if the image is all black (0's), this is not a valid text font
    if sum(img_data) == 0:
        return False

    # build a simplified version of the image data
    compressedList = []
    for i in range(height):
        prev_elem = None
        thisRow = []
        for j in range(width):
            index = i*width + j
            elem = img_data[index] # this is the element at (i,j)
            if prev_elem is None:
                # first element in this row, just append to "thisRow"
                thisRow.append(elem)
                prev_elem = elem
            elif elem == prev_elem:
                # if this element is same as previous (and it's a one), just increment the value in "thisRow"
                if elem == 1:
                    thisRow[len(thisRow)-1] += 1
            else:
                # just append the element to "thisRow"
                thisRow.append(elem)
                prev_elem = elem
        # finished row #i, append it to "compressedList"
        compressedList.append(thisRow)

    # a bit more compressing
    for row in compressedList:
        # eliminate leading zeros from each row
        while len(row) > 0 and row[0] == 0:
            del row[0]

        # eliminate trailing zeros from each row
        while len(row) > 0:
            index = len(row)-1
            if row[index] == 0:
                del row[index]
            else:
                break

    # eliminate leading empty rows
    while len(compressedList[0]) == 0:
        del compressedList[0]

    # eliminate trailing empty rows
    index = len(compressedList)-1
    while len(compressedList[index]) == 0:
        del compressedList[index]
        index = len(compressedList)-1

    if debug:
        # save the compressed format
        fname = str(fontName) + '_c.txt'
        fd = open(fname, mode='w')
        for row in compressedList:
            fd.write(str(row) + '\n')
        fd.close()

    # this is where the decision is actually made
    for row in compressedList:
        if len(row) > 3: # characteristic of a 'W', a simple box will have maximum rowLen of 3
            return True
    return False

答案 1 :(得分:0)

我不是这方面的专家,但在这里我是如何看待事物的。

当您尝试使用字体书写一些字母时,渲染器将使用此字母code point从字体文件中获取绘图说明。可能有3种情况:

  1. 存在代码点指令,但包含错误的图像。对于 例如,代码点0x0041而不是包含指令 绘制拉丁文大写字母" A" font包含绘制的指令 一些表情符号。
  2. 存在代码点说明并包含正确的图像。
  3. 代码点的说明不存在。
  4. 在第一种情况下,你没有选择:只有人类(或非常高级的脚本)可以说"这一组像素包含表情符号而不是字母"。但这种情况应该很少见:这不是(正常)人们如何创建符号字体。

    第二种情况很简单:这个字体没问题,你可以使用它。

    第三种情况更有趣。有时候人们会为unicode图像(for example)留下代码点,但会删除字母说明以减少字体文件的大小。 ImageFont似乎没有特定的方法来通过代码点提取信息,但它allows us来获取文本掩码。可以通过字体绘制的文本掩码将具有(0, 0)大小:

    from PIL import ImageFont
    
    
    font = ImageFont.truetype("font_to_test.ttf")
    
    mask = font.getmask('abcdefg')  # use some letters from lang you need
    
    if mask.size == (0, 0):
        print('This is image font.')
    else:
        print('This is text font.')
    

    不太理想,但我测试了几种字体的工作。