Reputation: 2330
I'm trying to implement a UIImageView
subclass that will allow a user to draw in the image view using their fingers. The contentMode of my UIImageView
is set to Aspect Fill
. I noticed that when my draw code executes and the resulting image is extracted from the graphics context it is being scaled in a Scale to Fill
type format which is not something I want. I was wondering if anyone knows how to achieve extracting this image and maintaining the aspect ratio of the image.
class DrawImageView : UIImageView {
var lastTouchPoint = CGPoint.zero
var isSwiping = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isSwiping = false
if let touchPoint = touches.first {
lastTouchPoint = touchPoint.location(in: self)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
isSwiping = true
if let touchPoint = touches.first {
let currentPoint = touchPoint.location(in: self)
UIGraphicsBeginImageContext(frame.size)
image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))
if let context = UIGraphicsGetCurrentContext() {
context.move(to: lastTouchPoint)
context.addLine(to: currentPoint)
context.setLineCap(CGLineCap.round)
context.setLineWidth(9.0)
context.setStrokeColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
context.strokePath()
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
lastTouchPoint = currentPoint
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if(!isSwiping) {
UIGraphicsBeginImageContext(frame.size)
image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))
if let context = UIGraphicsGetCurrentContext() {
context.setLineCap(CGLineCap.round)
context.setLineWidth(9.0)
context.setStrokeColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
context.move(to: lastTouchPoint)
context.addLine(to: lastTouchPoint)
context.strokePath()
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
}
}
Upvotes: 0
Views: 278
Reputation: 2330
The functions I ended up discovering and using to provide both an aspect fill rect and a aspect fit rect is as follows:
func getAspectFillFrame(sizeImageView : CGSize, sizeImage: CGSize) -> CGRect {
let aspect = sizeImage.width / sizeImage.height
let rect: CGRect
if sizeImageView.width / aspect > sizeImageView.height {
let height = sizeImageView.width / aspect
rect = CGRect(x: 0, y: (sizeImageView.height - height) / 2,
width: sizeImageView.width, height: height)
} else {
let width = sizeImageView.height * aspect
rect = CGRect(x: (sizeImageView.width - width) / 2, y: 0,
width: width, height: sizeImageView.height)
}
return rect
}
func getAspectFitFrame(sizeImgView:CGSize, sizeImage:CGSize) -> CGRect {
let imageSize:CGSize = sizeImage
let viewSize:CGSize = sizeImgView
let hfactor : CGFloat = imageSize.width/viewSize.width
let vfactor : CGFloat = imageSize.height/viewSize.height
let factor : CGFloat = max(hfactor, vfactor)
// Divide the size by the greater of the vertical or horizontal shrinkage factor
let newWidth : CGFloat = imageSize.width / factor
let newHeight : CGFloat = imageSize.height / factor
var x:CGFloat = 0.0
var y:CGFloat = 0.0
if newWidth > newHeight{
y = (sizeImgView.height - newHeight)/2
}
if newHeight > newWidth{
x = (sizeImgView.width - newWidth)/2
}
let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight)
return newRect
}
Upvotes: 0
Reputation: 77657
With this code:
UIGraphicsBeginImageContext(frame.size)
image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))
you are saying "draw this full image - regardless of size or aspect ratio - into a rectangle of width x height dimensions." So, if image
has a "native" size of, say, 300 x 200, and your frame
is 200 x 200, that's where the image is going to be drawn.
To avoid that, you need to calculate the proper rect to draw into. Using those sizes, you'd want to do (for aspect-fill):
image?.draw(in: CGRect(x:-50, y:0, width:frame.size.width + 50, height:frame.size.height))
Of course, instead of hard-coded values, you'd run quick calculations to determine the actual numbers.
Upvotes: 1