Created
October 20, 2011 20:21
-
-
Save wimhaanstra/1302242 to your computer and use it in GitHub Desktop.
Placing curved text on an UIImage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NSArray* sections = [[NSArray alloc] initWithObjects:@"text1", @"text2", @"text3", @"text4", nil]; | |
- (UIImage*) createMenuRingWithFrame:(CGRect)frame | |
{ | |
// First fix the frame to make sure it uses the right scaling (iPhone 4 / iPad compatibility). | |
frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width * scale, frame.size.height * scale); | |
// Same for the text radius | |
float scaledTextRadius = textRadius * scale; | |
float scaledRingWidth = ringWidth; | |
// Define the centerpoint of the circle. | |
CGPoint centerPoint = CGPointMake(frame.size.width / 2, frame.size.height / 2); | |
// self.menuItemsFont is of the type UIFont, which I use to get the font for displaying the text on the circle. | |
char* fontName = (char*)[self.menuItemsFont.fontName cStringUsingEncoding:NSASCIIStringEncoding]; | |
// 2 UIColor's, which I need for the color of the circle and for the text | |
ringColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.7]; | |
textColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; | |
CGFloat* ringColorComponents = (float*)CGColorGetComponents(ringColor.CGColor); | |
CGFloat* textColorComponents = (float*)CGColorGetComponents(textColor.CGColor); | |
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); | |
CGContextRef context = CGBitmapContextCreate(NULL, frame.size.width, frame.size.height, 8, 4 * frame.size.width, colorSpace, kCGImageAlphaPremultipliedFirst); | |
CGContextSetTextMatrix(context, CGAffineTransformIdentity); | |
CGContextSelectFont(context, fontName, 18 * scale, kCGEncodingMacRoman); | |
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], ringAlpha); | |
CGContextSetLineWidth(context, scaledRingWidth); | |
CGContextStrokeEllipseInRect(context, CGRectMake(scaledRingWidth, scaledRingWidth, frame.size.width - (scaledRingWidth * 2), frame.size.height - (scaledRingWidth * 2))); | |
CGContextSetRGBFillColor(context, textColorComponents[0], textColorComponents[1], textColorComponents[2], textAlpha); | |
CGContextSaveGState(context); | |
CGContextTranslateCTM(context, centerPoint.x, centerPoint.y); | |
// define the angles of the texts to divide them evenly on the circle. | |
float angleStep = 2 * M_PI / [sections count]; | |
// I set the starting-angle on 90 degrees, to make sure the first text was ON TOP of the circle. | |
float angle = degreesToRadians(90); | |
// Some custom text-radius fixing (and scaling for iPhone 4 & iPad). To make sure my text centered nicely. | |
scaledTextRadius = scaledTextRadius - 12 * scale; | |
// Loop through texts and draw them at the appropriate angle. | |
for (NSString* text in sections) | |
{ | |
// call a method that actually draws the text at an angle | |
[self drawStringAtContext:context string:text atAngle:angle withRadius:scaledTextRadius]; | |
angle -= angleStep; | |
} | |
CGContextRestoreGState(context); | |
CGImageRef contextImage = CGBitmapContextCreateImage(context); | |
// Release the stuff to avoid memory leaks. | |
CGContextRelease(context); | |
CGColorSpaceRelease(colorSpace); | |
return [UIImage imageWithCGImage:contextImage]; | |
} | |
// This method draws the text at an angle, while the location is based on the radius + angle. | |
- (void) drawStringAtContext:(CGContextRef) context string:(NSString*) text atAngle:(float) angle withRadius:(float) radius | |
{ | |
// Scale the fontsize to match UIScreen scaling | |
UIFont* scaledMenuItemsFont = [menuItemsFont fontWithSize:18 * scale]; | |
// Get the size of the string when it would be drawn with the selected font | |
CGSize textSize = [text sizeWithFont:scaledMenuItemsFont]; | |
float perimeter = 2 * M_PI * radius; | |
// determine the angle of the text. | |
float textAngle = (textSize.width) / perimeter * 2 * M_PI; | |
angle += textAngle / 2; | |
// We loop through each letter in the string, so we can set the angle for each letter right | |
for (int index = 0; index < [text length]; index++) | |
{ | |
// Get the correct letter by the index | |
NSRange range = {index, 1}; | |
NSString* letter = [text substringWithRange:range]; | |
char* c = (char*)[letter cStringUsingEncoding:NSASCIIStringEncoding]; | |
CGSize charSize = [letter sizeWithFont:scaledMenuItemsFont]; | |
// Determin the X and Y position of the letter based on the angle and the radius | |
float x = radius * cos(angle); | |
float y = radius * sin(angle); | |
float letterAngle = (charSize.width / perimeter * -2 * M_PI); | |
// Save the state of the context, because rotations are based on the original origin | |
CGContextSaveGState(context); | |
CGContextTranslateCTM(context, x, y); | |
// Rotate the canvas so we can just draw our text horizontally | |
CGContextRotateCTM(context, (angle - 0.5 * M_PI)); | |
CGContextShowTextAtPoint(context, 0, 0, c, strlen(c)); | |
// Restore the context again. | |
CGContextRestoreGState(context); | |
angle += letterAngle; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello there, I'd like to use your code to curve text. However, I'm not quite sure how to implement your code and make it work. Where should I put "NSArray* sections = [[NSArray alloc] initWithObjects:@"text1".... " into? Into Viewdidload? gistfile1.h file?