78

I want to make an image like this programmatically:

example

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.

Ramkumar Paulraj
  • 1,841
  • 2
  • 20
  • 40
Sanchit Paurush
  • 6,114
  • 17
  • 68
  • 107

15 Answers15

178

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 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.

Jano
  • 62,815
  • 21
  • 164
  • 192
  • 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 09 '11 at 09:21
  • Thanks bro. It works perfectly. one last thing to ask, How to set the background of that text as I shown u in my sample Picture – Sanchit Paurush Aug 09 '11 at 09:59
  • Wow, Looking as I wanted. U r perfect in image and graphics of objective-c. Thanks again – Sanchit Paurush Aug 09 '11 at 10:28
  • 1
    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 06:00
  • 3
    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 06:21
  • ok. i need to capture image and i need to put that captured image to uiimageview. then i need to enter some text using text field and that text should display on the uipicker view and wheni save i need to save both image and the text is it possible @sanchitsingh – sachi Mar 29 '12 at 06:33
  • I tried as you told but getting error like 'RootViewController' may not respond to '-drawText:inImage:atPoint:' @sanchitsingh – sachi Mar 29 '12 at 06:38
  • This error comes when you have not declared the method in .h file. Declare the method in .h file and define it in .m file. then it will work properly @sachi – Sanchit Paurush Mar 29 '12 at 07:02
  • I have declared drawText in .h file as +(UIImage*) drawText(NSString*) text inImage:(UIImage*) image atPoint:(CGPoint) point ; But still i am getting the same error. – sachi Mar 29 '12 at 07:07
  • @sanchitsingh brother thanks a lot it work for me. It was my mistake for getting those errors. – sachi Mar 29 '12 at 07:25
  • Where can i get the ImageUtils.h files? – Oleg Aug 02 '12 at 15:35
  • Make a ImageUtils class and add the method at the top. – Jano Aug 02 '12 at 18:16
  • Does this code add text to an image and changing the original image? i want to use that code to add text-labels to a rolling wheel menu, the label's each time before the start should be updated from a web service...is this code fits? – Oleg Aug 03 '12 at 16:55
  • 1
    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 03 '12 at 16:58
  • Can i add a label to image with the same idea of the function and not NSString? – Oleg Aug 05 '12 at 08:43
  • @Jano I am trying to draw the solid black color rectangle behind the the white color text. But I am failed, can you help me? CGRect rect = CGRectMake(10, (img.size.height-[text1 sizeWithAttributes:attributesDictionary].height),img.size.width, img.size.height); [[UIColor whiteColor] set]; CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, (img.size.height-[text1 sizeWithAttributes:attributesDictionary].height),img.size.width, img.size.height)); [[UIColor blackColor] set]; – Khalid Usman Dec 14 '13 at 09:52
  • I wanted to add a background to the images which I needed to be opaque I have tryed to use `CGContextFillRect ` method. Frame of my string was the frame of image and it made weird shadow like borders. Adding attribute`NSBackgroundColorAttributeName: [UIColor whiteColor]` to my string worked for me. – Zuzana Paulis Mar 23 '16 at 20:31
35

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

iGranDav
  • 2,450
  • 1
  • 21
  • 25
  • 9
    Thanks...I needed to move the color into the att dictionary to work in iOS7: NSDictionary *att = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: [UIColor whiteColor]}; – Symmetric Mar 06 '14 at 02:27
  • 2
    Replace the first line to this for higher text quality: `UIGraphicsBeginImageContextWithOptions(image.size, YES, 0.0f);` – SoftDesigner Nov 21 '14 at 13:16
  • not UIGraphicsBeginImageContext, but UIGraphicsBeginImageContextWithOptions – brbgyn Apr 06 '15 at 02:04
19

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.

Community
  • 1
  • 1
Christopher Wade Cantley
  • 7,122
  • 5
  • 35
  • 48
18

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"];
neoneye
  • 50,398
  • 25
  • 166
  • 151
