Как быстро нарисовать / нарисовать линию на UIImage?

Как быстро нарисовать / нарисовать линию на UIImage?

Мне нужно нарисовать / нарисовать линию в 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

Попробуйте использовать 2 изображения.

Dhruv Khatri 19.04.2018 13:27

Попробуйте использовать 2 изображения 1. Временное изображение, которое содержит текущий рисунок 2. Основное изображение, которое содержит другие уже созданные изображения

Dhruv Khatri 19.04.2018 13:28

Вы что-нибудь пробовали? Если да, покажите код и то, что не работает.

Sharad Chauhan 19.04.2018 13:28

Нарисуйте линии на imageView и снимите с него новый образ?

TheTiger 19.04.2018 13:55

да мне нужно что-то подобное @TheTiger

sarah 20.04.2018 03:46

@sarah В чем проблема? Вы уже умеете рисовать линию на виду. UIImageView - это сам вид, поэтому вы также можете рисовать на нем линии, а после этого просто сделайте снимок экрана этого imageView.

TheTiger 20.04.2018 06:51

@TheTiger Ага, я назначил UIImage в раскадровке для использования настраиваемого класса «DrawView», как мой код выше, но я не знаю, почему строки не отображаются в моем UIImage

sarah 20.04.2018 08:20

кажется, что функция touchesBegan никогда не будет выполняться, когда я использую DrawView Class в моем UIImageView

sarah 20.04.2018 08:24

Вы пробовали ответ ниже?

TheTiger 20.04.2018 08:25

@TheTiger Ага, я новичок, так что все еще работаю над этим,

sarah 20.04.2018 08:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
10
3 693
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете поместить свой UIImageView в фоновый режим и UIView наверх, а затем захватить UIView как образ и объединить его.

Обратитесь к этому, чтобы захватить UIView: Как захватить UIView в UIImage без потери качества на дисплее Retina

А затем объедините его, используя:

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
}

Это может вам помочь. Ссылка

Как нарисовать изображение в Swift?

  1. Сделайте изображение графическим контекстом. (До iOS 10 это можно было сделать, вызвав UIGraphicsBeginImageContextWithOptions. В iOS 10 есть другой способ, UIGraphicsImageRenderer, но вам не нужно его использовать, если вы не хотите.)

  2. Нарисуйте (то есть скопируйте) изображение в контекст. (У UIImage есть методы draw ... именно для этой цели.)

  3. Нарисуйте линию в контексте. (Для этого есть функции CGContext.)

  4. Извлеките полученное изображение из контекста. (Например, если вы использовали UIGraphicsBeginImageContextWithOptions, вы должны использовать UIGraphicsGetImageFromCurrentImageContext.) Затем закройте контекст.

Ответ принят как подходящий

Подробности

  • Xcode 10.2.1 (10E1001), Swift 5

Решение

import UIKit

// https://stackoverflow.com/a/41009006/4488252
class DrawnImageView: UIImageView {
    private lazy var path = UIBezierPath()
    private lazy var previousTouchPoint = CGPoint.zero
    private lazy var shapeLayer = CAShapeLayer()

    override func awakeFromNib() {
        super.awakeFromNib()
        setupView()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func setupView(){
        layer.addSublayer(shapeLayer)
        shapeLayer.lineWidth = 4
        shapeLayer.strokeColor = UIColor.white.cgColor
        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
    }
}

Применение

  1. Добавьте DrawnImageView в корневой (родительский) вид (рисование касанием будет включено автоматически)
  2. Для сохранения UIImage используйте drawingImageView.screenShot

Полный образец

Do not forget to add the solution code here

import UIKit

class ViewController: UIViewController {

    fileprivate weak var savedImageView: UIImageView?
    fileprivate weak var drawnImageView: UIImageView?

    override func viewDidLoad() {
        super.viewDidLoad()

        let drawnImageView = addImageView(image: UIImage(named: "swift")) as DrawnImageView
        drawnImageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        drawnImageView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height/3).isActive = true
        self.drawnImageView = drawnImageView

        let button = UIButton()
        button.setTitle("Save Image", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
        button.topAnchor.constraint(equalTo: drawnImageView.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 = drawnImageView?.screenShot
    }
}

Полученные результаты

Хороший ответ!! Но я сохраняю изображение с помощью UIImageWriteToSavedPhotosAlbum в альбоме, и изображение имеет белые границы, как это исправить?

Beginnerrrrrr 20.11.2019 04:09

@Beginnerrrrrr трудно понять, что произошло. Я предлагаю вам задать новый вопрос, где вы поделитесь своим кодом, имитирующим проблему. Потому что я не могу понять, в чем может быть проблема в вашем случае.

Vasily Bodnarchuk 20.11.2019 15:04

Отличный код, но он не поддерживает изменение цвета. Как в данном примере. Если я хочу "S", "W", "I", "F" и "T" с красным, зеленым, желтым, синим и белым соответственно, то я не могу использовать ваш код.

Mrugesh Tank 24.09.2020 12:14

@MrugeshTank вы можете изменить цвет shapeLayer.strokeColor = UIColor.white.cgColor. Итак, поэкспериментируйте с этой строкой, чтобы создать необходимую вам функциональность

Vasily Bodnarchuk 24.09.2020 15:04

Уже пробовал это, но если я установил красный цвет и нарисовал "S", а затем, если я установил зеленый, чтобы нарисовать "W", то "S" также изменит его цвет на зеленый.

Mrugesh Tank 28.09.2020 06:31

Другие вопросы по теме