CTRunGetImageBounds返回不准确的结果

我正在使用核心文本来绘制一些文本。 我想获得各种运行范围,但是当我调用CTRunGetImageBounds ,返回的矩形是正确的大小,但位置错误。 具体来说,行的原点在整个文本的末尾。

 - (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]; } 

生产:

结果

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

 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()或CTLineDraw()之前,需要在绘制或计算每一行之前,通过调用CGContextSetTextPosition()来设置起始文本位置。 原因是CTLine不知道从哪里开始绘图(或计算),它使用最后的文本位置,所以你需要给它一个XY起点。 为了得到帧的数组的起点,用一个点数组来调用CTFrameGetLineOrigins()。 然后,在绘制或计算每一行之前 – 通过CGContextSetTextPosition()设置该行的原点。

 NSArray *lines = (NSArray *)CTFrameGetLines(frame); CGPoint origins[[lines count]]; // the origins of each line at the baseline CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); int i, lineCount; lineCount = [lines count]; for (i = 0; i < lineCount; i++) { CTLineRef line = (CTLineRef)[lines objectAtIndex:i]; CGContextSetTextPosition(context, origins[i].x, origins[i].y); CTLineDraw(line, context); }