I'm working on a drawing app prototype and what I want to achieve is perfect rounding lines. I've implemented drawing via curves but still, my lines look a little bit pixelated.
Here is my result:
and here is what I'm trying to achieve:
class ViewController: UIViewController {
private var currentPoint: CGPoint?
private var previousPoint1: CGPoint?
private var previousPoint2: CGPoint?
private var lineColor = UIColor.black
private var lineWidth = CGFloat(10)
private var lineAlpha = CGFloat(1)
@IBOutlet private weak var imageView: UIImageView!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
previousPoint1 = touch.previousLocation(in: self.view)
currentPoint = touch.location(in: self.view)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
previousPoint2 = previousPoint1
previousPoint1 = touch.previousLocation(in: self.view)
currentPoint = touch.location(in: self.view)
let mid1 = middlePoint(previousPoint1!, previousPoint2: previousPoint2!)
let mid2 = middlePoint(currentPoint!, previousPoint2: previousPoint1!)
draw(move: CGPoint(x: mid1.x, y: mid1.y), to: CGPoint(x: mid2.x, y: mid2.y), control: CGPoint(x: previousPoint1!.x, y: previousPoint1!.y))
}
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesMoved(touches, with: event)
}
private func middlePoint(_ previousPoint1: CGPoint, previousPoint2: CGPoint) -> CGPoint {
return CGPoint(x: (previousPoint1.x + previousPoint2.x) * 0.5, y: (previousPoint1.y + previousPoint2.y) * 0.5)
}
func draw(move: CGPoint, to: CGPoint, control: CGPoint) {
UIGraphicsBeginImageContext(view.frame.size)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
imageView.image?.draw(in: view.bounds)
ctx.move(to: move)
ctx.addQuadCurve(to: to, control: control)
ctx.setLineCap(.round)
ctx.setLineJoin(.round)
ctx.setLineWidth(lineWidth)
ctx.setStrokeColor(lineColor.cgColor)
ctx.setBlendMode(.normal)
ctx.setAlpha(lineAlpha)
ctx.strokePath()
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
imageView.image = finalImage
UIGraphicsEndImageContext()
}
}
P.S. I want to draw via context, not using drawRect
The problem here is that the scale of imageContext you are creating is not correct. Rather than creating your context with UIGraphicsBeginImageContext try to create it with UIGraphicsBeginImageContextWithOptions and give scale value as 0. When you specify a scale value of 0, the scale factor is set to the scale factor of the device’s main screen. Updated code snippet would be like the one follows.
func draw(move: CGPoint, to: CGPoint, control: CGPoint) {
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
imageView.image?.draw(in: view.bounds)
ctx.move(to: move)
ctx.addQuadCurve(to: to, control: control)
ctx.setLineCap(.round)
ctx.setLineJoin(.round)
ctx.setLineWidth(lineWidth)
ctx.setStrokeColor(lineColor.cgColor)
ctx.setBlendMode(.normal)
ctx.setAlpha(lineAlpha)
ctx.strokePath()
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
imageView.image = finalImage
UIGraphicsEndImageContext()
}