I want to find out if a certain unicode character has a glyph representation even if by a cascading font. For example, let's say I am using UIFont.systemFont(withSize:18) and a string \u{1CDA} and would like to find out if this font will display the graphical representation of this character, and not a default question mark representation (ie there's no graphical representation, even by the supporting cascade fonts).
Asked
Active
Viewed 1,621 times
3
andrewz
- 4,070
- 4
- 44
- 61
-
1Possible duplicate of [Detect when a unicode character cannot be displayed correctly](http://stackoverflow.com/questions/31363211/detect-when-a-unicode-character-cannot-be-displayed-correctly) – Martin R Mar 01 '17 at 19:38
-
1@MartinR why not use your hammer? – JAL Mar 01 '17 at 19:39
-
@JAL: Because I have no experience with that problem myself. I'll dupe hammer it as soon as some confirmation from OP or someone else comes. – Martin R Mar 01 '17 at 19:42
-
@MartinR I saw that question and am using it's solution, but it returns only a glyph of that specific font. – andrewz Mar 01 '17 at 21:24
2 Answers
2
This works for me. Swift 3, XCode 8.6 version:
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!")
}
andrewz
- 4,070
- 4
- 44
- 61
-
When testing this code using Ingra-Book and the iPhone 7 simulator CTFontGetGlyphsForCharacters returns false for a number of test cases across the UTF-8 BMP space. The font has 1628 glyphs (CTFontGetGlyphCount). The backup support fonts are used for all matches. Could the font not be truly installed? Swift 3.1, Xcode 8.3.3., iPhone 7 simulator. Any suggestions would be helpful. – Jason Harrison Nov 17 '17 at 18:07
1
This may work too, it doesn't check the glyph, but it checks the character set
import CoreText
func isSupported(unicode: UnicodeScalar, font: UIFont) -> Bool {
let coreFont: CTFont = font
let characterSet: CharacterSet = CTFontCopyCharacterSet(coreFont) as CharacterSet
return characterSet.contains(unicode)
}
Example test:
let testString = "R"
let font = UIFont.boldSystemFont(ofSize: 10.0)
print("\(isSupported(unicode: testString.unicodeScalars.first!, font: font))")
Jason Harrison
- 830
- 9
- 27