How to create an image from UILabel?
Asked Answered
G

6

30

I'm currently developing a simple photoshop like application on iphone. When I want to flatten my layers, the labels are at the good position but with a bad font size. Here's my code to flatten :

UIGraphicsBeginImageContext(CGSizeMake(widthDocument,widthDocument));

for (UILabel *label in arrayLabel) {
    [label drawTextInRect:label.frame];
}

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Anybody can help me ?

Geotaxis answered 8/8, 2012 at 14:48 Comment(0)
C
53

From: pulling an UIImage from a UITextView or UILabel gives white image.

// iOS

- (UIImage *)grabImage {
    // Create a "canvas" (image context) to draw in.
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0);  // high res
    // Make the CALayer to draw in our "canvas".
    [[self layer] renderInContext: UIGraphicsGetCurrentContext()];

    // Fetch an UIImage of our "canvas".
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // Stop the "canvas" from accepting any input.
    UIGraphicsEndImageContext();

    // Return the image.
    return image;
}

// Swift extension w/ usage. credit @Heberti Almeida in below comments

extension UIImage {
    class func imageWithLabel(label: UILabel) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
        label.layer.renderInContext(UIGraphicsGetCurrentContext()!)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img
    }
}

The usage:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 22))
label.text = bulletString
let image = UIImage.imageWithLabel(label)
Chockablock answered 8/8, 2012 at 15:8 Comment(5)
Yes, I had seen this post but with this solution i can't get à high definition file. But you make me understood where is my problem ! Thank you very much!!Geotaxis
@Chockablock To get a sharp image for retina display, we need to replace the first line in your method by this line: UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0); as seen in this question and its accepted answer. Perhaps you might want to update your answer including that information.Kurd
If you need a transparent image set opaque to NO in UIGraphicsBeginImageContextWithOptionsBeard
is it possible to render the label to 3 times its actual size without losing sharpness?Bradybradycardia
Needed to change label.layer.renderInContext(UIGraphicsGetCurrentContext()!) to label.layer.render(in: UIGraphicsGetCurrentContext()!) in Swift 5Olympus
B
25

I have created a Swift extension to render the UILabel into a UIImage:

extension UIImage {
    class func imageWithLabel(label: UILabel) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
        label.layer.renderInContext(UIGraphicsGetCurrentContext()!)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img
    }
}

EDIT: Improved Swift 4 version

extension UIImage {
    class func imageWithLabel(_ label: UILabel) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
        defer { UIGraphicsEndImageContext() }
        label.layer.render(in: UIGraphicsGetCurrentContext()!)
        return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
    }
}

The usage is simple:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 22))
label.text = bulletString
let image = UIImage.imageWithLabel(label)
Beard answered 5/11, 2015 at 13:33 Comment(0)
S
5

you need to render the label in a context

replace

[label drawTextInRect:label.frame];

with

[label.layer renderInContext:UIGraphicsGetCurrentContext()];

and you will need to create one image per label, so move the for loop to outside the begin and end context calls

Seng answered 8/8, 2012 at 15:9 Comment(0)
E
3

for Swift, I use this UIView-extension:

// Updated for Swift 3.0
extension UIView {
    var grabbedImage:UIImage? {
        get {
            UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
            layer.render(in: UIGraphicsGetCurrentContext()!)
            let img = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return img
        }
    }
}
Evacuee answered 7/7, 2016 at 8:5 Comment(0)
M
1

You can use renderInContext on any CALayer. It will draw your view's layer on the context. So that you can change it to an image. Also if you do renderInContext on a view , all its subviews will be drawn onto the context. So instead of iterating through all the labels, while adding the labels, you can add those to a containerView. And just need to do renderInContext on that containerView.

Mucoprotein answered 8/8, 2012 at 19:41 Comment(0)
C
1
extension UIImage {

    class func imageFrom(text: String, width: CGFloat, font: UIFont, textAlignment: NSTextAlignment, lineBreakMode: NSLineBreakMode) -> UIImage? {
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        label.text = text
        label.font = font
        label.textAlignment = textAlignment
        label.lineBreakMode = lineBreakMode

        label.sizeToFit()

        UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
        label.layer.render(in: UIGraphicsGetCurrentContext()!)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img
    }

}

Using:

    let iv = UIImageView(image: UIImage.imageFrom(text: "Test For \nYarik", width: 537.0, font: UIFont.systemFont(ofSize: 30), textAlignment: .center, lineBreakMode: .byWordWrapping))
    iv.contentMode = .scaleAspectFit
Chrominance answered 9/10, 2018 at 14:50 Comment(1)
Please don't paste in code without any explanation.Wheedle

© 2022 - 2024 — McMap. All rights reserved.