You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CGContext strokePath绘制笔触边缘模糊,如何实现清晰手绘注释?

手绘应用笔触模糊问题解决方案

问题描述

我正在开发一款简单的手绘应用,使用UIGesture类跟踪笔触(即铅笔或手指的移动),随后在UIImageView上绘制这些触摸点。相关示例代码如下:

let previousLocation = touch.previousLocation(in: self)
let location = touch.location(in: self)
var lineWidth: CGFloat = 3
UIColor.black.setStroke()
context?.setLineWidth(lineWidth)
context?.setLineCap(.round)
context?.move(to: previousLocation)
context?.addLine(to: location)
context?.strokePath() 

绘制出的笔触边缘模糊,效果如图:
模糊的手绘笔触

已尝试以下方法但未彻底解决:

  • 使用贝塞尔路径绘制
  • 用View替代ImageView
  • 增大UIGraphicsBeginImageContextWithOptions的缩放比例(虽提升清晰度但导致书写卡顿)

请问如何实现清晰的手绘注释?


解决方案

1. 适配Retina屏幕的绘图上下文

确保绘图上下文的缩放因子与屏幕一致,同时上下文尺寸严格匹配控件显示尺寸,避免过度放大导致卡顿:

// 获取屏幕原生缩放比例
let scale = UIScreen.main.scale
// 创建与ImageView尺寸匹配的上下文,启用Retina支持
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
// 执行你的绘图逻辑...
// 结束上下文并更新图片
imageView.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

2. 平滑触摸路径提升清晰度

单纯连接相邻触摸点易出现折线和边缘模糊,通过收集多点生成平滑贝塞尔曲线优化:

// 存储触摸点的数组,用于路径平滑
private var touchPoints = [CGPoint]()

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    let currentPoint = touch.location(in: self)
    touchPoints.append(currentPoint)
    
    // 点数量足够时生成平滑路径
    if touchPoints.count > 3 {
        let path = UIBezierPath()
        path.move(to: touchPoints[0])
        
        // 用二次贝塞尔曲线连接中间点
        for i in 1..<touchPoints.count-2 {
            let midPoint = CGPoint(x: (touchPoints[i].x + touchPoints[i+1].x)/2,
                                  y: (touchPoints[i].y + touchPoints[i+1].y)/2)
            path.addQuadCurve(to: midPoint, controlPoint: touchPoints[i])
        }
        // 连接最后一个点
        path.addLine(to: touchPoints.last!)
        
        // 设置路径属性
        UIColor.black.setStroke()
        path.lineWidth = 3
        path.lineCapStyle = .round
        path.lineJoinStyle = .round
        path.stroke()
        
        // 更新ImageView
        imageView.image = UIGraphicsGetImageFromCurrentImageContext()
        // 保留最后3个点用于后续平滑
        touchPoints = Array(touchPoints.suffix(3))
    }
}

3. 使用CAShapeLayer实现GPU加速绘制

改用CAShapeLayer替代ImageView缓存绘制,利用GPU实时渲染,既保证清晰度又避免卡顿:

private let drawLayer = CAShapeLayer()

override func viewDidLoad() {
    super.viewDidLoad()
    // 配置ShapeLayer属性
    drawLayer.strokeColor = UIColor.black.cgColor
    drawLayer.lineWidth = 3
    drawLayer.lineCap = .round
    drawLayer.lineJoin = .round
    drawLayer.fillColor = UIColor.clear.cgColor
    // 添加到绘制视图的图层中
    drawView.layer.addSublayer(drawLayer)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    let startPoint = touch.location(in: drawView)
    // 初始化路径
    let path = UIBezierPath()
    path.move(to: startPoint)
    drawLayer.path = path.cgPath
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    let currentPoint = touch.location(in: drawView)
    // 扩展路径
    let mutablePath = CGMutablePath(path: drawLayer.path!)
    mutablePath.addLine(to: currentPoint)
    drawLayer.path = mutablePath
}

4. 禁用ImageView的自动缩放

确保ImageView的内容模式不会拉伸图片,避免模糊:

imageView.contentMode = .topLeft
imageView.clipsToBounds = true

内容的提问来源于stack exchange,提问作者Raj Kiran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:46:08