string - 如何将 swift String 转换为 CGGlyph 数组

标签 string swift glyph typesetting

此代码段可用于使用 CGContext 绘制 CGGlyphs。

    //drawing
    let coreGraphicsFont = CTFontCopyGraphicsFont(coreTextFont, nil)
    CGContextSetFont(context, coreGraphicsFont);
    CGContextSetFontSize(context, CTFontGetSize(coreTextFont))
    CGContextSetFillColorWithColor(context, Color.blueColor().CGColor)          
    CGContextShowGlyphsAtPositions(context, glyphs, positions, length)

但是我如何从包含标志或重音字符等表情符号的 swift 字符串中获取 CGGlyphs?

let string = "swift: \u{1F496} \u{65}\u{301} \u{E9}\u{20DD} \u{1F1FA}\u{1F1F8}"

这些方法都没有显示特殊字符,即使它们被正确地打印到控制台。请注意,第一种方法返回 NSGlyph,但绘图需要 CGGlyph。

    var progress = CGPointZero
    for character in string.characters
    {
        let glyph = font.glyphWithName(String(character))
        glyphs.append(CGGlyph(glyph))
        let advancement = font.advancementForGlyph(glyph)
        positions.append(progress)
        progress.x += advancement.width
    }

或者需要转换为 NSString 的第二种方法:

    var buffer = Array<unichar>(count: length, repeatedValue: 0)
    let range = NSRange(location: 0, length: length)
    (string as NSString).getCharacters(&buffer, range: range)

    glyphs = Array<CGGlyph>(count: length, repeatedValue: 0)
    CTFontGetGlyphsForCharacters(coreTextFont, &buffer, &glyphs, length)

    //glyph positions
    advances = Array<CGSize>(count: length, repeatedValue: CGSize.zero)
    CTFontGetAdvancesForGlyphs(ctFont, CTFontOrientation.Default, glyphs, &advances, length)
    positions = []
    var progress = CGPointZero
    for advance in advances
    {
        positions.append(progress)
        progress.x += advance.width
    }

某些字符在任一方法中都被绘制为空框。有点卡在这里,希望你能帮忙。

编辑:

使用 CTFontDrawGlyphs 可以正确呈现字形,但在调用 CGContextShowGlyphsAtPositions 之前直接设置字体、大小和文本矩阵不会绘制任何内容。我觉得这很奇怪。

最佳答案

如果您自己生成字形,您还需要自己执行字体替换。当您使用 Core Text 或 TextKit 布局和绘制文本时,它们会为您执行字体替换。例如:

let richText = NSAttributedString(string: "Hello😀→")
let line = CTLineCreateWithAttributedString(richText)
print(line)

输出:

<CTLine: 0x7fa349505f00>{run count = 3, string range = (0, 8), width = 55.3457, A/D/L = 15/4.6875/0, glyph count = 7, runs = (

<CTRun: 0x7fa34969f600>{string range = (0, 5), string = "Hello", attributes = <CFBasicHash 0x7fa3496902d0 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153bb720 [0x10e85a7b0]>{contents = "NSFont"} = <CTFont: 0x7fa3496182f0>{name = Helvetica, size = 12.000000, matrix = 0x0, descriptor = <CTFontDescriptor: 0x7fa34968f860>{attributes = <CFBasicHash 0x7fa34968f8b0 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153c16c0 [0x10e85a7b0]>{contents = "NSFontNameAttribute"} = <CFString 0x1153b4700 [0x10e85a7b0]>{contents = "Helvetica"}
}
>}}
}
}


<CTRun: 0x7fa3496cde40>{string range = (5, 2), string = "\U0001F600", attributes = <CFBasicHash 0x7fa34b11a150 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153bb720 [0x10e85a7b0]>{contents = "NSFont"} = <CTFont: 0x7fa3496c3eb0>{name = AppleColorEmoji, size = 12.000000, matrix = 0x0, descriptor = <CTFontDescriptor: 0x7fa3496a3c30>{attributes = <CFBasicHash 0x7fa3496a3420 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153c16c0 [0x10e85a7b0]>{contents = "NSFontNameAttribute"} = <CFString 0x11cf63bb0 [0x10e85a7b0]>{contents = "AppleColorEmoji"}
}
>}}
}
}


<CTRun: 0x7fa3496cf3e0>{string range = (7, 1), string = "\u2192", attributes = <CFBasicHash 0x7fa34b10ed00 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153bb720 [0x10e85a7b0]>{contents = "NSFont"} = <CTFont: 0x7fa3496cf2c0>{name = PingFangSC-Regular, size = 12.000000, matrix = 0x0, descriptor = <CTFontDescriptor: 0x7fa3496a45a0>{attributes = <CFBasicHash 0x7fa3496a5660 [0x10e85a7b0]>{type = mutable dict, count = 1,
entries =>
    2 : <CFString 0x1153c16c0 [0x10e85a7b0]>{contents = "NSFontNameAttribute"} = <CFString 0x11cf63230 [0x10e85a7b0]>{contents = "PingFangSC-Regular"}
}
>}}
}
}

)
}

我们可以在这里看到 Core Text 识别出默认字体 (Helvetica) 没有表情符号或箭头的字形,因此它将一行分成三行,每行都有所需的字体。

Core Text Programming Guide是这样说的:

Most of the time you should just use a CTLine object to get this information because one font may not encode the entire string. In addition, simple character-to-glyph mapping will not get the correct appearance for complex scripts. This simple glyph mapping may be appropriate if you are trying to display specific Unicode characters for a font.

最好的办法是使用 CTLineCreateWithAttributedString 生成字形并选择字体。然后,如果您想要调整字形的位置,请使用 CTLineGetGlyphRuns 获取行外的运行,然后向运行请求字形、字体和您需要的任何其他内容。

如果您想自己处理字体替换,我想您会想要查看 “font cascading” .

关于string - 如何将 swift String 转换为 CGGlyph 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33424757/

相关文章:

ios - 模糊覆盖不会覆盖整个屏幕

php - 如何在 Swift 或 Php 中将核心数据编码为 JSON(不带斜线)

java - Font.canDisplay 在 mac 上总是返回 true

c++ - 将文本转换为网格

c - 函数没有通过某些测试用例

Javascript 字符串转二维数组

ios - 定义 Bundle.main.url 以在 iOS9 及以上版本的 Swift 4 中使用 Core Data

listview - 如何在 .NET ListView 中设置标题排序字形?

C char指针获取特定字符

c - 如何在C中将字符串添加到二维数组