Search code examples
swiftuiimageuitextfielduigraphicscontext

Merge an image and text creating another image in swift 4


I am trying to merge an UIImage and a text of an UITextField creating another Image, but I hadn't any success.

What does my app to do? or should it do?

Basically it takes the image created by the method snapshot, merge that image with a text from UITextField, creating an other image that will be save and shows in a tableView.

But I'm having a lot of trouble making it work.

When I take only the image everything works well. Follow my code.

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first, let startPoint = startPoint else {return}
    let currentPoint = touch.location(in: imageView)
    let frame = rect(from: startPoint, to: currentPoint)

    rectShapeLayer.removeFromSuperlayer()


    if frame.size.width < 1{
        tfText.resignFirstResponder()
    } else {
        let memedImage = getImage(frame: frame, imageView: self.imageView)
        save(imageView: imageView, image: memedImage)
    }
}

func getImage(frame: CGRect, imageView: UIImageView) -> UIImage {

    let cropImage = imageView.snapshot(rect: frame, afterScreenUpdates: true)

    return cropImage

But when I try to create an Image using UIGraphicsBeginImageContextWithOptions to merge it with a textField, I fail.

Follow my code

   override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first, let startPoint = startPoint else {return}
    let currentPoint = touch.location(in: imageView)
    let frame = rect(from: startPoint, to: currentPoint)

    rectShapeLayer.removeFromSuperlayer()


    if frame.size.width < 1{
        tfText.resignFirstResponder()
    } else {
        let memedImage = getImage(frame: frame, imageView: self.imageView)
        save(imageView: imageView, image: memedImage)
    }
}

func getImage(frame: CGRect, imageView: UIImageView) -> UIImage {

    let cropImage = imageView.snapshot(rect: frame, afterScreenUpdates: true)

    UIGraphicsBeginImageContextWithOptions(cropImage.size, false, 0.0)

    cropImage.draw(in: frame)
    tfText.drawText(in: frame)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return newImage
}

Let me show you some screenshots of the my app.

First creating only image. enter image description here

enter image description here

enter image description here

Now when I try to merge the text and image. enter image description here

Please, look at the debug area.

The images are created, but they don’t show up on the tableView.

What am I doing wrong?

UPDATE THE QUESTION

With the code above my memedImage is empty. "Thanks Rob"

So, I changed my previous getImage(_:) to:

   func getANewImage(frame: CGRect, imageView: UIImageView, textField: UITextField) -> UIImage{

    let cropImage = imageView.snapshot(rect: frame, afterScreenUpdates: true)

    let newImageView = UIImageView(image: cropImage)

    UIGraphicsBeginImageContextWithOptions(newImageView.frame.size, false, 0.0)

    let context = UIGraphicsGetCurrentContext()!

    context.translateBy(x: newImageView.frame.origin.x, y: newImageView.frame.origin.y)
    newImageView.layer.render(in: context)
    textField.layer.render(in: context)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return newImage
}

That way I almost got... I created a new image with the textField, but the textField changed its position, it should be in the center.

enter image description here

With .draw does't work, but with layer.render works almost well.


Solution

  • I almost didn't have help with that question, only a litte hint of the my friend Rob. Thank you again Rob.

    Likely, I found out how to fix the problem with the TextField position and I'd like to share the solution.

    func getImage(frame: CGRect, imageView: UIImageView, textField: UITextField) -> UIImage{
    
        //Get the new image after snapshot method
        let cropImage = imageView.snapshot(rect: frame, afterScreenUpdates: true)
    
        //Create new imageView with the cropImage
        let newImageView = UIImageView(image: cropImage)
    
        //Origin point of the Snapshot Frame.
        let frameOriginX = frame.origin.x
        let frameOriginY = frame.origin.y
    
        UIGraphicsBeginImageContextWithOptions(newImageView.frame.size, false, cropImage.scale)
        let context = UIGraphicsGetCurrentContext()!
    
        //Render the "cropImage" in the CGContext
        newImageView.layer.render(in: context)
    
        //Position of the TextField
        let tf_X = textField.frame.origin.x - frameOriginX
        let tf_Y = textField.frame.origin.y - frameOriginY
    
        //Context Translate with TextField position
        context.translateBy(x: tf_X, y: tf_Y)
    
        //Render the "TextField" in the CGContext
        textField.layer.render(in: context)
    
        //Create newImage
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
    
        return newImage
    }
    

    Of course this code can be optimized, but it worked very well for me.