将 CATextLayer 与 CGContext 结合使用

发布于 2024-12-28 13:10:48 字数 4227 浏览 1 评论 0原文

我需要将文本绘制到 CGContext 中,并希望使用 CATextLayer 来设置文本。谁能给我一些关于如何完成的步骤。我已经为它编写了一些代码,但不知道它的正确性(因为我是iPhone开发的新手)。

一些基本问题: 1.如何获取设置CATextLayer框架的文本位置和大小 2. 文本以某种方式出现倒置,我已使用 CGAffineTransform 修复了该问题,但这是一个黑客修复,我想知道文本出现倒置的实际原因。 3. 我还需要设置我使用 NSAttributedString 的文本边框宽度和颜色,但设置文本大小(增大或减小)不会反映在屏幕上。

编辑 1:

我已根据您的建议更新了代码,但即使在使用 CTFontRef 后,文本也不会调整大小。此外,在 iPhone 上,文本从顶部被截断了一点。知道什么设置不正确吗?当我检查从 getTypgraphicBounds 获取的值时,它们都是 0(origin.x、origin.y、宽度和高度)。

getTypgraphicBounds 方法:

width = CTLineGetTypographicBounds(m_line, &ascent, &descent, &leading);

// Return text bounds
return CGRectMake(0, 0, width, ascent + descent);

修改后的代码:

CATextLayer*    text      = [[CATextLayer alloc] init];
CGColorSpaceRef rgbColor  = CGColorSpaceCreateDeviceRGB();
CGColorRef rgb            = CGColorCreate(rgbColor, m_fill_color);
text.foregroundColor      = rgb;
text.frame                = CGRectMake([self getTypographicBounds].origin.x, [self getTypographicBounds].origin.y, [self getTypographicBounds].size.width + 2*m_padding, [self getTypographicBounds].size.height + 2*m_padding);
text.wrapped              = YES;

    NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];

    CTFontRef aCFFont = CTFontCreateWithName ((CFStringRef)m_font_name, 30.0, NULL);

    // Set a negative width so we get both stroke and fill to show
    [stringAttributes setObject: (NSObject*)aCFFont forKey: (id)kCTFontNameAttribute];
    [stringAttributes setObject: [NSNumber numberWithFloat: -3 ] forKey: (id)kCTStrokeWidthAttributeName];
    [stringAttributes setObject: [UIColor whiteColor] forKey: (id)kCTStrokeColorAttributeName];

    NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:m_text
                                                                       attributes:stringAttributes];

    text.string = (NSString*)stringToDraw;
    [text drawInContext:ctx];

编辑2:wiki 示例使用 CTLine,我使用 CATextLayer。 Reason::CATextLayer 允许我在运行时修改文本以显示中文、日语、印地语、俄语以及具有不同脚本的所有语言。此外,CATextLayer 的渲染效果似乎比 CoreText 更清晰。

我现在面临的问题是 [text drawInContext:ctx] 行显示的文本从顶部截断。我检查了框架和文本字体大小。字体大小为 16 px,框架高度为 17.768,所以我不知道为什么它会被截断。

// Ensure CTLine is up-to-date
if (m_is_dirty)
    [self recomputeLine];

// Get text metrics
CGFloat width;
CGFloat ascent;
CGFloat descent;
CGFloat leading;

width = CTLineGetTypographicBounds(m_line, &ascent, &descent, &leading);

// Position text so that top of text aligns with top of layer
CGContextSetTextMatrix(ctx, CGAffineTransformIdentity );

// Setup text drawing style
CGContextSetRGBFillColor   (ctx, m_fill_color  [0], m_fill_color  [1], m_fill_color  [2], 1.0);
CGContextSetRGBStrokeColor (ctx, m_stroke_color[0], m_stroke_color[1], m_stroke_color[2], 1.0);
CGContextSetFont           (ctx, m_font        );
CGContextSetFontSize       (ctx, m_font_size   );
CGContextSetLineWidth      (ctx, m_stroke_width);

