Converting Text to Image on iOS

image, ios, rendering, text, uiimageview

Solution

With Swift 5 and iOS 12, you can choose one the 6 following ways in order to solve your problem.

#1. Using `NSString`'s `draw(at:withAttributes:)` method

In the simplest case where you want to convert a `String` to a `UIImage` with some attributes, you can use `draw(at:withAttributes:)`. The following Playground codes show how to get an `UIImage` from a `String` using `draw(at:withAttributes:)`:

import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

UIGraphicsBeginImageContextWithOptions(textSize, true, 0)
text.draw(at: CGPoint.zero, withAttributes: attributes)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

PlaygroundPage.current.liveView = UIImageView(image: image)
import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

let renderer = UIGraphicsImageRenderer(size: textSize)
let image = renderer.image(actions: { context in
    text.draw(at: CGPoint.zero, withAttributes: attributes)
})

PlaygroundPage.current.liveView = UIImageView(image: image)

Note that `NSAttributedString` has a similar method called `draw(at:)`.

#2. Using `NSString`'s `draw(in:withAttributes:)` method

As an alternative to `draw(at:withAttributes:)`, you can use `draw(in:withAttributes:)`.

import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

UIGraphicsBeginImageContextWithOptions(textSize, true, 0)
let rect = CGRect(origin: .zero, size: textSize)
text.draw(in: rect, withAttributes: attributes)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

PlaygroundPage.current.liveView = UIImageView(image: image)
import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

let renderer = UIGraphicsImageRenderer(size: textSize)
let image = renderer.image(actions: { context in
    let rect = CGRect(origin: .zero, size: textSize)
    text.draw(in: rect, withAttributes: attributes)
})

PlaygroundPage.current.liveView = UIImageView(image: image)

Note that `NSAttributedString` has a similar method called `draw(in:)`.

#3. Using `NSString`'s `draw(with:options:attributes:context:)` method

As an alternative to `draw(at:withAttributes:)` and `draw(in:)`, you can use `draw(with:options:attributes:context:)`. Note that Apple has some recommendations for `draw(with:options:attributes:context:)`:

This method uses the baseline origin by default. If `usesLineFragmentOrigin` is not specified, the rectangle’s height will be ignored and the operation considered to be single-line rendering.

import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

UIGraphicsBeginImageContextWithOptions(textSize, true, 0)
let rect = CGRect(origin: .zero, size: textSize)
text.draw(with: rect, options: [.usesLineFragmentOrigin], attributes: attributes, context: nil)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

PlaygroundPage.current.liveView = UIImageView(image: image)
import UIKit
import PlaygroundSupport

let text = "Hello, world"
let attributes = [
    NSAttributedString.Key.foregroundColor: UIColor.yellow,
    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)
]
let textSize = text.size(withAttributes: attributes)

let renderer = UIGraphicsImageRenderer(size: textSize)
let image = renderer.image(actions: { context in
    text.draw(with: .zero, options: [.usesLineFragmentOrigin], attributes: attributes, context: nil)
})

PlaygroundPage.current.liveView = UIImageView(image: image)

Note that `NSAttributedString` has a similar method called `draw(with:options:context:)`.

#4. Using `CALayer`'s `render(in:)` method

If you want to capture the text of a `UILabel`, `UITextField` or `UITextView` to a `UIImage`, you can use `render(in:)`. The following Playground codes show how to snapshot the content text of a `UILabel` using `render(in:)`:

import UIKit
import PlaygroundSupport

let label = UILabel(frame: .zero)
label.textColor = .yellow
label.font = UIFont.systemFont(ofSize: 22)
label.text = "Hello, world"
label.sizeToFit()

UIGraphicsBeginImageContextWithOptions(label.frame.size, true, 0)
guard let context = UIGraphicsGetCurrentContext() else { exit(0) }
label.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

PlaygroundPage.current.liveView = UIImageView(image: image)
import UIKit
import PlaygroundSupport

let label = UILabel(frame: .zero)
label.textColor = .yellow
label.font = UIFont.systemFont(ofSize: 22)
label.text = "Hello, world"
label.sizeToFit()

let renderer = UIGraphicsImageRenderer(size: label.frame.size)
let image = renderer.image(actions: { context in
    label.layer.render(in: context.cgContext)
})

PlaygroundPage.current.liveView = UIImageView(image: image)

#5. Using `UIView`'s `drawHierarchy(in:afterScreenUpdates:)` method

If you want to capture the text of a `UILabel`, `UITextField` or `UITextView` to a `UIImage`, you can use `drawHierarchy(in:afterScreenUpdates:)`. Note that Apple has some recommendations for `drawHierarchy(in:afterScreenUpdates:)`:

Use this method when you want to apply a graphical effect, such as a blur, to a view snapshot. This method is not as fast as the `snapshotView(afterScreenUpdates:)` method.

import UIKit
import PlaygroundSupport

let label = UILabel(frame: .zero)
label.textColor = .yellow
label.font = UIFont.systemFont(ofSize: 22)
label.text = "Hello, world"
label.sizeToFit()

UIGraphicsBeginImageContextWithOptions(label.frame.size, true, 0)    
_ = label.drawHierarchy(in: label.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

PlaygroundPage.current.liveView = UIImageView(image: image)
import UIKit
import PlaygroundSupport

let label = UILabel(frame: .zero)
label.textColor = .yellow
label.font = UIFont.systemFont(ofSize: 22)
label.text = "Hello, world"
label.sizeToFit()

let renderer = UIGraphicsImageRenderer(size: label.frame.size)
let image = renderer.image(actions: { context in
    _ = label.drawHierarchy(in: label.bounds, afterScreenUpdates: true)
})

PlaygroundPage.current.liveView = UIImageView(image: image)

#6. Using `UIView`'s `snapshotView(afterScreenUpdates:)` method

If it's OK for you to get a `UIView` instead of a `UIImage` from your snapshot operation, you can use `snapshotView(afterScreenUpdates:)`. The following Playground code shows how to snapshot the content text of a `UILabel` into a `UIView` using `snapshotView(afterScreenUpdates:)`:

import UIKit
import PlaygroundSupport

let label = UILabel(frame: .zero)
label.textColor = .yellow
label.font = UIFont.systemFont(ofSize: 22)
label.text = "Hello, world"
label.sizeToFit()

let view = label.snapshotView(afterScreenUpdates: true)
PlaygroundPage.current.liveView = view

Problem

How to convert Text to Image and show in UIImageview. Can anyone know the conversion from Text to Image?

Original source