iOS Swift, как постепенно рисовать в UIImage? - PullRequest
1 голос
/ 31 марта 2019

Как использовать основную графику iOS для постепенного рисования большого набора данных в одном изображении?

У меня есть код, который готов обрабатывать весь набор данных одновременно (более 100 000 прямоугольников) и создает одно изображение. Это очень длительная операция, и я хочу, чтобы этот набор данных рисовался постепенно по 1000 прямоугольников за раз, отображая эти небольшие обновления изображения (например, изображения, загруженные из Интернета в 90-х годах)

Мои вопросы: оставлю ли я ссылку на один и тот же context на протяжении всей операции и просто добавлю к ней элементы? - ИЛИ - Должен ли я захватывать текущее изображение, используя UIGraphicsGetImageFromCurrentImageContext(), затем рисовать его в новом контексте и рисовать дополнительные прямоугольники поверх него?

Бонусный вопрос - правильный ли это подход, если я хочу использовать несколько потоков для добавления к одному изображению?

   let context = UIGraphicsGetCurrentContext()!

    context.setStrokeColor(borderColor)
    context.setLineWidth(CGFloat(borderWidth))
    for elementIndex in 0 ..< data.count {

        context.setFillColor(color.cgColor)
        let marker = CGRect(x: toX(elementIndex),
                            y: toY(elementIndex),
                            width: rectWidth,
                            height: rectHeight)

        context.addRect(marker)
        context.drawPath(using: .fillStroke)
    }
    // Save the context as a new UIImage
    let myImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    if let cgImage = myImage?.cgImage,
        let orientation = myImage?.imageOrientation {

        return UIImage(cgImage: cgImage, scale: 2, orientation: orientation)
    }

1 Ответ

1 голос
/ 31 марта 2019

Вы должны:

  • Отправить все это в некоторую фоновую очередь;
  • периодически вызывайте UIGraphicsGetImageFromCurrentImageContext и отправляйте обновление представления изображения в основную очередь

Например, это будет обновлять вид изображения каждую ¼ секунду:

DispatchQueue.global().async {
    var lastDrawn = CACurrentMediaTime()

    UIGraphicsBeginImageContextWithOptions(size, false, 0)

    for _ in 0 ..< 100_000 {
        // draw whatever you want

        let now = CACurrentMediaTime()
        if now - lastDrawn > 0.25 {
            self.updateImageView()
            lastDrawn = now
        }
    }

    self.updateImageView()

    UIGraphicsEndImageContext()
}

Где:

func updateImageView() {
    guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return }

    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

Таким образом:

func buildImage(of size: CGSize) {
    DispatchQueue.global().async {
        var lastDrawn = CACurrentMediaTime()

        UIGraphicsBeginImageContextWithOptions(size, false, 0)

        for _ in 0 ..< 100_000 {
            self.someColor().setFill()
            UIBezierPath(rect: self.someRectangle(in: size)).fill()

            let now = CACurrentMediaTime()
            if now - lastDrawn > 0.25 {
                self.updateImageView()
                lastDrawn = now
            }
        }

        self.updateImageView()

        UIGraphicsEndImageContext()
    }
}

func updateImageView() {
    let image = UIGraphicsGetImageFromCurrentImageContext()
    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

func someRectangle(in size: CGSize) -> CGRect {
    let x = CGFloat.random(in: 0...size.width)
    let y = CGFloat.random(in: 0...size.height)
    let width = CGFloat.random(in: 0...(size.width - x))
    let height = CGFloat.random(in: 0...(size.height - y))

    return CGRect(x: x, y: y, width: width, height: height)
}

func someColor() -> UIColor {
    return UIColor(red: .random(in: 0...1),
                   green: .random(in: 0...1),
                   blue: .random(in: 0...1),
                   alpha: 1)
}

Урожайность:

enter image description here

Теперь я не вызываю CoreGraphics напрямую, но вы можете, и он будет работать так же.

...