How to create an image from UILabel?

2019-01-08 20:36发布

问题:

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 ?

回答1:

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)


回答2:

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)


回答3:

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



回答4:

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


回答5:

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.



回答6:

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