如何在CGContext中绘制正确的垂直文本?

How to draw proper vertical text in a CGContext?

提问人:Peter Nowell 提问时间:9/17/2023 最后编辑:Peter Nowell 更新时间:9/18/2023 访问量:74

问:

我需要使用垂直布局方向(即垂直的“书写方向”)绘制一个到一个。仅仅旋转水平排版的文本行是不够的,因为这不会激活垂直 OpenType 功能,也不会考虑字形应该在哪些脚本中是直立的(例如:中文)。NSAttributedStringCGContext

这已经可以通过 NSTextView 实现。通过设置 NSLayoutManager.TextLayoutOrientation 值,或者通过 UI 在视图内单击鼠标右键,可以是水平或垂直的布局方向。但我需要将文本绘制到 Core Graphics PDF 上下文中,而不是视图中NSTextView

我在 CoreText 中没有看到任何关于垂直排版的信息,但我猜 TextKit 能够做到这一点。TextKit 的 NSTextContainer 似乎可以被子类化为使用垂直方向,这似乎是难题的重要组成部分。我目前正在这样做:

class VerticalTextContainer: NSTextContainer {
    override var layoutOrientation: NSLayoutManager.TextLayoutOrientation { .vertical }
}

我是 TextKit 的新手,找不到很多人们将其与 CGContext 而不是视图一起使用的示例,因此我确定我的设置不正确。这是我的 TextKit 设置:

let attrString = NSAttributedString(
    string: "Hello 你好!"
)

/// The text box; the shape/frame to fill with the text.
let textContainer: NSTextContainer = VerticalTextContainer(size: NSSize(width: 300, height: 300) )

/// The part that handles laying out text elements, generating text layout fragments.
let textLayoutManager: NSTextLayoutManager = {
    var layoutManager = NSTextLayoutManager()
    layoutManager.textContainer = textContainer
    return layoutManager
}()

/// The part that stores the attributed string and connects to the layout manager.
let textContentStorage: NSTextContentStorage = {
    var storage = NSTextContentStorage()
    storage.attributedString = attrString
    storage.addTextLayoutManager( textLayoutManager )
    return storage
}()

然后,在我的 CGContext 中,我尝试了这个——但什么也没出现:

// inside a new 300x300 CGContext:

// prep:
cgContext.scaleBy(x: 1, y: -1)
cgContext.translateBy(x: 0, y: size.height * -1)
cgContext.textMatrix = .identity
cgContext.setFillColor( .black )

// try drawing the TextKit line fragments
textLayoutManager.enumerateTextLayoutFragments(
    from: textLayoutManager.documentRange.location,
    options: .ensuresLayout
) { textLayoutFragment in
    textLayoutFragment.draw(at: CGPoint(x: 100, y: 100), in: cgContext)
    return true
}

我尝试了许多变体,包括传递给枚举方法的参数,遍历每个参数并绘制每个参数,然后执行.似乎没有任何效果。我什至不确定是否正在创建布局片段。nilfrom:textLayoutFragment.textLineFragmentstextLayoutManager.ensureLayout(for: textLayoutFragment.rangeInElement)

任何帮助将不胜感激!

Swift Cocoa Core-Graphics TextKit 垂直文本

评论

0赞 Sweeper 9/17/2023
无论如何,制作一个,并将 的图层绘制到上下文中怎么样?参见 render(in:)NSTextViewNSTextView
0赞 Peter Nowell 9/17/2023
@Sweeper 我宁愿不创建视图的一个原因是因为我希望它从主线程运行。我也不需要交互性或视图的其他功能,这些功能可能会在要求苛刻的情况下降低性能。
0赞 Willeke 9/17/2023
如果您不更改布局方向、不缩放和不翻译,它是否有效?
0赞 Peter Nowell 9/17/2023
@Willeke 只是尝试了这些组合的每一种组合,但它们并没有改变结果。
0赞 Willeke 9/18/2023
我尝试了您的代码,并出现了(水平)文本。

答: 暂无答案