首页 > 解决方案 > 给定具有任何pointSize的UIFont,如何计算适当的笔划宽度?

问题描述

我想将单个实线笔划应用于文本。这很容易通过NSAttributedString指定.strokeWidth. 但是,我发现确定strokeWidth应该UIFont在任何给定的情况下呈现什么是棘手的pointSize。我可以很容易地说,在点大小为 50 时,笔画宽度为 1 看起来很棒。我直观地假设,如果将字体大小加倍,则应该将笔划宽度加倍,因此当字体缩放时,笔划将按比例缩放,并导致笔划粗细看起来与原始“基本”字体大小一致。然而,这不是发生的事情。随着字体大小和笔画宽度成比例增加,笔画宽度变得太粗了。

在此处输入图像描述

此处的屏幕截图显示第一行的字体大小为 50,笔划宽度为 1。下一行被加倍,因此字体大小为 100,笔划宽度为 2,并重复此操作,直到最后一行是 350 vs 7。

我相信这是因为笔画是向内和向外渲染的。它的中心位于角色的边缘,然后向两个方向扩展。如果您比较这两张图片,您可以看到这一点,这张没有应用笔划。

在此处输入图像描述

因此,随着字体大小的增加,笔划宽度不应按比例增加,它需要以较慢的速度增加,以确保所有尺寸的粗细一致。我正在尝试确定计算此值的正确方法。

所以给定一个看起来很理想的基本配置(比如说 50pt 字体大小和 1pt 笔划宽度)和一个新配置pointSize(例如 350pt),你如何计算正确的strokeWidth?或者也许我不应该使用不同的值pointSize

我当前按比例缩放的算法是:(
let strokeWidth = font.pointSize / 50只需求解 x in 1/50 = x/pointSize

这是我用来绘制此文本的代码:

    let text = "hello"
    let imageRect = CGRect(x: 0, y: 0, width: 343 * 3, height: 500 * 3)

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let alphaInfo = CGImageAlphaInfo.premultipliedLast.rawValue

    let bitmapContext = CGContext(data: nil, width: Int(imageRect.width), height: Int(imageRect.height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: alphaInfo)!
    bitmapContext.setAlpha(1)
    bitmapContext.setTextDrawingMode(CGTextDrawingMode.fill)

    //1
    bitmapContext.textPosition = CGPoint(x: 40, y: 1080)
    let displayLineText1 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 50), .strokeColor: UIColor.red, .strokeWidth: 1]))
    CTLineDraw(displayLineText1, bitmapContext)

    //2
    bitmapContext.textPosition = CGPoint(x: 40, y: 1000)
    let displayLineText2 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 100), .strokeColor: UIColor.red, .strokeWidth: 2]))
    CTLineDraw(displayLineText2, bitmapContext)

    //3
    bitmapContext.textPosition = CGPoint(x: 40, y: 875)
    let displayLineText3 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 150), .strokeColor: UIColor.red, .strokeWidth: 3]))
    CTLineDraw(displayLineText3, bitmapContext)

    //4
    bitmapContext.textPosition = CGPoint(x: 40, y: 725)
    let displayLineText4 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 200), .strokeColor: UIColor.red, .strokeWidth: 4]))
    CTLineDraw(displayLineText4, bitmapContext)

    //5
    bitmapContext.textPosition = CGPoint(x: 40, y: 540)
    let displayLineText5 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 250), .strokeColor: UIColor.red, .strokeWidth: 5]))
    CTLineDraw(displayLineText5, bitmapContext)

    //6
    bitmapContext.textPosition = CGPoint(x: 40, y: 310)
    let displayLineText6 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 300), .strokeColor: UIColor.red, .strokeWidth: 6]))
    CTLineDraw(displayLineText6, bitmapContext)

    //7
    bitmapContext.textPosition = CGPoint(x: 40, y: 40)
    let displayLineText7 = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 350), .strokeColor: UIColor.red, .strokeWidth: 7]))
    CTLineDraw(displayLineText7, bitmapContext)

    let textCGImage = bitmapContext.makeImage()!
    let textImage = CIImage(cgImage: textCGImage)

标签: iosnsattributedstringuifontstroke

解决方案


从(重点添加)的文档中:.strokeWidth

该属性的值是一个NSNumber包含浮点值的对象。此值表示更改笔画宽度的量,并指定为字体点大小的百分比。指定 0(默认值)表示不进行其他更改。指定正值以单独更改笔划宽度。指定负值来描边和填充文本。例如,轮廓文本的典型值为 3.0。

因此,该值已经缩放到字体大小。您也不应该自己缩放它。选择一个值,该值可以在任何给定字体大小下给出您喜欢的相对笔画宽度,并将其用于所有字体大小。


推荐阅读