MTKView отображает CIImage не так, когда изображение меняет размер - PullRequest
0 голосов
/ 29 октября 2018

Я использую довольно стандартный подкласс MTKView, который отображает CIImage, в целях быстрого обновления с использованием CIFilters. Код для функции draw() приведен ниже.

У меня проблема в том, что на самом деле перерисовываются только те части изображения, которые покрыты изображением, в данном случае scaledImage в приведенном ниже коде. Это означает, что если новое изображение меньше предыдущего, я все еще могу видеть части старого изображения, высовывающиеся из-за него.

Есть ли способ очистить содержимое текстуры рисованного объекта при изменении размера содержащегося изображения, чтобы этого не произошло?

override func draw() {
    guard let image = image,
        let targetTexture = currentDrawable?.texture,
        let commandBuffer = commandQueue.makeCommandBuffer()
        else { return }

    let bounds = CGRect(origin: CGPoint.zero, size: drawableSize)

    let scaleX = drawableSize.width / image.extent.width
    let scaleY = drawableSize.height / image.extent.height
    let scale = min(scaleX, scaleY)

    let width = image.extent.width * scale
    let height = image.extent.height * scale
    let originX = (bounds.width - width) / 2
    let originY = (bounds.height - height) / 2

    let scaledImage = image
        .transformed(by: CGAffineTransform(scaleX: scale, y: scale))
        .transformed(by: CGAffineTransform(translationX: originX, y: originY))

    ciContext.render(
        scaledImage,
        to: targetTexture,
        commandBuffer: commandBuffer,
        bounds: bounds,
        colorSpace: colorSpace
    )

    guard let drawable = currentDrawable else { return }
    commandBuffer.present(drawable)
    commandBuffer.commit()
    super.draw()
}

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

MTKView имеет clearColor свойство, которое вы можете использовать следующим образом:

clearColor = MTLClearColorMake(1, 1, 1, 1)

В качестве альтернативы, если вы хотите использовать CIImage, вы можете просто создать его с CIColor следующим образом:

CIImage(color: CIColor(red: 1, green: 1, blue: 1)).cropped(to: CGRect(origin: .zero, size: drawableSize))
0 голосов
/ 29 октября 2018

У меня есть следующее решение, которое работает, но я не очень доволен им, так как оно кажется хакерским, поэтому, пожалуйста, кто-нибудь подскажет мне лучший способ сделать это!

То, что я делаю, - это отслеживание изменения размера изображения и установка флага с именем needsRefresh. Во время функции draw() представления я затем проверяю, установлен ли этот флаг, и, если это так, я создаю новый CIImage из clearColor представления того же размера, что и отрисовываемый объект, и визуализирую его, прежде чем перейти к изображению, которое я на самом деле хочу сделать.

Это кажется действительно неэффективным, так что лучшие решения приветствуются!

Вот дополнительный код для рисования:

    if needsRefresh {
        let color = UIColor(mtkColor: clearColor)
        let clearImage = CIImage(cgImage: UIImage.withColor(color, size: bounds.size)!.cgImage!)
        ciContext.render(
            clearImage,
            to: targetTexture,
            commandBuffer: commandBuffer,
            bounds: bounds,
            colorSpace: colorSpace
        )
        needsRefresh = false
    }

Вот расширение UIColor для преобразования ясного цвета:

extension UIColor {
    convenience init(mtkColor: MTLClearColor) {
        let red = CGFloat(mtkColor.red)
        let green = CGFloat(mtkColor.green)
        let blue = CGFloat(mtkColor.blue)
        let alpha = CGFloat(mtkColor.alpha)
        self.init(red: red, green: green, blue: blue, alpha: alpha)
    }
}

И, наконец, небольшое расширение для создания CIImages из заданного цвета фона:

extension UIImage {
    static func withColor(_ color: UIColor, size: CGSize = CGSize(width: 10, height: 10)) -> UIImage? {
        UIGraphicsBeginImageContext(size)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        context.setFillColor(color.cgColor)
        context.fill(CGRect(origin: .zero, size: size))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }   
}
...