For an application I am building I have drawn 2 circles. One a bit bigger than the other. I want to curve text between those lines, for a circular menu I am building.
I read most stuff about curving a text that you have to split up your text in characters and draw each character on it's own with the right angle in mind (by rotating the context you are drawing on).
I just can't wrap my head around on how to get the right angles and positions for my characters.
I included a screenshot on what the menu, at the moment, look like. Only the texts I added by are loaded from an image in an UIImageView.
I hope someone can get me some starting points on how I can draw the text in the white circle, at certain points.
EDIT: Ok, I am currently at this point:
I accomplish by using the following code:
- (UIImage*) createMenuRingWithFrame:(CGRect)frame
{
CGRect imageSize = CGRectMake(0,0,300,300);
float perSectionDegrees = 360 / [sections count];
float totalRotation = 90;
char* fontName = (char*)[self.menuItemsFont.fontName cStringUsingEncoding:NSASCIIStringEncoding];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, imageSize.size.width, imageSize.size.height, 8, 4 * imageSize.size.width, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextSelectFont(context, fontName, 18, kCGEncodingMacRoman);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
CGPoint centerPoint = CGPointMake(imageSize.size.width / 2, imageSize.size.height / 2);
double radius = (frame.size.width / 2);
CGContextStrokeEllipseInRect(context, CGRectMake(centerPoint.x - (frame.size.width / 2), centerPoint.y - (frame.size.height / 2), frame.size.width, frame.size.height));
for (int index = 0; index < [sections count]; index++)
{
NSString* menuItemText = [sections objectAtIndex:index];
CGSize textSize = [menuItemText sizeWithFont:self.menuItemsFont];
char* menuItemTextChar = (char*)[menuItemText cStringUsingEncoding:NSASCIIStringEncoding];
float x = centerPoint.x + radius * cos(degreesToRadians(totalRotation));
float y = centerPoint.y + radius * sin(degreesToRadians(totalRotation));
CGContextSaveGState(context);
CGContextTranslateCTM(context, x, y);
CGContextRotateCTM(context, degreesToRadians(totalRotation - 90));
CGContextShowTextAtPoint(context, 0 - (textSize.width / 2), 0 - (textSize.height / 2), menuItemTextChar, strlen(menuItemTextChar));
CGContextRestoreGState(context);
totalRotation += perSectionDegrees;
}
CGImageRef contextImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:contextImage];
}
These are the variables I use in there:
NSArray* sections = [[NSArray alloc] initWithObjects:@"settings", @"test", @"stats", @"nog iets", @"woei", @"woei2", nil];
self.menuItemsFont = [UIFont fontWithName:@"VAGRounded-Bold" size:18];
The rotation of the words seem correct, the placement also. Now I need somehow figure out at which rotation the letters (and their coordinates) should be. I could use some help with that.
Edit: Fixed! Check out the following code!
- (void) drawStringAtContext:(CGContextRef) context string:(NSString*) text atAngle:(float) angle withRadius:(float) radius
{
CGSize textSize = [text sizeWithFont:self.menuItemsFont];
float perimeter = 2 * M_PI * radius;
float textAngle = textSize.width / perimeter * 2 * M_PI;
angle += textAngle / 2;
for (int index = 0; index < [text length]; index++)
{
NSRange range = {index, 1};
NSString* letter = [text substringWithRange:range];
char* c = (char*)[letter cStringUsingEncoding:NSASCIIStringEncoding];
CGSize charSize = [letter sizeWithFont:self.menuItemsFont];
NSLog(@"Char %@ with size: %f x %f", letter, charSize.width, charSize.height);
float x = radius * cos(angle);
float y = radius * sin(angle);
float letterAngle = (charSize.width / perimeter * -2 * M_PI);
CGContextSaveGState(context);
CGContextTranslateCTM(context, x, y);
CGContextRotateCTM(context, (angle - 0.5 * M_PI));
CGContextShowTextAtPoint(context, 0, 0, c, strlen(c));
CGContextRestoreGState(context);
angle += letterAngle;
}
}
- (UIImage*) createMenuRingWithFrame:(CGRect)frame
{
CGPoint centerPoint = CGPointMake(frame.size.width / 2, frame.size.height / 2);
char* fontName = (char*)[self.menuItemsFont.fontName cStringUsingEncoding:NSASCIIStringEncoding];
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, kCGEncodingMacRoman);
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], ringAlpha);
CGContextSetLineWidth(context, ringWidth);
CGContextStrokeEllipseInRect(context, CGRectMake(ringWidth, ringWidth, frame.size.width - (ringWidth * 2), frame.size.height - (ringWidth * 2)));
CGContextSetRGBFillColor(context, textColorComponents[0], textColorComponents[1], textColorComponents[2], textAlpha);
CGContextSaveGState(context);
CGContextTranslateCTM(context, centerPoint.x, centerPoint.y);
float angleStep = 2 * M_PI / [sections count];
float angle = degreesToRadians(90);
textRadius = textRadius - 12;
for (NSString* text in sections)
{
[self drawStringAtContext:context string:text atAngle:angle withRadius:textRadius];
angle -= angleStep;
}
CGContextRestoreGState(context);
CGImageRef contextImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
[self saveImage:[UIImage imageWithCGImage:contextImage] withName:@"test.png"];
return [UIImage imageWithCGImage:contextImage];
}