2011-03-06 3 views
3

일부 텍스트를 그리기 위해 핵심 텍스트를 사용하고 있습니다. 다양한 실행 범위를 얻고 싶습니다만, CTRunGetImageBounds을 호출하면 반환되는 rect가 올바른 크기이지만 잘못된 위치에 있습니다. 특히, 라인 원점은 텍스트 전체에 있습니다.부정확 한 결과를 반환하는 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]; 
} 

는 생산 :

여기

results

답변

10

내가 생각 해낸 것입니다. 이것은 완전히 정확합니다.

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++; 
} 
+0

전자가 CGContext를 필요로하지 않기 때문에 대신 이미지 경계의이 답변에 표시된 것처럼 인쇄상의 경계를 사용하는 것이 좋습니다. 또한 getImageBounds 함수는 더 느린 순서입니다. – Cocoanetics

+0

나중에 2 시간 씩 인터넷 검색, 나는 성배를 우연히 발견합니다. 감사. –

+0

위의 코드는 부분적으로 작동합니다. 오류 결과를 반환하는 코드는 다음과 같습니다. runBounds.origin.y = origins [lineIndex] .y + rect.origin.y; runBounds.origin.y - = descent; 앞의 모든 코드가 width, height, origin.x ... origin.y의 올바른 결과를 반환하더라도 누구나 그 이유를 알고 있습니까? 어떤 도움을 주셔서 감사합니다. – stefanosn

3

당신이 그리거나 각 행을 계산하기 전에 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); 
} 
관련 문제