Каков наиболее оптимизированный способ изменения альфы смешанных изображений в CoreImage в Swift

Я хочу смешать два изображения с помощью darkenBlendMode и использовать Slider для управления альфа-каналом первого и второго изображения. К сожалению, мой метод тормозит на iPhone 6S. Я знаю, что проблема заключается в вызове функции «loadImage» при каждом касании слайдера, но я понятия не имею, как сделать ее менее раздражающей. У вас есть идеи, как его отремонтировать?

extension UIImage {

    func alpha(_ value:CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        draw(at: CGPoint.zero, blendMode: .normal, alpha: value)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

struct ContentView: View {

    @State private var image: Image?
    @State private var opacity: CGFloat = 0
    let context = CIContext()

    var body: some View {

        return VStack(alignment: .center) {
            image?
                .resizable()
                .padding(14.0)
                .scaledToFit()

            Slider(value: Binding(
                get: {
                    self.opacity
                },
                set: {(newValue) in
                      self.opacity = newValue
                      self.loadImage()
                }
            ), in: -0.5...0.5)
        }
        .onAppear(perform: loadImage)

    }

    func loadImage(){
        let uiInputImage = UIImage(named: "photo1")!.alpha(0.5 + opacity)

        let uiBackgroundInputImage = UIImage(named: "photo2")!.alpha(0.5 - opacity)

        let ciInputImage = CIImage(image: uiInputImage)
        let ciBackgroundInputImage = CIImage(image: uiBackgroundInputImage)


        let currentFilter = CIFilter.darkenBlendMode()

        currentFilter.inputImage = ciInputImage

        currentFilter.backgroundImage = ciBackgroundInputImage

        guard let blendedImage = currentFilter.outputImage else {return}

        if let cgBlendedImage = context.createCGImage(blendedImage, from: blendedImage.extent){
            let uiblendedImage = UIImage(cgImage: cgBlendedImage)



            image = Image(uiImage: uiblendedImage)
        }
    }
}

person Bartson    schedule 13.06.2020    source источник
comment
Рендеринг из CIImage в CGImage происходит медленно. Единственный способ заставить Core Image не отставать от ползунка — отображать CIImage напрямую через представление Metal.   -  person matt    schedule 13.06.2020
comment
@matt Не могли бы вы поделиться ссылками, где я могу начать с Metal View или как это сделать в моем случае?   -  person Bartson    schedule 13.06.2020
comment
Я конечно могу показать пример, но не для SwiftUI. Например, stackoverflow.com/a/51753747/341994   -  person matt    schedule 13.06.2020
comment
Спасибо, это действительно хорошая отправная точка :)   -  person Bartson    schedule 13.06.2020
comment
Мммм, хорошо, но я думаю, что реальное решение — копнуть глубже и спросить себя, действительно ли вам нужно использовать Core Image вообще. Если идея состоит в том, чтобы просто рисовать с альфой, вы этого не сделаете.   -  person matt    schedule 13.06.2020
comment
Я хочу отображать смешанные изображения (поэтому я предполагаю, что здесь нужен CoreImage), и я хочу контролировать их альфа-канал.   -  person Bartson    schedule 13.06.2020
comment
Что ж, как я уже сказал, если все, что вы хотите сделать, это смешать изображения, основное изображение совершенно не нужно.   -  person matt    schedule 13.06.2020
comment
Итак, как я могу получить смешанные изображения в Swift без использования CIFilters? Что я должен искать?   -  person Bartson    schedule 14.06.2020
comment
Я думал о простых методах UIImage, таких как https://developer.apple.com/documentation/uikit/uiimage/1624095-draw. Он имеет параметры blendMode и alpha.   -  person matt    schedule 14.06.2020


Ответы (1)


Вы можете использовать фильтр CIColorMatrix для изменения альфа-канала изображений без повторной загрузки растровых данных:

let colorMatrixFilter = CIFilter.colorMatrix()
colorMatrixFilter.inputImage = ciInputImage // no need to load that every time
colorMatrixFilter.inputAVector = CIVector(x: 0, y: 0, z: 0, w: 0.5 + opacity)
let semiTransparentImage = colorMatrixFilter.outputImage

// perform blending
person Frank Schlegel    schedule 16.06.2020