DoesData
DoesData

Reputation: 7047

Swift: Draw on image without changing its size (Aspect fill)

I have a simple view controller where the entire screen is an imageView. The imageView has its content mode set to UIViewContentMode.scaleAspectFill. I can draw on the picture, but as soon as I do the image shrinks horizontally. This messing up the quality of the image and I'm not sure exactly why it's happening.

I looked at this question, but I didn't understand the only answer. I think the issue is with the way I am drawing and that rect is shrinking the image.

class AnnotateViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    var lastPoint = CGPoint.zero
    var fromPoint = CGPoint()
    var toPoint = CGPoint.zero
    var brushWidth: CGFloat = 5.0
    var opacity: CGFloat = 1.0


     @IBAction func startDrawing(_ sender: Any) {
        self.isDrawing = !self.isDrawing
        if isDrawing {
            self.imageView.isUserInteractionEnabled = true
            showColorButtons()
        }
        else {
            self.imageView.isUserInteractionEnabled = false
            hideColorButtons()
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            lastPoint = touch.preciseLocation(in: self.imageView)
        }
    }

    func drawLineFrom(fromPoint: CGPoint, toPoint: CGPoint) {
        UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, false, 0.0)
        imageView.image?.draw(in: CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height))

        let context = UIGraphicsGetCurrentContext()
        context?.move(to: fromPoint)
        context?.addLine(to: toPoint)


        context?.setLineCap(CGLineCap.round)
        context?.setLineWidth(brushWidth)
        context?.setStrokeColor(red: 255, green: 0, blue: 0, alpha: 1.0)
        context?.setBlendMode(CGBlendMode.normal)
        context?.strokePath()

        imageView.image = UIGraphicsGetImageFromCurrentImageContext()
        imageView.alpha = opacity
        UIGraphicsEndImageContext()

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let currentPoint = touch.preciseLocation(in: self.imageView)
            drawLineFrom(fromPoint: lastPoint, toPoint: currentPoint)
            lastPoint = currentPoint
        }
    }
}

UPDATE - SOLUTION

I finally got back to working on this problem. Looking at this question, I was able to use the accepted answer to solve my problem. Below is my updated code:

func drawLineFrom(fromPoint: CGPoint, toPoint: CGPoint) {
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, true, 0.0)

        let aspect = imageView.image!.size.width / imageView.image!.size.height
        let rect: CGRect
        if imageView.frame.width / aspect > imageView.frame.height {
            let height = imageView.frame.width / aspect
            rect = CGRect(x: 0, y: (imageView.frame.height - height) / 2,
                          width: imageView.frame.width, height: height)
        } else {
            let width = imageView.frame.height * aspect
            rect = CGRect(x: (imageView.frame.width - width) / 2, y: 0,
                          width: width, height: imageView.frame.height)
        }
        imageView.image?.draw(in: rect)

        let context = UIGraphicsGetCurrentContext()
        context?.move(to: fromPoint)
        context?.addLine(to: toPoint)
        context?.setLineCap(CGLineCap.round)
        context?.setLineWidth(brushWidth)
        context?.setStrokeColor(red: self.red, green: self.green, blue: self.blue, alpha: 1.0)
        context?.setBlendMode(CGBlendMode.normal)
        context?.strokePath()

        imageView.image = UIGraphicsGetImageFromCurrentImageContext()
        annotatedImage = imageView.image
        imageView.alpha = opacity
        UIGraphicsEndImageContext()
    }

Upvotes: 1

Views: 2114

Answers (1)

Lou Franco
Lou Franco

Reputation: 89172

This line:

imageView.image?.draw(in: CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height))

Draws the image at the aspect ratio of the screen, but your image is probably not at the same aspect ratio (the ratio of width to height).

I think this might be useful: UIImage Aspect Fit when using drawInRect?

Upvotes: 2

Related Questions