Hassan Shahbazi
Hassan Shahbazi

Reputation: 1603

Merge two UIImages swift 4

I have a captured image from a device's camera and I want to add a UITextView on it and then save it into the gallery. I'm using the following code to get an image from the text view

extension UITextView {
    var imageOfView: UIImage {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)
        self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return image!
    }
}

Then, by using the following code, I try to add the above image to the taken image:

extension UIImage {

    func combine(with image: UIImage, at point: CGPoint, isLandscapeMode: Bool = false) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, 0.0)

        self.draw(at: .zero)
        image.draw(at: point)

        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return result!
    }
}

finally, I call the method here to send the edited image to the previous page:

onImageEdited?(capturedImage.combine(with: textArea.imageOfView, at: textArea.frame.origin, isLandscapeMode: true))

Looking at the below screenshots, it's seen that the size changes and the position seem to be randomly chosen. Any idea why and how can I fix that?

During the editing:

before saving changes

After it's saved:

after saving changes

P.S: The captured image and the editing page are in Landscape mode

Upvotes: 0

Views: 338

Answers (3)

Wide Angle Technology
Wide Angle Technology

Reputation: 1222

Try this one, I have commented the code which I have edited from the above code, please check it out and let me know it worked for you.

func stitchImages(images: [UIImage], isVertical: Bool) -> UIImage {
    var stitchedImages : UIImage!
    if images.count > 0 {
        var maxWidth = CGFloat(0), maxHeight = CGFloat(0)
        for image in images {
            if image.size.width > maxWidth {
                maxWidth = image.size.width
            }
            if image.size.height > maxHeight {
                maxHeight = image.size.height
            }
        }
        var totalSize : CGSize
        let maxSize = CGSize(width: maxWidth, height: maxHeight)
        if isVertical {
            totalSize = CGSize(width: maxSize.width, height: maxSize.height * (CGFloat)(images.count))
        } else {
            totalSize = CGSize(width: maxSize.width, height:  maxSize.height)
        }
        UIGraphicsBeginImageContext(totalSize)

        let offset = (CGFloat)(0)
        // Need to change or adjust the frame get get reach your reqirement
        let rect1 = AVMakeRect(aspectRatio: images[1].size, insideRect: isVertical ? CGRect(x: 0, y: maxSize.height * offset, width: maxSize.width, height: maxSize.height) : CGRect(x: maxSize.width * offset, y: 0, width: maxSize.width, height: maxSize.height))
        images[1].draw(in: rect1)

        let rect2  = AVMakeRect(aspectRatio: images[0].size, insideRect: isVertical ? CGRect(x: 0, y: maxSize.height * offset, width: maxSize.width - 60, height: maxSize.height - 500) : CGRect(x: maxSize.width * offset, y: 250, width: maxSize.width - 60, height: maxSize.height - 500))
        images[0].draw(in: rect2)

        //            for image in images {
        //                let offset = (CGFloat)(0)
        //                let rect =  AVMakeRect(aspectRatio: image.size, insideRect: isVertical ?
        //                    CGRect(x: 0, y: maxSize.height * offset, width: maxSize.width, height: maxSize.height) :
        //                    CGRect(x: maxSize.width * offset, y: 0, width: maxSize.width, height: maxSize.height))
        //                image.draw(in: rect)
        //            }

        stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
    return stitchedImages
}

Upvotes: 0

Nathan
Nathan

Reputation: 949

func combine(text: String, withImage image: UIImage, atPoint point: CGPoint) -> UIImage? {

        // Variables
        let textColor = UIColor.white
        let font = UIFont.systemFont(ofSize: 12)

        let attributes: [NSAttributedStringKey: Any] = [
            .foregroundColor: textColor,
            .font: font
        ]

        // Set scale and begin context
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

        // Draw
        image.draw(in: CGRect(origin: .zero, size: image.size))
        let rect = CGRect(origin: point, size: image.size)
        text.draw(in: rect, withAttributes: attributes)

        // Get the new image
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage

    }

You could also create an extension for UIImageView and render a new image from all of its subviews (e.x. the UITextView)

extension UIImageView {

    func renderSubviewsToImage() -> UIImage? {

        guard let image = image else { return nil }

        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        self.layer.render(in: context)

        let renderedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return renderedImage

    }

}

Upvotes: 0

Wide Angle Technology
Wide Angle Technology

Reputation: 1222

Try this code in Swift 4.2

func stitchImages(images: [UIImage], isVertical: Bool) -> UIImage {
    var stitchedImages : UIImage!
    if images.count > 0 {
        var maxWidth = CGFloat(0), maxHeight = CGFloat(0)
        for image in images {
            if image.size.width > maxWidth {
                maxWidth = image.size.width
            }
            if image.size.height > maxHeight {
                maxHeight = image.size.height
            }
        }
        var totalSize : CGSize
        let maxSize = CGSize(width: maxWidth, height: maxHeight)
        if isVertical {
            totalSize = CGSize(width: maxSize.width, height: maxSize.height * (CGFloat)(images.count))
        } else {
            totalSize = CGSize(width: maxSize.width  * (CGFloat)(images.count), height:  maxSize.height)
        }
        UIGraphicsBeginImageContext(totalSize)
        for image in images {
            let offset = (CGFloat)(images.index(of: image)!)
            let rect =  AVMakeRect(aspectRatio: image.size, insideRect: isVertical ?
                CGRect(x: 0, y: maxSize.height * offset, width: maxSize.width, height: maxSize.height) :
                CGRect(x: maxSize.width * offset, y: 0, width: maxSize.width, height: maxSize.height))
            image.draw(in: rect)
        }
        stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
    return stitchedImages
  }
}

and you can use this:

@IBOutlet weak var imageView: UIImageView!
let imageArray = [image1, image3, image4, image4]

override func viewDidLoad() {
    super.viewDidLoad()
    let image = stitchImages(images: imageArray, isVertical: false)
    imageView.image = image
}

Upvotes: 1

Related Questions