user2786
user2786

Reputation: 716

How to generate an UIImage from custom text in Swift

I am trying to generate an UIImage from custom text in Swift3.

Using iOS Controls, It's possible to create an UIImage, below is the code:

class func imageWithText(txtField: UITextField) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(txtField.bounds.size, false, 0.0)
        txtField.layer.render(in: UIGraphicsGetCurrentContext()!)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }

Note: I know it's also possible to add some text to an image, but I don't want to do like this.

Can someone help me to resolve this? Thank you!

Upvotes: 18

Views: 16558

Answers (3)

Fattie
Fattie

Reputation: 12625

In re this very old question, it's honestly now this simple:

Make a square of color:

let image = UIGraphicsImageRenderer(size: size).image { rendererContext in
    UIColor.yellow.setFill()
    rendererContext.fill(rect)
}

Adding text is nowadays this simple:

let image = UIGraphicsImageRenderer(size: sz).image { rendererContext in
    UIColor.yellow.setFill()
    rendererContext.fill(rect)
    "fattie".draw(in: rect)
}

That's the whole thing.

    "some text".draw(in: rect)

To set the scale (likely "1"), font, blah blah etc ...

let sz = CGSize(width: 500, height: 300)
let frame = CGRect(origin: .zero, size: sz).insetBy(dx: 40, dy: 40)
let fmt = UIGraphicsImageRendererFormat()
fmt.scale = 1
let att = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 50.0)]

let image = UIGraphicsImageRenderer(size: sz, format: fmt).image { rendererContext in
    UIColor.systemYellow.setFill()
    rendererContext.fill(CGRect(origin: .zero, size: sz))
    "fattie?!".draw(in: frame, withAttributes: att)
}

if let data = image.jpegData(compressionQuality: 0.4) {
    let pp = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let ff = pp.appendingPathComponent("example.jpg")
    try? data.write(to: ff)
    print("On your mac look in: \(pp.path)")
}

enter image description here

ok?

Upvotes: 3

rollingcodes
rollingcodes

Reputation: 16008

Here is a String extension that can be used as shown below to create UIImage instances from a String instance, without the need for UI controls like UITextField or UILabel:

var image: UIImage? =
    "Test".image(withAttributes: [
        .foregroundColor: UIColor.red,
        .font: UIFont.systemFont(ofSize: 30.0),
    ], size: CGSize(width: 300.0, height: 80.0))

// Or
image = "Test".image(withAttributes: [.font: UIFont.systemFont(ofSize: 80.0)])

// Or
image = "Test".image(size: CGSize(width: 300.0, height: 80.0))

// Or even just
image = "Test".image()

Playground Sampler

Below are two possible implementations for achieving the desired effect demonstrated above:

UIGraphicsImageRenderer Method (more performant and recommended implementation by Apple)

extension String {
    
    /// Generates a `UIImage` instance from this string using a specified
    /// attributes and size.
    ///
    /// - Parameters:
    ///     - attributes: to draw this string with. Default is `nil`.
    ///     - size: of the image to return.
    /// - Returns: a `UIImage` instance from this string using a specified
    /// attributes and size, or `nil` if the operation fails.
    func image(withAttributes attributes: [NSAttributedString.Key: Any]? = nil, size: CGSize? = nil) -> UIImage? {
        let size = size ?? (self as NSString).size(withAttributes: attributes)
        return UIGraphicsImageRenderer(size: size).image { _ in
            (self as NSString).draw(in: CGRect(origin: .zero, size: size),
                                    withAttributes: attributes)
        }
    }
    
}

UIGraphicsImageContext Method (old-school; included for thoroughness)

extension String {
    
    /// Generates a `UIImage` instance from this string using a specified
    /// attributes and size.
    ///
    /// - Parameters:
    ///     - attributes: to draw this string with. Default is `nil`.
    ///     - size: of the image to return.
    /// - Returns: a `UIImage` instance from this string using a specified
    /// attributes and size, or `nil` if the operation fails.
    func image(withAttributes attributes: [NSAttributedString.Key: Any]? = nil, size: CGSize? = nil) -> UIImage? {
        let size = size ?? (self as NSString).size(withAttributes: attributes)
        UIGraphicsBeginImageContext(size)
        (self as NSString).draw(in: CGRect(origin: .zero, size: size), 
                                withAttributes: attributes)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
    
}

Upvotes: 39

A.Munzer
A.Munzer

Reputation: 1990

You can use this function, you can send any text to this function, inside it i create UILabel and set text attribute as you like

func imageWith(name: String?) -> UIImage? {
     let frame = CGRect(x: 0, y: 0, width: 100, height: 100)
     let nameLabel = UILabel(frame: frame)
     nameLabel.textAlignment = .center
     nameLabel.backgroundColor = .lightGray
     nameLabel.textColor = .white
     nameLabel.font = UIFont.boldSystemFont(ofSize: 40)
     nameLabel.text = name
     UIGraphicsBeginImageContext(frame.size)
      if let currentContext = UIGraphicsGetCurrentContext() {
         nameLabel.layer.render(in: currentContext)
         let nameImage = UIGraphicsGetImageFromCurrentImageContext()
         return nameImage
      }
      return nil
}

Upvotes: 28

Related Questions