CATextLayer*    text      = [[CATextLayer alloc] init];
CGColorSpaceRef rgbColor  = CGColorSpaceCreateDeviceRGB();
CGColorRef rgb            = CGColorCreate(rgbColor, m_fill_color);
text.foregroundColor      = rgb;
text.fontSize = m_font_size;
text.font = m_font;
text.frame                = CGRectMake([self getTypographicBounds].origin.x, [self getTypographicBounds].origin.y, [self getTypographicBounds].size.width, [self getTypographicBounds].size.height);
text.wrapped              = YES;

NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];


// Set a negative width so we get both stroke and fill to show
[stringAttributes setObject: [UIFont fontWithName:m_font_name size:m_font_size] forKey: (id)kCTFontNameAttribute];
[stringAttributes setObject: [NSNumber numberWithFloat: -3 ] forKey: (id)kCTStrokeWidthAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: (id)kCTStrokeColorAttributeName];

NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:m_text
                                                                       attributes:stringAttributes];

text.string = (NSString*)stringToDraw;        
[text drawInContext:ctx];

预先感谢

尼克

I need to draw text into a CGContext and want to use CATextLayer to set the text. Can anyone give me some steps as to how it'll be done. I've written some code for it, but don't know the correctness of it (since I'm new to iPhone Development).

Some basic questions :
1. How to obtain position and size of text for setting the CATextLayer frame
2. The text is somehow coming out inverted which I've fixed using CGAffineTransform, but its a hacky fix and I want to know the actual reason why the text is coming out inverted.
3. I also need to set the text border width and color for which I'm using NSAttributedString, but setting the text size (increasing or decreasing) does not reflect on the screen.

EDIT 1 :

I've updated the code as per your recommendations, but the text is not resizing even after using CTFontRef. Also, on the iPhone the text is getting truncated a little bit from the top. Any idea what's being set incorrectly? When I checked the values I'm getting from getTypographicBounds, they're all 0 (origin.x, origin.y, width and height).

The getTypographicBounds method :

width = CTLineGetTypographicBounds(m_line, &ascent, &descent, &leading);

// Return text bounds
return CGRectMake(0, 0, width, ascent + descent);

The modified code :

CATextLayer*    text      = [[CATextLayer alloc] init];
CGColorSpaceRef rgbColor  = CGColorSpaceCreateDeviceRGB();
CGColorRef rgb            = CGColorCreate(rgbColor, m_fill_color);
text.foregroundColor      = rgb;
text.frame                = CGRectMake([self getTypographicBounds].origin.x, [self getTypographicBounds].origin.y, [self getTypographicBounds].size.width + 2*m_padding, [self getTypographicBounds].size.height + 2*m_padding);
text.wrapped              = YES;

    NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];

    CTFontRef aCFFont = CTFontCreateWithName ((CFStringRef)m_font_name, 30.0, NULL);

    // Set a negative width so we get both stroke and fill to show
    [stringAttributes setObject: (NSObject*)aCFFont forKey: (id)kCTFontNameAttribute];
    [stringAttributes setObject: [NSNumber numberWithFloat: -3 ] forKey: (id)kCTStrokeWidthAttributeName];
    [stringAttributes setObject: [UIColor whiteColor] forKey: (id)kCTStrokeColorAttributeName];

    NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:m_text
                                                                       attributes:stringAttributes];

    text.string = (NSString*)stringToDraw;
    [text drawInContext:ctx];

EDIT 2 : The wiki example uses CTLine, I'm using CATextLayer. Reason :: CATextLayer lets me modify text during runtime to show Chinese, Japanese, Hindi, Russian and all languages with different scripts. Also, CATextLayer seems to render with more clarity than CoreText.

The issue I'm facing right now is that the text being displayed by [text drawInContext:ctx] line is truncating from the top. I checked the frame and text font size. Font size is 16 px and frame height is 17.768, so I don't know why it's truncating.

// Ensure CTLine is up-to-date
if (m_is_dirty)
    [self recomputeLine];

