Ios CTRunGetImageBounds返回不准确的结果
我正在使用核心文本来绘制一些文本。我想获得各种运行边界,但当我调用Ios CTRunGetImageBounds返回不准确的结果,ios,core-text,Ios,Core Text,我正在使用核心文本来绘制一些文本。我想获得各种运行边界,但当我调用CTRunGetImageBounds时,返回的rect大小正确,但位置错误。具体来说,线条原点位于整个文本的末尾 - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); self.transform = CGAffineTransformMakeScale(1.0, -1.0); CGCon
CTRunGetImageBounds
时,返回的rect大小正确,但位置错误。具体来说,线条原点位于整个文本的末尾
- (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起点。要获取帧线数组的原点,请使用点数组调用ctFrameGetLineOriginates()。然后,在绘制或计算每条线之前,通过CGContextSetTextPosition()设置该线的原点
NSArray*行=(NSArray*)CTFrameGetLines(frame);
CGPoint原点[[行数]];//基线处每条线的原点
CTFrameGetLineOriginates(框架,CFRangeMake(0,0),原点);
int i,行数;
lineCount=[行数];
对于(i=0;i
最好使用如本答案所示的印刷边界,而不是图像边界,因为前者不需要CGContext。另外,getImageBounds函数的速度要慢几个数量级。2小时后,我在谷歌上偶然发现了圣杯。谢谢。上面的代码对我部分有效。返回错误结果的代码是以下运行边界。origin.y=origins[lineIndex].y+rect.origin.y;runBounds.origin.y-=下降;尽管前面的所有代码都返回了正确的宽度、高度、原点.x。。。起源。y有缺陷。有人知道为什么吗?谢谢你的帮助。
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);
}