12

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();
nunoines
  • 121
  • 1
  • 3
  • 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
7

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)!)

Swift 4.0 version:

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
    }

}
Kaolin Fire
  • 2,521
  • 28
  • 43
Hossam Ghareeb
  • 7,063
  • 3
  • 53
  • 64
  • 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 03 '15 at 04:28
  • The watermark is meant to be above the image not below! – Hossam Ghareeb Jul 03 '15 at 09:18
2

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

}
1

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; 
}
Heefan
  • 385
  • 2
  • 8
Piyushkumar
  • 418
  • 4
  • 10
0

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

    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];
}
MikeG
  • 3,745
  • 1
  • 29
  • 51
RY_ Zheng
  • 3,041
  • 29
  • 36
  • imageView.size.width will give following error Property 'size' not found on object of type 'UIImageView *' To resolve this error user imageView.frame.size.width – Anand Jun 13 '23 at 09:19
0

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!
    }
Shrawan
  • 7,128
  • 4
  • 29
  • 40
0

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

    }
}
johnnyMac
  • 381
  • 2
  • 14
0

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
    }
}
0

My function can add text water mark on image with 45 degree and 90 degree rotations

+(UIImage *)drawText:(NSString *)text diagonallyOnImage:(UIImage *)image rotation:(WatermarkRotation)rotation{

    UIColor *textColor = [UIColor colorWithRed:255 green:0 blue:0 alpha:0.2];//[UIColor colorWithWhite:0.5 alpha:1.0];
    UIFont *font = [UIFont systemFontOfSize:250];

    // Compute rect to draw the text inside
    NSDictionary *attr = @{NSForegroundColorAttributeName: textColor, NSFontAttributeName: font};
    CGSize textSize = [text sizeWithAttributes:attr];
    CGSize imageSize = image.size;
    // Create a bitmap context into which the text will be rendered.
    UIGraphicsBeginImageContext(textSize);
    // Render the text
    [text drawAtPoint:CGPointMake(0,0) withAttributes:attr];
    // Retrieve the image
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext();

    CGImageRef imageRef = [img CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);


    CGContextRef bitmap = CGBitmapContextCreate(NULL, textSize.width, textSize.width, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    switch (rotation) {
        case WatermarkRotation90left:
            CGContextRotateCTM (bitmap, DEGREES_RADIANS(-90));
            CGContextTranslateCTM(bitmap, -textSize.width, 0);
            break;

        case WatermarkRotation90right:
            CGContextRotateCTM (bitmap, DEGREES_RADIANS(90));
            CGContextTranslateCTM(bitmap, 0, -textSize.width);
            break;

        case WatermarkRotation45ltr:
            CGContextRotateCTM (bitmap, DEGREES_RADIANS(45));
            CGContextTranslateCTM(bitmap, textSize.width/4, -textSize.width/2);
            break;

        case WatermarkRotation45rtl:
            CGContextRotateCTM (bitmap, DEGREES_RADIANS(-45));
            CGContextTranslateCTM(bitmap, -textSize.width/2, textSize.width/4);
            break;

        default:
            break;
    }

    CGContextDrawImage(bitmap, CGRectMake(0, (textSize.width/2)-(textSize.height/2), textSize.width, textSize.height), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    UIGraphicsBeginImageContext( imageSize );

    // Use existing opacity as is
    [image drawInRect:CGRectMake(0,0,imageSize.width,imageSize.height)];


    if (rotation == WatermarkRotation90left) {
        [newImage drawInRect:CGRectMake(-((textSize.width/2)-(textSize.height/2)),(imageSize.height/2)-(textSize.width/2),textSize.width,textSize.width) blendMode:kCGBlendModeNormal alpha:1.0];
    }else if(rotation == WatermarkRotation90right){
        [newImage drawInRect:CGRectMake((imageSize.width-textSize.width/2)-(textSize.height/2),(imageSize.height/2)-(textSize.width/2),textSize.width,textSize.width) blendMode:kCGBlendModeNormal alpha:1.0];
    }else{
        [newImage drawInRect:CGRectMake((imageSize.width/2)-(textSize.width/2),(imageSize.height/2)-(textSize.width/2),textSize.width,textSize.width) blendMode:kCGBlendModeNormal alpha:1.0];
    }


    UIImage *mergedImage = UIGraphicsGetImageFromCurrentImageContext();


    UIGraphicsEndImageContext();
    return mergedImage;
}

Enum for rotation:

typedef enum:NSUInteger{
    WatermarkRotation90left=1,
    WatermarkRotation90right,
    WatermarkRotation45ltr,
    WatermarkRotation45rtl
}WatermarkRotation;

Note: Use 0 for drawing watermark in centre of image.(Default case of switch statement)

Add this macro for degree to radian:

#define DEGREES_RADIANS(angle) ((angle) / 180.0 * M_PI)

Hope this helps !!!

Harish Pathak
  • 1,567
  • 1
  • 18
  • 32
0

I built a solution based on the example provided by @harish-pathak. It takes devices with HiDPI-displays into consideration (size is int, whereas left and top are percent as double).

-(UIImage *)drawText:(NSString *)text onImage:(UIImage *)image withSize:(NSInteger)size posLeft:(double)left posTop:(double)top {
    
    // Get UI scale for HiDPI
    CGFloat scale = [[UIScreen mainScreen] scale];
    
    UIColor *textColor = [UIColor whiteColor];
    UIFont *font = [UIFont fontWithName:@"Font-Name" size:size];
    
    // Compute rect to draw the text inside
    NSDictionary *attr = @{NSForegroundColorAttributeName: textColor, NSFontAttributeName: font};
    CGSize textSize = [text sizeWithAttributes:attr];
    CGSize imageSize = image.size;
    
    // Create a bitmap context into which the text will be rendered
    UIGraphicsBeginImageContextWithOptions(textSize, NO, scale);
    
    // Render the text
    [text drawAtPoint:CGPointMake(0,0) withAttributes:attr];
    // Retrieve the image
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext();

    CGImageRef imageRef = [img CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
    
    // Create bitmap context for text
    CGFloat scaledTextWidth = textSize.width * scale;
    CGFloat scaledTextHeight = textSize.height * scale;
    CGContextRef textBitmap = CGBitmapContextCreate(NULL, scaledTextWidth, scaledTextHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
    
    // Scale text for HiDPI devices
    CGContextScaleCTM(textBitmap, scale, scale);
    
    // Draw image for text
    CGRect textPosition = CGRectMake(0, 0, textSize.width, textSize.height);
    CGRect textPixelAligned = CGRectIntegral(textPosition);
    CGContextDrawImage(textBitmap, textPixelAligned, imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(textBitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];
    
    // Create bitmap context into which the image will be rendered
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, scale);

    // Use existing opacity as is
    [image drawInRect:CGRectMake(0,0,imageSize.width,imageSize.height)];
    
    // Create new image with blendmode "normal"
    CGFloat textLeft = (imageSize.width*left)-(textSize.width*0.5);
    CGFloat textTop = (imageSize.height*top)-(textSize.height*0.5);
    CGRect imagePosition = CGRectMake(textLeft,textTop,textSize.width,textSize.height);
    CGRect imagePixelAligned = CGRectIntegral(imagePosition);
    [newImage drawInRect:imagePixelAligned blendMode:kCGBlendModeNormal alpha:1.0];
    
    // Get merged image from context
    UIImage *mergedImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    return mergedImage;
}

To center text on image call the function like this:

[self drawText:@"Text" onImage:img withSize:120 posLeft:0.5 posTop:0.5];

Credits to:

Rafa2602
  • 423
  • 4
  • 12
-2
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.

Praveen S
  • 10,355
  • 2
  • 43
  • 69