如何在swiftui中对核心图像过滤器进行动画动画

发布于 2025-02-10 19:35:25 字数 385 浏览 1 评论 0原文

我想应用一个给定的cifilter,但我想对其进行动画效果,而不是立即出现的效果。例如,我想在2秒内将颜色图像保留为灰度,或通过将其放松的动画曲线超过0.8秒将其深入到完整的图像来解决块状图像。

如果您使用的是内置的SwiftUi视图修饰符,例如.blur(),那么您是金色的。只需附加一些.ainimate()变体,就完成了。

但是,鉴于您必须跳过篮球,无论您是使用UIImage,CGIMAGE,CIIMAGE路线还是MTLView,CirenderDestination,ContentView from wwdc 2022示例代码,我有点困惑。

理想情况下,我想我只想为我想做的每种效果编写视图修饰符,以便它们与Swiftui内置的效果一样可用,但是我不知道这是否可能。这样做有幸福的方式吗?有什么想法吗?

I want to apply a given CIFilter but instead of the effect showing up instantly, I want to animate it. For example, I want to desaturate a color image to grey scale over 2 seconds, or resolve a blocky image by depixellating it to a full-resolution image using an EaseInOut animation curve over 0.8 seconds.

If you're using one of the built in SwiftUI view modifiers like .blur(), you're golden. Just append some .animate() variant and you're done.

But given that you have to jump through hoops whether you go the UIImage, CGImage, CIImage route, or the MTLView, CIRenderDestination, ContentView example from the WWDC 2022 sample code, I'm a bit confused.

Ideally I guess I'd just like to write View Modifiers for each effect I want to do, so that they're as usable as the SwiftUI built-in ones, but I don't know if that's possible. Is there one blessed way of doing this? Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我早已燃尽 2025-02-17 19:35:25

这是一种方法适应动画。您可以轻松地适应您的需求:

struct ContentView: View {
    
    @State private var animate = false

    var body: some View {
        VStack {
            PixellatedImage(imageName: "yoga", scale: animate ? 100 : 1)
                .scaledToFit()
        }
        .padding()
        .onAppear {
            withAnimation(Animation.linear(duration: 3.0).repeatForever()) {
                self.animate.toggle()
            }
        }
    }
}


struct PixellatedImage: View, Animatable {
    
    let imageName: String
    var scale: CGFloat
    
    var animatableData: CGFloat {
        get { scale }
        set { scale = newValue }
    }
    
    var body: some View {
        Image(uiImage: pixellatedImage(imageName: imageName, scale: scale))
            .resizable()
    }
}


func pixellatedImage(imageName: String, scale: Double) -> UIImage {
    if let inputImage = UIImage(named: imageName) {
        let context = CIContext(options: nil)
        
        if let currentFilter = CIFilter(name: "CIPixellate") {
            let beginImage = CIImage(image: inputImage)
            currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
            currentFilter.setValue(scale, forKey: kCIInputScaleKey)
            
            if let output = currentFilter.outputImage {
                if let cgimg = context.createCGImage(output, from: output.extent) {
                    let processedImage = UIImage(cgImage: cgimg)
                    return processedImage
                }
            }
        }
    }
    return UIImage() // empty default instead of nil
}

Here is an approach adapting Animatable. You can easily adapt it to your needs:

struct ContentView: View {
    
    @State private var animate = false

    var body: some View {
        VStack {
            PixellatedImage(imageName: "yoga", scale: animate ? 100 : 1)
                .scaledToFit()
        }
        .padding()
        .onAppear {
            withAnimation(Animation.linear(duration: 3.0).repeatForever()) {
                self.animate.toggle()
            }
        }
    }
}


struct PixellatedImage: View, Animatable {
    
    let imageName: String
    var scale: CGFloat
    
    var animatableData: CGFloat {
        get { scale }
        set { scale = newValue }
    }
    
    var body: some View {
        Image(uiImage: pixellatedImage(imageName: imageName, scale: scale))
            .resizable()
    }
}


func pixellatedImage(imageName: String, scale: Double) -> UIImage {
    if let inputImage = UIImage(named: imageName) {
        let context = CIContext(options: nil)
        
        if let currentFilter = CIFilter(name: "CIPixellate") {
            let beginImage = CIImage(image: inputImage)
            currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
            currentFilter.setValue(scale, forKey: kCIInputScaleKey)
            
            if let output = currentFilter.outputImage {
                if let cgimg = context.createCGImage(output, from: output.extent) {
                    let processedImage = UIImage(cgImage: cgimg)
                    return processedImage
                }
            }
        }
    }
    return UIImage() // empty default instead of nil
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文