确定UIFont中是否有Unicode字符的字形

4

我想确定某个Unicode字符是否具有字形表示,即使是通过级联字体。例如,假设我正在使用UIFont.systemFont(withSize:18)和一个字符串\u{1CDA},并且想要找出此字体是否会显示此字符的图形表示,而不是默认的问号表示(即没有图形表示,即使是支持级联字体)。


1
可能是重复的问题:如何检测Unicode字符无法正确显示 - Martin R
1
@MartinR 为什么不用你的锤子? - JAL
@JAL:因为我自己没有遇到过这个问题,所以在得到 OP 或其他人的确认后,我会立即进行复制锤操作。 - Martin R
@MartinR 我看到了那个问题并使用了它的解决方案,但它只返回了特定字体的一个字形。 - andrewz
3个回答

3
这对我有用。Swift 3,XCode 8.6版本:
import UIKit
import CoreText

extension Font {
    public func hasGlyph(utf32 character:UInt32) -> Bool {

        var code_point: [UniChar] = [
            UniChar.init(truncatingBitPattern: character),
            UniChar.init(truncatingBitPattern: character >> 16)
        ]
        var glyphs: [CGGlyph] = [0,0]
        let result = CTFontGetGlyphsForCharacters(self as CTFont, &code_point, &glyphs, glyphs.count)
        return result
    }
}

public class Glypher {

    let font:UIFont

    var support:[CTFont] = []

    public init(for font:UIFont, languages:[String] = ["en"]) {
        self.font = font
        let languages = languages as CFArray
        let result = CTFontCopyDefaultCascadeListForLanguages(font as CTFont, languages)
        let array = result as! Array<CTFontDescriptor>
        for descriptor in array {
            support.append(CTFontCreateWithFontDescriptor(descriptor,18,nil))
        }
    }

    public func isGlyph(_ point:UInt32) -> Bool {
        return font.hasGlyph(utf32:point) || isGlyphSupported(point)
    }

    public func isGlyphSupported(_ point:UInt32) -> Bool {
        for font in support {
            var code_point: [UniChar] = [
                UniChar.init(truncatingBitPattern: point),
                UniChar.init(truncatingBitPattern: point >> 16)
            ]
            var glyphs: [CGGlyph] = [0, 0]
            let result = CTFontGetGlyphsForCharacters(font as CTFont, &code_point, &glyphs, glyphs.count)
            if result {
                return true
            }
        }
        return false
    }
}

let glypher = Glypher(for:UIFont.systemFont(ofSize:18))
if glypher.isGlyph(0x1CDA) {
    print("bingo!")
}

当使用Ingra-Book和iPhone 7模拟器测试此代码时,UTF-8 BMP空间中的许多测试案例都会使CTFontGetGlyphsForCharacters返回false。该字体具有1628个字形(CTFontGetGlyphCount)。所有匹配都使用备用支持字体。这个字体可能没有真正安装吗?Swift 3.1,Xcode 8.3.3.,iPhone 7模拟器。任何建议都将非常有帮助。 - Jason Harrison

1
这也可能有效,它不检查字形,但会检查字符集。
import CoreText
func isSupported(unicode: UnicodeScalar, font: UIFont) -> Bool {
    let coreFont: CTFont = font
    let characterSet: CharacterSet = CTFontCopyCharacterSet(coreFont) as CharacterSet
    return characterSet.contains(unicode)
 }

示例测试:

let testString = "R"
let font = UIFont.boldSystemFont(ofSize: 10.0)
print("\(isSupported(unicode: testString.unicodeScalars.first!, font: font))")

0

这是基于@andrewz的答案进行了大量修改,所以大部分功劳归于他们!我发现某些表情符号会导致错误的负面结果(包括✋),因此我进行了一些修改,包括将表情符号作为String传递:

注意:我使用了Font而不是UIFont,因为我在iOS和macOS上都使用它,所以有一个类型别名来在两个字体类之间切换,您可以根据自己选择的平台添加前缀NSUI!)

extension Font {
    
    func canRender(emoji: String) -> Bool {
        var code_points = Array(emoji.utf16)
        var glyphs: [CGGlyph] = Array(repeating: 0, count: code_points.count)
        return CTFontGetGlyphsForCharacters(self as CTFont, &code_points, &glyphs, glyphs.count)
    }
    
}

class Glypher {

    private let font: Font
    private var support: [CTFont] = []

    init(for font: Font, languages: [String] = ["en"]) {
        self.font = font
        let languages = languages as CFArray
        let result = CTFontCopyDefaultCascadeListForLanguages(font as CTFont, languages)
        let array = result as! Array<CTFontDescriptor>
        for descriptor in array {
            support.append(CTFontCreateWithFontDescriptor(descriptor, 18, nil))
        }
    }

    func isRenderable(emoji: String) -> Bool {
        return font.canRender(emoji: emoji) || renderSupported(emoji: emoji)
    }

    func renderSupported(emoji: String) -> Bool {
        var code_points = Array(emoji.utf16)
        var glyphs: [CGGlyph] = Array(repeating: 0, count: code_points.count)
        for font in support where CTFontGetGlyphsForCharacters(font as CTFont, &code_points, &glyphs, glyphs.count) {
            return true
        }
        return false
    }
    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接