0

I am trying image crop tutorial

I want to make app that crop image and add sticker.

subviews are imageview’s subview ( imageview.addsubview(subview) )

please check this Image link

Everything is fine, but I can’t make final image. I want to make final image using original resolution but my fuction’s result is too low resolution

I lost 5 days about this

example)

scrollview’s rect 0, 0, 200, 400

imageview size 7680 x 4320

I tried below code. but result quality is very low. because the resolution is 200x400(scrollview’s rect) .

func screenshot() -> UIImage {
    guard let imageview = imageview else { return UIImage() }
    UIGraphicsBeginImageContextWithOptions(self.scrollView.bounds.size, false, UIScreen.main.scale)
    let offset = self.scrollView.contentOffset
    guard let thisContext = UIGraphicsGetCurrentContext() else { return UIImage() }
    thisContext.translateBy(x: -offset.x, y: -offset.y)
    self.scrollView.layer.render(in: thisContext)
    let visibleScrollViewImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return visibleScrollViewImage ?? UIImage()
}

please let me know how to high quality resolution final image including sticker subviews

how to get one high quality image using

Zouhair Sassi
  • 1,403
  • 1
  • 13
  • 30

1 Answers1

0

Using that method, you get an image of what is rendered on the screen.

What you want to do is calculate the "sticker" size and placement relative to the scaled image and then combine the images.

You can use this extension to overlay one image on another:

extension UIImage {
    func overlayWith(image: UIImage, posX: CGFloat, posY: CGFloat) -> UIImage {
        let rFormat = UIGraphicsImageRendererFormat()
        let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
        let newImage = renderer.image {
            (context) in
            self.draw(at: .zero)
            image.draw(at: CGPoint(x: posX, y: posY))
        }
        return newImage
    }
}

Use it by calling (for example):

let combinedImage = bkgImage.overlayWith(image: stickerImage, posX: 1000.0, posY: 1000.0)

That says "Create a new UIImage by overlaying the sticker image onto the background image at x: 1000, y:1000"

Remember that you'll need to translate your coordinates... So, if you are showing your 7680 x 4320 image in a 200 x 400 scrollview (not taking any zooming into account here), the on-screen image size will be 711 x 400. If the user places the sticker at 100, 50, the actual position on the original size image will be:

    let scaleFactor = bkgImage.size.height / 400.0
    let x = 100.0 * scaleFactor
    let y = 50.0 * scaleFactor

    // scaleFactor equals 10.8
    // x equals 100 * 10.8 == 1080
    // y equals 50 * 10.8 == 540

    let combinedImage = bkgImage.overlayWith(image: stickerImage, posX: x, posY: y)

Here is a basic sample you can try out.

It starts with a background image of 5120 x 2880:

and a "sticker" image at 512 x 512:

And the result, with the sticker placed at x: 1000, y:1000. Top image is original background (aspectFit), middle image is the combined image (again, aspectFit), and the bottom image is the actual size combined image in a scroll view:

enter image description here

Use this source code to run that example (all code, no @IBoutlet):

import UIKit

extension UIImage {
    func overlayWith(image: UIImage, posX: CGFloat, posY: CGFloat) -> UIImage {
        let rFormat = UIGraphicsImageRendererFormat()
        let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
        let newImage = renderer.image {
            (context) in
            self.draw(at: .zero)
            image.draw(at: CGPoint(x: posX, y: posY))
        }
        return newImage
    }
}

class ViewController: UIViewController {

    let origImageView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .scaleAspectFit
        v.backgroundColor = .yellow
        return v
    }()

    let modImageView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .scaleAspectFit
        v.backgroundColor = .yellow
        return v
    }()

    let actualSizeImageView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .topLeft
        v.backgroundColor = .yellow
        return v
    }()

    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let bkgImage = UIImage(named: "background"),
            let stickerImage = UIImage(named: "sticker") else {

                fatalError("missing images")

        }

        view.backgroundColor = .systemGreen

        view.addSubview(origImageView)
        view.addSubview(modImageView)

        view.addSubview(scrollView)
        scrollView.addSubview(actualSizeImageView)

        let g = view.safeAreaLayoutGuide

        let sg = scrollView.contentLayoutGuide

        NSLayoutConstraint.activate([

            origImageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 10.0),
            origImageView.centerXAnchor.constraint(equalTo: g.centerXAnchor, constant: 0.0),
            origImageView.widthAnchor.constraint(equalToConstant: 200.0),
            origImageView.heightAnchor.constraint(equalToConstant: 120.0),

            modImageView.topAnchor.constraint(equalTo: origImageView.bottomAnchor, constant: 10.0),
            modImageView.centerXAnchor.constraint(equalTo: origImageView.centerXAnchor, constant: 0.0),
            modImageView.widthAnchor.constraint(equalTo: origImageView.widthAnchor),
            modImageView.heightAnchor.constraint(equalTo: origImageView.heightAnchor),

            scrollView.topAnchor.constraint(equalTo: modImageView.bottomAnchor, constant: 10.0),
            scrollView.centerXAnchor.constraint(equalTo: origImageView.centerXAnchor, constant: 0.0),
            scrollView.widthAnchor.constraint(equalTo: g.widthAnchor, constant: -10.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -10.0),

            actualSizeImageView.topAnchor.constraint(equalTo: sg.topAnchor),
            actualSizeImageView.bottomAnchor.constraint(equalTo: sg.bottomAnchor),
            actualSizeImageView.leadingAnchor.constraint(equalTo: sg.leadingAnchor),
            actualSizeImageView.trailingAnchor.constraint(equalTo: sg.trailingAnchor),

            actualSizeImageView.widthAnchor.constraint(equalToConstant: bkgImage.size.width),
            actualSizeImageView.heightAnchor.constraint(equalToConstant: bkgImage.size.height),

        ])

        origImageView.image = bkgImage

        let combinedImage = bkgImage.overlayWith(image: stickerImage, posX: 1000.0, posY: 1000.0)

        modImageView.image = combinedImage

        actualSizeImageView.image = combinedImage

    }
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • thanks for your kindness answer. I one more thing, I want to make the stickerview can be rotate, zoom. and then the view's transform is changed. how to apply the transform when I call overlaywith() ? is it possible to apply transform? – ddaddaddda Nov 22 '19 at 02:36
  • @ddaddaddda - that's beyond the scope of your initial question. Here is a good example of rotating a `UIImage`: https://stackoverflow.com/a/39804312/6257435 ... as to zooming / scaling, calculate the desired width and height of the "sticker" image and modify the `overlayWith` func to accept that size (width and height) and use `image.draw(in: CGRect(x: posX, y: posY, width: targetW, height: targetH))` instead of `image.draw(at: ...)` – DonMag Nov 25 '19 at 13:36