首页 文章

如何在swift中在UIImage上绘制/涂鸦线?

提问于
浏览
5

enter image description here

我需要像上面的图片一样在UIImage中绘制/涂鸦一行,我看到很多教程在UIView上涂鸦线但不在UIImage中 .

用户在图像上涂鸦后,我想将其保存为新图像(具有线条的图像) . 我怎么在Swift中做到这一点?

我只能在UIView上找到绘制线而不是在UIImage中用于绘制UIView就像这个在youtube教程http://youtube.com/watch?v=gbFHqHHApC4中的一个,我将其更改为继承DrawView到UIImageView

struct  Stroke {
    let startPoint : CGPoint
    let endPoint : CGPoint
    let strokeColor : CGColor
}


class DrawView : UIImageView {

    var isDrawing = false
    var lastPoint : CGPoint!
    var strokeColor : CGColor! = UIColor.black.cgColor
    var strokes = [Stroke]()


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard !isDrawing else { return }
        isDrawing = true

        guard let touch = touches.first else {return}
        let currentPoint = touch.location(in: self)
        lastPoint = currentPoint
        print(currentPoint)


    }



    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard isDrawing else { return}

        guard let touch = touches.first else {return}
        let currentPoint = touch.location(in: self)
        let stroke = Stroke(startPoint: lastPoint, endPoint: currentPoint, strokeColor: strokeColor)
        strokes.append(stroke)
        lastPoint = currentPoint

        setNeedsDisplay()


        print(currentPoint)
    }




    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard isDrawing else { return}
        isDrawing = false


        guard let touch = touches.first else {return}

        let currentPoint = touch.location(in: self)
        let stroke = Stroke(startPoint: lastPoint, endPoint: currentPoint, strokeColor: strokeColor)
        strokes.append(stroke)

        setNeedsDisplay()

        lastPoint = nil
        print(currentPoint)

    }


    override func draw(_ rect: CGRect) {

        let context = UIGraphicsGetCurrentContext()
        context?.setLineWidth(5)
        context?.setLineCap(.round)

        for stroke in strokes {
            context?.beginPath()

            context?.move(to: stroke.startPoint)
            context?.addLine(to: stroke.endPoint)

            context?.setStrokeColor(stroke.strokeColor)
            context?.strokePath()
        }

    }


    func erase() {
        strokes = []
        strokeColor = UIColor.black.cgColor
        setNeedsDisplay()
    }






}

我在故事板中分配了UIImage以使用自定义类“DrawView”,就像我上面的代码一样,但我不知道为什么这些行没有出现在我的UIImage上

3 回答

  • 5

    详情

    Xcode 9.3,Swift 4.1

    解决方案

    // https://stackoverflow.com/a/41009006/4488252
    class DrawingImageView: UIImageView {
        var path = UIBezierPath()
        var previousTouchPoint = CGPoint.zero
        var shapeLayer = CAShapeLayer()
    
        override func awakeFromNib() {
            super.awakeFromNib()
            setupView()
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            setupView()
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func setupView(){
            self.layer.addSublayer(shapeLayer)
            self.shapeLayer.lineWidth = 4
            self.shapeLayer.strokeColor = UIColor.white.cgColor
            self.isUserInteractionEnabled = true
        }
    
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesBegan(touches, with: event)
            if let location = touches.first?.location(in: self){
                previousTouchPoint = location
            }
        }
    
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesMoved(touches, with: event)
    
            if let location = touches.first?.location(in: self){
                path.move(to: location)
                path.addLine(to: previousTouchPoint)
                previousTouchPoint = location
                shapeLayer.path = path.cgPath
            }
        }
    }
    
    // https://stackoverflow.com/a/40953026/4488252
    extension UIView {
    
        var screenShot: UIImage?  {
    
            let scale = UIScreen.main.scale
            UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
            if let context = UIGraphicsGetCurrentContext() {
                layer.render(in: context)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
    
            return nil
        }
    }
    

    用法

    • 将DrawingImageView添加到根(父)视图(触摸绘图将自动启用)

    • 要保存UIImage,请使用 drawingImageView.screenShot

    完整样本

    不要忘记在此处添加解决方案代码

    import UIKit
    
    class ViewController: UIViewController {
    
        fileprivate weak var savedImageView: UIImageView!
        fileprivate weak var drawingImageView: UIImageView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            let drawingImageView = addImageView(image: UIImage(named: "swift")) as DrawingImageView
            drawingImageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            drawingImageView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height/3).isActive = true
            self.drawingImageView = drawingImageView
    
            let button = UIButton()
            button.setTitle("Save Image", for: .normal)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitleColor(.blue, for: .normal)
            view.addSubview(button)
            button.topAnchor.constraint(equalTo:drawingImageView.bottomAnchor, constant: 60).isActive = true
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            button.heightAnchor.constraint(equalToConstant: 44).isActive = true
            button.addTarget(self, action: #selector(saveImageButtonTouchUpInside), for: .touchUpInside)
    
            let savedImageView = addImageView()
            savedImageView.topAnchor.constraint(equalTo: button.bottomAnchor, constant: 60).isActive = true
            savedImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            self.savedImageView = savedImageView
        }
    
        private func addImageView<T: UIImageView>(image: UIImage? = nil) -> T {
            let imageView = T(frame: .zero)
            imageView.contentMode = .scaleAspectFit
            imageView.image = image
            view.addSubview(imageView)
    
            imageView.translatesAutoresizingMaskIntoConstraints = false
            imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    
            return imageView
        }
    
        @objc func saveImageButtonTouchUpInside(sender: UIButton) {
            savedImageView.image = drawingImageView.screenShot
        }
    }
    

    结果

    enter image description here

    enter image description here

  • 3

    您可以将 UIImageView 放在后台,将 UIView 放在其顶部,然后将 UIView 捕获为图像并合并它 .

    请参考此捕获UIView:How to capture UIView to UIImage without loss of quality on retina display

    然后使用以下方法合并它:

    func mergeImages (forgroundImage : UIImage, backgroundImage : UIImage, size : CGSize) -> UIImage {
    
         let bottomImage = backgroundImage
         UIGraphicsBeginImageContext(size)
    
         let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
         bottomImage.draw(in: areaSize)
    
         let topImage      = forgroundImage
         topImage.draw(in: areaSize, blendMode: .normal, alpha: 1.0)
    
         let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    
         UIGraphicsEndImageContext()
    
       return newImage
    }
    
  • 0

    这可能对你有所帮助 . 请参阅链接

    How do I draw on an image in Swift?

    • 制作图像图形上下文 . (在iOS 10之前,您可以通过调用UIGraphicsBeginImageContextWithOptions来完成此操作 . 在iOS 10中,还有另一种方法,UIGraphicsImageRenderer,但如果您不想使用它,则不必使用它 . )

    • 将图像绘制(即复制)到上下文中 . (对于这个目的,UIImage实际上有绘制...方法 . )

    • 在上下文中绘制线条 . (这里有CGContext函数 . )

    • 从上下文中提取生成的图像 . (例如,如果您使用了UIGraphicsBeginImageContextWithOptions,则可以使用UIGraphicsGetImageFromCurrentImageContext . )然后关闭上下文 .

相关问题