CTRunGetImageBounds返回不准确的结果 [英] CTRunGetImageBounds returning inaccurate results

查看:415
本文介绍了CTRunGetImageBounds返回不准确的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Core Text绘制一些文字。我想获得各种运行边界,但是当我调用 CTRunGetImageBounds 时,返回的rect是正确的大小,但位置错误。具体来说,行原点位于整个文本的末尾。

I am using Core Text to draw some text. I would like to get the various run bounds, but when I call CTRunGetImageBounds, the rect that is returned is the correct size, but in the wrong location. Specifically, the line origin is at the end of the text as a whole.

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    self.transform = CGAffineTransformMakeScale(1.0, -1.0);
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);

    [[UIColor whiteColor] set];
    CGContextFillRect(context, self.bounds);

    NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:@"Blue should be underlined."];
    NSRange blueRange = NSMakeRange(0, 4);
    [attrString beginEditing];
    //make all text size 20.0
    [attrString addAttribute:(NSString *)kCTFontAttributeName value:(id)CTFontCreateWithName((CFStringRef)@"Helvetica", 20.0, NULL) range:NSMakeRange(0, [attrString length])];
    //make the text appear in blue
    [attrString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[[UIColor blueColor] CGColor] range:blueRange];
    //next make the text appear with an underline
    [attrString addAttribute:(NSString *)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:1] range:blueRange];
    [attrString endEditing];

    CGMutablePathRef path = CGPathCreateMutable();
    CGRect bounds = CGRectMake(10.0, 10.0, 200.0, 200.0);
    [[UIColor redColor] set];
    CGContextFillRect(context, bounds);
    CGPathAddRect(path, NULL, bounds);

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CTFrameDraw(frame, context);

    for (id lineObj in (NSArray *)CTFrameGetLines(frame)) {
        CTLineRef line = (CTLineRef)lineObj;
        for (id runObj in (NSArray *)CTLineGetGlyphRuns(line)) {
            CTRunRef run = (CTRunRef)runObj;
            CGRect runBounds = CTRunGetImageBounds(run, context, CFRangeMake(0, 0));
            NSLog(@"bounds: %@", NSStringFromCGRect(runBounds));

            [[UIColor greenColor] set];
            CGContextFillRect(context, runBounds);
        }
    }

    CFRelease(framesetter);
    CFRelease(frame);
    [attrString release];
}

产生:

推荐答案

这是我想出的。这是完全准确的。

Here is what I came up with. This is completely accurate.

CTFrameRef frame = [self _frameWithRect:rect];

NSArray *lines = (NSArray *)CTFrameGetLines(frame);

CGPoint origins[[lines count]];//the origins of each line at the baseline
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

NSUInteger lineIndex = 0;
for (id lineObj in lines) {
    CTLineRef line = (CTLineRef)lineObj;

    for (id runObj in (NSArray *)CTLineGetGlyphRuns(line)) {
        CTRunRef run = (CTRunRef)runObj;
        CFRange runRange = CTRunGetStringRange(run);

        CGRect runBounds;

        CGFloat ascent;//height above the baseline
        CGFloat descent;//height below the baseline
        runBounds.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, NULL);
        runBounds.size.height = ascent + descent;

        CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL);
        runBounds.origin.x = origins[lineIndex].x + rect.origin.x + xOffset;
        runBounds.origin.y = origins[lineIndex].y + rect.origin.y;
        runBounds.origin.y -= descent;

        //do something with runBounds
    }
    lineIndex++;
}

这篇关于CTRunGetImageBounds返回不准确的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