How to write text on image in Objective-C (iOS)?

Clash Royale CLAN TAG#URR8PPPHow to write text on image in Objective-C (iOS)?
I want to make an image like this programmatically:

I have the upper image and text with me. Should I write text on the image?
I want to make it a complete .png image(image + label) and set it as the background of the button.
no.. Please provide the sample code so that I can try.
– Sanchit Paurush
Aug 9 '11 at 7:35
Do you just want to display it like that inside your app, or do you want to edit image file to contain this text and save it like that?
– Filip Radelic
Aug 9 '11 at 7:41
I want to make it a complete image(image + label) and add it in the background of the button.
– Sanchit Paurush
Aug 9 '11 at 8:50
13 Answers
13
Draw text inside an image and return the resulting image:
+(UIImage*) drawText:(NSString*) text
inImage:(UIImage*) image
atPoint:(CGPoint) point
{
UIFont *font = [UIFont boldSystemFontOfSize:12];
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(point.x, point.y, image.size.width, image.size.height);
[[UIColor whiteColor] set];
[text drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Usage:
// note: replace "ImageUtils" with the class where you pasted the method above
UIImage *img = [ImageUtils drawText:@"Some text"
inImage:img
atPoint:CGPointMake(0, 0)];
Change the origin of the text inside the image from 0,0 to whatever point you like.
To paint a rectangle of solid color behind the text, add the following before the line [[UIColor whiteColor] set];:
[[UIColor whiteColor] set];
[[UIColor brownColor] set];
CGContextFillRect(UIGraphicsGetCurrentContext(),
CGRectMake(0, (image.size.height-[text sizeWithFont:font].height),
image.size.width, image.size.height));
I'm using the text size to calculate the origin for the solid color rectangle, but you can replace it with any number.
Yes, This is the thing that I needed. But it is adding text at the right side of the image. Can we add it at the bottom of the image? plz help
– Sanchit Paurush
Aug 9 '11 at 9:21
See updated answer.
– Jano
Aug 9 '11 at 10:14
I am getting error as error: 'ImageUtils' was not declared in this scope. what is this ImageUtils. please tell me. i need the same as your requirement. @sanchitsingh
– sachi
Mar 29 '12 at 6:00
ImageUtils is the class name in which drawText method has been defined. Do one thing. In your .h file declare the draw text method and define it in .m file and use it as [self drawText:@"Some text" inImage:img atPoint:CGPointMake(0, 0)]; @sachi
– Sanchit Paurush
Mar 29 '12 at 6:21
It changes the UIImage object, but if you want another just do newImage = [UIImage imageNamed:@"..."]; since the underlying image file is cached, it won't affect memory or performance.
– Jano
Aug 3 '12 at 16:58
My contribution to the first answer with iOS 7 support :
+(UIImage*) drawText:(NSString*) text
inImage:(UIImage*) image
atPoint:(CGPoint) point
{
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0.0f);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(point.x, point.y, image.size.width, image.size.height);
[[UIColor whiteColor] set];
UIFont *font = [UIFont boldSystemFontOfSize:12];
if([text respondsToSelector:@selector(drawInRect:withAttributes:)])
{
//iOS 7
NSDictionary *att = @{NSFontAttributeName:font};
[text drawInRect:rect withAttributes:att];
}
else
{
//legacy support
[text drawInRect:CGRectIntegral(rect) withFont:font];
}
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Hope this helps
EDIT: modified the UIGraphicsBeginImageContextWithOptions to handle screen scale. Thk @SoftDesigner
UIGraphicsBeginImageContextWithOptions
Thanks...I needed to move the color into the att dictionary to work in iOS7: NSDictionary *att = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: [UIColor whiteColor]};
– Symmetric
Mar 6 '14 at 2:27
Replace the first line to this for higher text quality:
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0.0f);– SoftDesigner
Nov 21 '14 at 13:16
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0.0f);
not UIGraphicsBeginImageContext, but UIGraphicsBeginImageContextWithOptions
– brbgyn
Apr 6 '15 at 2:04
@brbgyn I've edited my original answer thanks
– iGranDav
Apr 7 '15 at 14:44
iOS7 only.
Watermark in lower right corner.
@interface UIImage (DrawWatermarkText)
-(UIImage*)drawWatermarkText:(NSString*)text;
@end
@implementation UIImage (DrawWatermarkText)
-(UIImage*)drawWatermarkText:(NSString*)text {
UIColor *textColor = [UIColor colorWithWhite:0.5 alpha:1.0];
UIFont *font = [UIFont systemFontOfSize:50];
CGFloat paddingX = 20.f;
CGFloat paddingY = 20.f;
// Compute rect to draw the text inside
CGSize imageSize = self.size;
NSDictionary *attr = @{NSForegroundColorAttributeName: textColor, NSFontAttributeName: font};
CGSize textSize = [text sizeWithAttributes:attr];
CGRect textRect = CGRectMake(imageSize.width - textSize.width - paddingX, imageSize.height - textSize.height - paddingY, textSize.width, textSize.height);
// Create the image
UIGraphicsBeginImageContext(imageSize);
[self drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
[text drawInRect:CGRectIntegral(textRect) withAttributes:attr];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
@end
Usage:
UIImage *image = [UIImage imageNamed:@"mona_lisa"];
image = [image drawWatermarkText:@"Leonardo da Vinci"];
Use UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0f); to maintain image quality.
– Sebastian Dwornik
Nov 21 '13 at 22:00
@SebastianDwornik the 0.0f parameter causes the code to depend on wether the device is retina or not.
– neoneye
Nov 24 '13 at 12:21
Correct. Hence I made the decision to only go iOS 7 and retina devices.
– Sebastian Dwornik
Nov 24 '13 at 17:12
@neoneye Can you help me i want to write text on image in white color and the are background area on the image where text is written should be black transparent alpha=0.5 Thanks.
– Khalid Usman
Dec 19 '13 at 6:17
@KhalidUsman is it a thin outline that is semitransparent around the text that you want?
– neoneye
Dec 19 '13 at 7:04
Here is the Swift version.
func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
var textColor: UIColor = UIColor.whiteColor()
var textFont: UIFont = UIFont(name: "Helvetica Bold", size: 12)!
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Creating a point within the space that is as bit as the image.
var rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
//Now Draw the text into an image.
drawText.drawInRect(rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
}
To call it you just pass in an image.
textToImage("000", inImage: UIImage(named:"thisImage.png")!, atPoint: CGPointMake(20, 20))
The following links helped me get this straight.
Swift - Drawing text with drawInRect:withAttributes:
How to write text on image in Objective-C (iOS)?
The original goal was to create a dynamic image that I could use in an AnnotaionView such as putting a price at a given location on a map and this worked out great for it. Hope this helps someone trying to do the same thing.
Great solution for Swift. Thanks so much!
– RanLearns
Mar 16 '15 at 4:47
I did something like this! After browsing and combining some examples.
Puts the text in the midle of the image, resizing the font if needed.
UIImage *myImage = [UIImage imageNamed:@"promoicon.png"];
UIGraphicsBeginImageContext(myImage.size);
[myImage drawInRect:CGRectMake(0,0,myImage.size.width,myImage.size.height)];
UITextView *myText = [[UITextView alloc] init];
myText.font = [UIFont fontWithName:@"TrebuchetMS-Bold" size:15.0f];
myText.textColor = [UIColor whiteColor];
myText.text = NSLocalizedString(@"promotionImageText", @"");
myText.backgroundColor = [UIColor clearColor];
CGSize maximumLabelSize = CGSizeMake(myImage.size.width,myImage.size.height);
CGSize expectedLabelSize = [myText.text sizeWithFont:myText.font
constrainedToSize:maximumLabelSize
lineBreakMode:UILineBreakModeWordWrap];
myText.frame = CGRectMake((myImage.size.width / 2) - (expectedLabelSize.width / 2),
(myImage.size.height / 2) - (expectedLabelSize.height / 2),
myImage.size.width,
myImage.size.height);
[[UIColor whiteColor] set];
[myText.text drawInRect:myText.frame withFont:myText.font];
UIImage *myNewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Why are you allocating a UITextView? You're not actually using it, as far as I can tell -- you're only using the frame (a CGRect) and the font (a UIFont), both of which would be easier to keep separately.
– Joe Strout
Jun 10 '13 at 17:42
...ah, unless it's the UITextView that's resizing the font to fit.
– Joe Strout
Jun 10 '13 at 17:46
best one solution
– Imran Ahmed
Aug 4 '15 at 13:58
I have created fully customized extension for UIImage to draw watermark in Swift:
extension UIImage{
enum WaterMarkCorner{
case TopLeft
case TopRight
case BottomLeft
case BottomRight
}
func waterMarkedImage(#waterMarkText:String, corner:WaterMarkCorner = .BottomRight, margin:CGPoint = CGPoint(x: 20, y: 20), waterMarkTextColor:UIColor = UIColor.whiteColor(), waterMarkTextFont:UIFont = UIFont.systemFontOfSize(20), backgroundColor:UIColor = UIColor.clearColor()) -> UIImage{
let textAttributes = [NSForegroundColorAttributeName:waterMarkTextColor, NSFontAttributeName:waterMarkTextFont]
let textSize = NSString(string: waterMarkText).sizeWithAttributes(textAttributes)
var textFrame = CGRectMake(0, 0, textSize.width, textSize.height)
let imageSize = self.size
switch corner{
case .TopLeft:
textFrame.origin = margin
case .TopRight:
textFrame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: margin.y)
case .BottomLeft:
textFrame.origin = CGPoint(x: margin.x, y: imageSize.height - textSize.height - margin.y)
case .BottomRight:
textFrame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: imageSize.height - textSize.height - margin.y)
}
/// Start creating the image with water mark
UIGraphicsBeginImageContext(imageSize)
self.drawInRect(CGRectMake(0, 0, imageSize.width, imageSize.height))
NSString(string: waterMarkText).drawInRect(textFrame, withAttributes: textAttributes)
let waterMarkedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return waterMarkedImage
}
}
As you see, I have added some default values for attributes so you can ignore if you don't need to change. Here some examples for how to use it:
let watermark1 = image.waterMarkedImage(waterMarkText: "@yourapp")
let watermark2 = image.waterMarkedImage(waterMarkText: "your app name", corner: .TopRight, margin: CGPoint(x: 5, y: 5), waterMarkTextColor: UIColor.greenColor())
let watermark3 = image.waterMarkedImage(waterMarkText: "appName", waterMarkTextColor: UIColor.blackColor(), waterMarkTextFont: UIFont(name: "Helvatica", size: 25)!)
extension UIImage
{
enum WaterMarkCorner
{
case TopLeft
case TopRight
case BottomLeft
case BottomRight
}
func waterMarkedImage(text:String, corner:WaterMarkCorner = .BottomRight, margin:CGPoint = CGPoint(x: 20, y: 20), color:UIColor = UIColor.white, font:UIFont = UIFont.systemFont(ofSize: 20), background:UIColor = UIColor.clear) -> UIImage?
{
let attributes = [NSAttributedStringKey.foregroundColor: color, NSAttributedStringKey.font:font]
let textSize = NSString(string: text).size(withAttributes: attributes)
var frame = CGRect(x: 0, y: 0, width: textSize.width, height: textSize.height)
let imageSize = self.size
switch corner
{
case .TopLeft:
frame.origin = margin
case .TopRight:
frame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: margin.y)
case .BottomLeft:
frame.origin = CGPoint(x: margin.x, y: imageSize.height - textSize.height - margin.y)
case .BottomRight:
frame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: imageSize.height - textSize.height - margin.y)
}
// Start creating the image with water mark
UIGraphicsBeginImageContext(imageSize)
self.draw(in: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
NSString(string: text).draw(in: frame, withAttributes: attributes)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Very nice piece of code. But it draws the text inside the image. I've done some editing in the code to draw the text below the image which I was looking for.
– Vakas
Jul 3 '15 at 4:28
The watermark is meant to be above the image not below!
– Hossam Ghareeb
Jul 3 '15 at 9:18
Here is a Swift version which correctly centers the text on the image. This works with text of various sizes.
func addTextToImage(text: NSString, inImage: UIImage, atPoint:CGPoint) -> UIImage{
// Setup the font specific variables
let textColor = YOURCOLOR
let textFont = YOUR SIZE
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
// Create bitmap based graphics context
UIGraphicsBeginImageContextWithOptions(inImage.size, false, 0.0)
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Our drawing bounds
let drawingBounds = CGRectMake(0.0, 0.0, inImage.size.width, inImage.size.height)
let textSize = text.sizeWithAttributes([NSFontAttributeName:textFont])
let textRect = CGRectMake(drawingBounds.size.width/2 - textSize.width/2, drawingBounds.size.height/2 - textSize.height/2,
textSize.width, textSize.height)
text.drawInRect(textRect, withAttributes: textFontAttributes)
// Get the image from the graphics context
let newImag = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImag
}
Use this method to add your textfield on image with selected font and color and size
//Method to add
- (UIImage *) addText:(UIImage *)img text:(NSString *)text
{
CGRect rect = CGRectMake(0,0, img.size.width, img.size.height);
// create a context according to image size
UIGraphicsBeginImageContext(rect.size);
// draw image
[img drawInRect:rect];
float fontSize = _txtvwEdit.font.pointSize*2;
NSLog(@"Original %f new %f",_txtvwEdit.font.pointSize,fontSize);
UIFont* font = [UIFont fontWithName:_txtvwEdit.font.fontName size:fontSize];
CGRect textRect = CGRectMake((_txtvwEdit.frame.origin.x*2)-5,_txtvwEdit.frame.origin.y*2,_txtvwEdit.frame.size.width*2,_txtvwEdit.frame.size.height*2);
if ([temparyGifframes count]>0)
{
font = [UIFont fontWithName:_txtvwEdit.font.fontName size:_txtvwEdit.font.pointSize];
textRect = CGRectMake(_txtvwEdit.frame.origin.x,_txtvwEdit.frame.origin.y ,_txtvwEdit.frame.size.width,_txtvwEdit.frame.size.height);
}
/// Make a copy of the default paragraph style
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
paragraphStyle.alignment = NSTextAlignmentLeft;
NSDictionary *attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: _txtvwEdit.textColor,NSParagraphStyleAttributeName: paragraphStyle };
// draw text
[text drawInRect:textRect withAttributes:attributes];
// get as image
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Considering performance, you should avoid having frequent calls to -drawRect:. Every UIView is backed with a CALayer and images as layer contents remain in memory as long as the CALayer stays in the hierarchy.This means that most of the operations you see in an application, including movement, rotation, and scaling of the view/layer, do not require a redraw.This means you can use add an CATextLayer on UIImageView , If you don't need a image with watermark.
https://developer.apple.com/library/ios/qa/qa1708/_index.html
- (void)addText:(NSString *)text inImageView:(UIImageView *)imageView {
CATextLayer *textLayer = [CATextLayer layer];
UIFont *font = [UIFont systemFontOfSize:14.0f];
CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.0f]}];
textLayer.frame = CGRectMake((imageView.size.width - textSize.width)/2,
(imageView.size.height - textSize.height)/2,
textSize.width, textSize.height);;
textLayer.string = text;
textLayer.fontSize = font.pointSize;
[imageView.layer addSublayer:textLayer];
}
- (void)addText:(NSString *)text inImageView:(UIImageView *)imageView {
CATextLayer *textLayer = [CATextLayer layer];
UIFont *font = [UIFont systemFontOfSize:14.0f];
CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.0f]}];
textLayer.frame = CGRectMake((imageView.size.width - textSize.width)/2,
(imageView.size.height - textSize.height)/2,
textSize.width, textSize.height);;
textLayer.string = text;
textLayer.fontSize = font.pointSize;
[imageView.layer addSublayer:textLayer];
}
In Swift-3 of @Jano Answer :-
func drawText(text:NSString ,image:UIImage ,point:CGPoint ) -> UIImage {
let font = UIFont.boldSystemFont(ofSize: 12)
UIGraphicsBeginImageContext(image.size)
image.draw(in:CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height) )
let rect = CGRect(x: point.x, y: point.y, width:image.size.width, height: image.size.height )
UIColor.white.set()
text.draw(in: rect.integral, withAttributes: [NSFontAttributeName : font])
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
Swift 3
extension UIImage {
func textToImage(drawText: NSString, atPoint:CGPoint) -> UIImage? {
// Setup the font specific variables
let textColor: UIColor = UIColor.white
let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 12)!
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(self.size)
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
] as [String : Any]
//Put the image into a rectangle as large as the original image.
self.draw(in: CGRect(x:0, y:0, width:self.size.width, height: self.size.height))
// Creating a point within the space that is as bit as the image.
let rect: CGRect = CGRect(x:atPoint.x, y:atPoint.y, width:self.size.width, height:self.size.height)
//Now Draw the text into an image.
drawText.draw(in: rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
}
}
Swift 3 version of @Hossam Ghareebs answer
and added the missing integration of the backgroundColor parameter:
enum WaterMarkCorner{
case TopLeft
case TopRight
case BottomLeft
case BottomRight
}
extension UIImage{
func waterMarkedImage(_ waterMarkText:String, corner:WaterMarkCorner = .TopRight, margin:CGPoint = CGPoint(x: 20, y: 20), waterMarkTextColor:UIColor = UIColor.black, waterMarkTextFont:UIFont = UIFont.systemFont(ofSize: 40), backgroundColor:UIColor = UIColor(white: 1.0, alpha: 0.5)) -> UIImage?{
let textAttributes = [NSForegroundColorAttributeName:waterMarkTextColor, NSFontAttributeName:waterMarkTextFont, NSBackgroundColorAttributeName: backgroundColor]
let textSize = NSString(string: waterMarkText).size(attributes: textAttributes)
var textFrame = CGRect(x:0, y:0, width:textSize.width, height:textSize.height)
let imageSize = self.size
switch corner{
case .TopLeft:
textFrame.origin = margin
case .TopRight:
textFrame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: margin.y)
case .BottomLeft:
textFrame.origin = CGPoint(x: margin.x, y: imageSize.height - textSize.height - margin.y)
case .BottomRight:
textFrame.origin = CGPoint(x: imageSize.width - textSize.width - margin.x, y: imageSize.height - textSize.height - margin.y)
}
/// Start creating the image with water mark
UIGraphicsBeginImageContext(imageSize)
self.draw(in: CGRect(x:0, y:0, width:imageSize.width, height:imageSize.height))
NSString(string: waterMarkText).draw(in: textFrame, withAttributes: textAttributes)
let waterMarkedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return waterMarkedImage
}
}
UIImageView *imageView = [UIImageView alloc];
imageView.image = [UIImage imageNamed:@"img.png"];
UILabel *label = [UILabel alloc];
label.text = @"Your text";
[imageView addsubview:label];
Set the frame of the label where you want the label to be displayed.
Don't forget to release label after adding it as the subView.
– Akshay
Aug 9 '11 at 8:01
I want to make it a complete image(image + label) and add it in the background of the button.
– Sanchit Paurush
Aug 9 '11 at 8:50
In that case you may want to create the image and label in gimp/photoshop and use it as a background image for a button.
– Praveen S
Aug 9 '11 at 9:01
Other method would be to place a clear color button on top of the image view. It will give the same impression.
– Praveen S
Aug 9 '11 at 9:01
Question is for text on image, not imageView.
– Boris Nikolić
Apr 18 '16 at 12:35
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
Have you tried UIImage and UILabel?
– Praveen S
Aug 9 '11 at 7:34