Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breaking a CTFrame into CTLines

I have the following code which draws an attributed string in a rect:

CGContextRef context = UIGraphicsGetCurrentContext();
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)string);

    // left column form
    CGMutablePathRef leftColumnPath = CGPathCreateMutable();
    CGPathAddRect(leftColumnPath, NULL, CGRectMake(rect.origin.x, -rect.origin.y,rect.size.width, self.bounds.size.height));

    // left column frame
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);   
    CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), leftColumnPath, NULL);
    CTFrameDraw(leftFrame, context);

Everything works fine here, but I need finer control over each individual line. So instead of drawing the frame, I want to draw each line separately. So I'm trying instead of using CTFrameDraw using this:

CFArrayRef linesArray =  CTFrameGetLines(leftFrame);
    for (CFIndex i = 0; i < CFArrayGetCount(linesArray); i++){
        CTLineRef line = CFArrayGetValueAtIndex(linesArray, i);
        CTLineDraw(line, context);
}

However, this doesn't draw the same result as drawing the frame. I'm a newbie to Core Text, so is there more I should be doing to draw the line? Current this loop executes several times, but only one line is drawn on the bottom of the screen (rather on top with CTFrameDraw)

like image 542
Snowman Avatar asked Sep 10 '26 05:09

Snowman


2 Answers

insert CGContextSetTextPosition(context, x, y) just before CTLineDraw and change x & y as needed (don't forget y is reversed)

like image 176
cocoapriest Avatar answered Sep 12 '26 18:09

cocoapriest


example code extracted from: https://github.com/BigZaphod/Chameleon/blob/master/UIKit/Classes/UIStringDrawing.m

 if (lines)
 {
     CFIndex numberOfLines = CFArrayGetCount(lines);

    numberOfLines = 3;

    const CGFloat fontLineHeight = font.lineHeight;
    CGFloat textOffset = 0;

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y+font.ascender);
    CGContextSetTextMatrix(ctx, CGAffineTransformMakeScale(1,-1));

    for (CFIndex lineNumber=0; lineNumber<numberOfLines; lineNumber++) {
        CTLineRef line = CFArrayGetValueAtIndex(lines, lineNumber);
        float flush = 0.5;

        switch (alignment) {
            case UITextAlignmentCenter: flush = 0.5;    break;
            case UITextAlignmentRight:  flush = 1;      break;
            case UITextAlignmentLeft:
            default:                    flush = 0;      break;
        }

        CGFloat penOffset = CTLineGetPenOffsetForFlush(line, flush, rect.size.width);
        CGContextSetTextPosition(ctx, penOffset, textOffset);
        CTLineDraw(line, ctx);
        textOffset += fontLineHeight;
    }

    CGContextRestoreGState(ctx);

    CFRelease(lines);
}
like image 31
8suhas Avatar answered Sep 12 '26 19:09

8suhas