// Get text metrics
CGFloat width;
CGFloat ascent;
CGFloat descent;
CGFloat leading;

width = CTLineGetTypographicBounds(m_line, &ascent, &descent, &leading);

// Position text so that top of text aligns with top of layer
CGContextSetTextMatrix(ctx, CGAffineTransformIdentity );

// Setup text drawing style
CGContextSetRGBFillColor   (ctx, m_fill_color  [0], m_fill_color  [1], m_fill_color  [2], 1.0);
CGContextSetRGBStrokeColor (ctx, m_stroke_color[0], m_stroke_color[1], m_stroke_color[2], 1.0);
CGContextSetFont           (ctx, m_font        );
CGContextSetFontSize       (ctx, m_font_size   );
CGContextSetLineWidth      (ctx, m_stroke_width);

CATextLayer*    text      = [[CATextLayer alloc] init];
CGColorSpaceRef rgbColor  = CGColorSpaceCreateDeviceRGB();
CGColorRef rgb            = CGColorCreate(rgbColor, m_fill_color);
text.foregroundColor      = rgb;
text.fontSize = m_font_size;
text.font = m_font;
text.frame                = CGRectMake([self getTypographicBounds].origin.x, [self getTypographicBounds].origin.y, [self getTypographicBounds].size.width, [self getTypographicBounds].size.height);
text.wrapped              = YES;

NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];


// Set a negative width so we get both stroke and fill to show
[stringAttributes setObject: [UIFont fontWithName:m_font_name size:m_font_size] forKey: (id)kCTFontNameAttribute];
[stringAttributes setObject: [NSNumber numberWithFloat: -3 ] forKey: (id)kCTStrokeWidthAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: (id)kCTStrokeColorAttributeName];

NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:m_text
                                                                       attributes:stringAttributes];

text.string = (NSString*)stringToDraw;        
[text drawInContext:ctx];

Thanks in advance

Nick

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月下伊人醉 2025-01-04 13:10:48

这是因为 CGContext 使用了翻转的坐标空间。有关完整说明(带图表),请参阅此处

编辑:
要控制位置,请在绘制文本之前翻译您的上下文:

CGContextTranslateCTM(context, x, y);

编辑2:

看起来您需要使用CTFontRef,而不是UIFont。有关示例,请参阅此处(请参阅 Gordon Apple 于 6 月 23 日星期三 10:40 发表的帖子: 2010 年 23 日)。

编辑3:

除非您特别需要使用 NSAttributedString,否则我建议使用更简单的 NSString drawInRect:withFont:lineBreakMode:alignment: 方法。它为您创建一个 CATextLayer,但使用起来更简单:

    UIFont *font = [UIFont fontWithName:m_font_name size:30.f];
    [m_text drawInRect:text.frame  withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];

编辑 4:

尝试像这样设置字典:

    CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)fontName, pointSize,NULL);
    CGColorRef color = textColor.CGColor;

    NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                    (__bridge id)ctFont, (id)kCTFontAttributeName,
                                    color, (id)kCTForegroundColorAttributeName,nil];

It is because of the flipped coordinate space used for CGContexts. For a full explanation (with diagrams) see here.

EDIT:
To control the position translate your context before drawing the text:

CGContextTranslateCTM(context, x, y);

EDIT 2:

Looks like you need to use a CTFontRef, not a UIFont. For an example, see here (see post by Gordon Apple Wed Jun 23 10:40:23 2010).

EDIT 3:

Unless you specifically need to use NSAttributedString, I would recommend using the much simpler NSString drawInRect:withFont:lineBreakMode:alignment: method. It creates a CATextLayer for you, but is much simpler to use:

    UIFont *font = [UIFont fontWithName:m_font_name size:30.f];
    [m_text drawInRect:text.frame  withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];

EDIT 4:

Try setting your dictionary like this:

    CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)fontName, pointSize,NULL);
    CGColorRef color = textColor.CGColor;

    NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                    (__bridge id)ctFont, (id)kCTFontAttributeName,
                                    color, (id)kCTForegroundColorAttributeName,nil];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文