Core Text With Asymmetric Shape on iOS

Viewed 965

I want to write text in a path that can take up any shape. Right now I can draw flipped text in it:

NSArray *coordinates = ...;

CGMutablePathRef pathRef = [self objectPathGivenCoordinates:coordinates];

... // Draw the shapes

// Now draw the text    
CGContextSetTextMatrix(context, CGAffineTransformIdentity);

NSAttributedString* attString = [[NSAttributedString alloc] initWithString:@"0,1,2..."];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attString);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, [attString length]), pathRef, NULL);
CTFrameDraw(frame, context);

That produces this:

Flipped text in Asymmetric Shape

I understand that iOS has a flipped coordinate system. Most solutions add these two lines before drawing:

CGContextTranslateCTM(context, 0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

But that produces this:

Text is now written left-right right-side-up but out of path bounds

So why doesn't this technique work? In every example I've seen, this technique is used when text is rendered in something symmetric, or with clipping, or on OS X. If we're drawing text in a symmetric shape, our calls to CGContextTranslateCTM() and CGContextScaleCTM() make sense. A call to CGContextTranslateCTM(context, 0, rect.size.height), moves the origin of the first letter to the top. A call to CGContextScaleCTM(context, 1, -1) reverses the direction of Y. If we reverse the direction of Y on a symmetric shape, it doesn't change. Sadly, my shapes aren't symmetric.

Here is what I've considered but abandoned

  • Draw shapes and numbers on the same scale (both upside-down), then flip the UIImageView behind it somehow (1)
  • Don't make calls to change the scale or translate the CTM. Flip the text matrix with CGContextSetTextMatrix() so that text is drawn from left to right, bottom up, and is right side up. Determine how many extra characters are left in the shape after a string for the shape is determined. Reverse the words (now it will draw top to bottom, right to left, right side up). Add spaces for every extra character. Now for each CTLine, somehow reverse the words again (now it will draw top to bottom, left to right, right side up) (2)

Why I abandoned them

(1) I can't flip my images. They always need to be right side up

(2) This may be overkill for a simple solution someone else knows

1 Answers
Related