【问题标题】:Drawing Text with Core Graphics使用核心图形绘制文本
【发布时间】:2011-05-22 03:28:00
【问题描述】:

我需要将居中的文本绘制到 CGContext。

我从 Cocoa 方法开始。我用文本创建了一个 NSCell 并尝试绘制它:

NSGraphicsContext* newCtx = [NSGraphicsContext
     graphicsContextWithGraphicsPort:bitmapContext flipped:true];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:newCtx];
[pCell setFont:font];
[pCell drawWithFrame:rect inView:nil];
[NSGraphicsContext restoreGraphicsState];

但是 CGBitmapContext 似乎没有在其上呈现文本。可能是因为我必须为 inView: 参数传递 nil。

所以我尝试将文本渲染切换到 Core Graphics:

最简单的方法似乎是使用 CGContextSelectFont 使用它的 postscript 名称和点大小来选择字体,但是 CGContextShowTextAtPoint 只接受非 unicode 字符,并且没有明显的方法可以将文本适应矩形:或计算一行文本的范围以手动布置矩形。

然后,有一个可以创建的CGFont,并设置cia CGContextSetFont。绘制此文本需要 CGContextShowGlyphsAtPoint,但 CGContext 似乎又缺少计算生成文本的边界矩形或将文本包装到矩形的函数。另外,如何将字符串转换为 CGGlyphs 数组并不明显。

下一个选项是尝试使用 CoreText 来呈现字符串。但是 Core Text 类非常复杂,虽然有示例展示了如何以指定的字体、矩形显示文本,但没有示例展示如何计算 CoreText 字符串的边界矩形。

所以:

  • 给定一个 CGFont 一个 CGContext 如何计算某些文本的边界矩形,以及如何将文本字符串转换为 CGGlyphs 数组?
  • 给定一个字符串、一个 CGContext 和一个 postscript 名称和磅值,我需要创建哪些 Core Text 对象来计算字符串的边界矩形,和/或绘制包装到 CGContext 上的矩形的字符串。
  • 给定一个字符串和一个 NSFont - 如何将字符串渲染到 CGBitmapContext 上?我已经知道如何获取它的范围。

【问题讨论】:

  • 你能画一个期望结果的例子吗?
  • 也许,但是想要的结果很简单——我想在一个矩形中绘制一个带有字体(面和点大小)的字符串。字符串必须被换行,并且我必须能够选择行是左对齐、居中还是右对齐,并且段落是顶部对齐、居中还是底部对齐。

标签: cocoa core-graphics core-text


【解决方案1】:

我会继续使用您的上述方法,但改用 NSAttributedString。

NSGraphicsContext* newCtx = [NSGraphicsContext graphicsContextWithGraphicsPort:bitmapContext flipped:true];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:newCtx];
NSAttributedString *string = /* make a string with all of the desired attributes */;
[string drawInRect:locationToDraw];
[NSGraphicsContext restoreGraphicsState];

【讨论】:

  • NSGraphicsContext 和您使用的对齐 API 如何与 CGContext 及其自己的 API 兼容?这些可以混合吗?我的代码是跨平台 SDK 的一部分,它应该同时运行 iOS MacOS 等,因此我将自己限制在 CoreGraphics API 上——您能否增强您在 CGBitmapContext 上工作的答案?
【解决方案2】:

经过 4 天的搜索,我终于找到了答案。我真的希望 Apple 制作更好的文档。所以我们开始吧

我假设你已经有了 CGFontRef。如果不让我知道,我会告诉你如何将资源包中的 ttf 加载到 CgFontRef 中。

下面是代码 sn-p 用任何 CGFontref 计算任何字符串的边界

        int charCount = [string length];
        CGGlyph glyphs[charCount];
        CGRect rects[charCount];

        CTFontGetGlyphsForCharacters(theCTFont, (const unichar*)[string cStringUsingEncoding:NSUnicodeStringEncoding], glyphs, charCount);
        CTFontGetBoundingRectsForGlyphs(theCTFont, kCTFontDefaultOrientation, glyphs, rects, charCount);

        int totalwidth = 0, maxheight = 0;
        for (int i=0; i < charCount; i++)
        {
            totalwidth += rects[i].size.width;
            maxheight = maxheight < rects[i].size.height ? rects[i].size.height : maxheight;
        }

        dim = CGSizeMake(totalwidth, maxheight);

重复使用相同的函数 CTFontGetGlyphsForCharacters 来获取字形。要从 CGFontRef 获取 CTFontRef,请使用 CTFontCreateWithGraphicsFont() 函数

还请记住,NSFont 和 CGFontRef 是免费桥接的,这意味着它们可以相互转换,并且无需任何额外工作即可无缝工作。

【讨论】:

  • 但是您遗漏了实际答案...如何在矩形中实际绘制该文本...您问题中的代码使用 AppKit (NS) API,以及您的问题(以及我的要求。 ..) 是在 CGBitmapContext 上绘制文本,仅使用 CoreGraphics API(以便跨 iOS/MacOS)。你能扩大一点吗?
【解决方案3】:

Swift 5 版本!

let targetSize: CGSize = // the space you have available for drawing the text
let origin: CGPoint = // where you want to position the top-left corner
let string: String = // your string
let font: UIFont = // your font

let attrs: [NSAttributedString.Key:Any] = [.font: font]
let boundingRect = string.boundingRect(with: targetSize, options: [.usesLineFragmentOrigin], attributes: attrs, context: nil)
let textRect = CGRect(origin: origin, size: boundingRect.size)
text.draw(with: textRect, options: [.usesLineFragmentOrigin], attributes: attrs, context: nil)

【讨论】:

    猜你喜欢
    • 2012-03-23
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多