代码之家  ›  专栏  ›  技术社区  ›  John Anderson

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

  •  4
  • John Anderson  · 技术社区  · 7 年前

    我正在构建一个kivy应用程序,需要包含一个字体选择器。因为我找不到一个给kivy的,所以我正在建立自己的。但我找不到一种方法来判断字体是否对我有用(例如,我可以用它来造句,而不是用一串符号)。我正在使用枕头图像字体。在python中,有没有办法描述符号和文本字体之间的关系?

    2 回复  |  直到 7 年前
        1
  •  1
  •   John Anderson    7 年前

    我一直在努力,现在我对我的工作有点满意了。仍然不完美,但下面的代码只对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
    
        2
  •  0
  •   Mikhail Gerasimov    7 年前

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

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

    1. 代码点的指令存在,但包含错误的图像。对于 例如,对于代码点 0x0041 而不是包含说明 绘制拉丁文大写字母“A”的步骤字体包含绘制说明 一些表情符号。
    2. 代码点的指令存在并包含正确的图像。
    3. 代码点的指令不存在。

    在第一种情况下,您没有选择:只有人类(或非常高级的脚本)可以说“这组像素包含表情符号而不是字母”。但这种情况应该很少见:这不是(正常)人创建符号字体的方式。

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

    第三种情况更有趣一些。有时人们会留下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.')
    

    不太理想,但在我测试的几种字体上都可以。