Quick Tip: Drawing Right Side Up With Core Text

Anyone who has decided to explore using Core Text on iOS has probably noticed that everything is drawn upside down. This is because Core Graphics contexts that have been created with functions provided by UIKit (such as UIGraphicsBeginImageContext, or the drawRect method in a UIView) have a coordinate system with it’s origin (0,0) located in the top left corner. However, in the days before iOS, and when using a more traditional approach to creating a CGContext (CGBitmapContextCreate for example), the origin starts in the lower left corner. Because of its desktop origins and close ties to Core Graphics, Core Text expects the more traditional coordinate system; Without context adjustments, text is drawn as if it were mirrored vertically.

When I first started dabbling with Core Text, CGContextSetTextMatrix seemed like a reasonable place to start in order to fix this – it accepts a CGContextRef and a CGAffineTransform, and something like the following will indeed flip your text.

CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));

Great, problem solved! Except that it’s not, especially if you plan on having more than one line of text using something like CTFrameDraw. In this case, just transforming the text matrix will flip your letters, but doesn’t adjust the direction in which the frame lays out line breaks. What you’ll notice is readable text, but with last line starting at the top.

Basically, you can think of the transform applied with CGContextSetTextMatrix as being applied to each individual letter as it is drawn. If you want to impact that way a segment of text is laid out as a group, then a transform needs to be applied to entire context. The following will both flip your letters, and lay text in the proper direction

CGContextTranslateCTM(context, 0.0f, contextHeight);
CGContextScaleCTM(context, 1.0f, -1.0f);

Mind you, transforming individual letters can still be fun! In the last view of the screenshot we’ve applied the following set of transforms to rotate each letter by 45 degrees, while maintaining proper layout and line breaks.

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeRotation(45 * M_PI / 180.0f);
CGContextSetTextMatrix(context, transform);
CGContextTranslateCTM(context, 0.0f, rect.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);

About Jerry Jones

Co-Founder of Spaceman Labs, Inc. Formerly of Mellmo, Inc. iOS Developer since 2007. You can find me on LinkedIn, Twitter, and doing backflips on jet skis.
This entry was posted in Code and tagged , , . Bookmark the permalink.