CTRunGetImageBounds returning inaccurate results

前端 未结 2 547
遇见更好的自我
遇见更好的自我 2021-02-04 20:59

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 si

相关标签:
2条回答
  • 2021-02-04 21:33

    Before you can use CTRunGetImageBounds() or CTLineDraw() you need to set the starting text position with a call to CGContextSetTextPosition() before drawing or computing each line. The reason is a CTLine has no idea where to start drawing (or computing) on its own, it uses the last text position, so you need to give it an XY starting point. To get the origins for a frame's array of lines, call CTFrameGetLineOrigins() with an array of points. Then, before drawing or computing each line - set the origin of that line via 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);
     }
    
    0 讨论(0)
  • 2021-02-04 21:37

    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++;
    }
    
    0 讨论(0)
提交回复
热议问题