当前位置: 首页 > news >正文

如何在 SwiftUI 中对 CoreImage 滤镜做实时预览

网罗开发(小红书、快手、视频号同名)

大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!


文章目录

    • 前言
    • 先说结论:实时预览的关键点是什么?
    • 一个最基础的目标效果
    • Step 1:准备 CoreImage 的基础组件
    • Step 2:一个最简单的 SwiftUI 结构
    • Step 3:把 CoreImage 滤镜接进来
    • Step 4:把实时预览“接”到 SwiftUI 状态上
    • 性能问题从哪开始暴露?
    • Step 5:把滤镜计算移出主线程
    • 再往前一步:为什么 SwiftUI 特别适合做这件事?
    • 一点真实项目里的经验总结
    • 总结

前言

在做图片相关功能时,有一个需求几乎绕不开:
用户拖动参数,图片实时变化。

比如:

  • 调整模糊强度
  • 改变对比度、饱和度
  • 预览滤镜效果,再决定是否应用

在 UIKit 时代,我们可能会用UIImageView + CoreImage + GCD硬撸。
但到了 SwiftUI,很多人第一反应是:

SwiftUI + CoreImage + 实时预览,这事靠谱吗?

答案是:靠谱,但得用对方式。

这篇文章就从一个最小可用 Demo开始,一步一步把实时滤镜预览这件事讲清楚。

先说结论:实时预览的关键点是什么?

在 SwiftUI 里做 CoreImage 实时预览,核心其实只有三点:

  1. 图片渲染要尽量轻
  2. 滤镜计算不能阻塞主线程
  3. UI 状态变化要最小化

如果你一上来就把所有滤镜计算都丢进body
那基本等于在和 SwiftUI 的刷新机制正面硬刚。

一个最基础的目标效果

我们先定一个目标:

  • 显示一张原图
  • 拖动 Slider
  • 实时调整高斯模糊强度
  • 图片随着 Slider 连续变化

这是绝大多数滤镜编辑页的基础形态。

Step 1:准备 CoreImage 的基础组件

先把 CoreImage 的几个核心对象准备好:

importSwiftUIimportCoreImageimportCoreImage.CIFilterBuiltinsletcontext=CIContext()letfilter=CIFilter.gaussianBlur()

这里有两个细节值得注意:

  • CIContext应该尽量复用
  • 不要在body里反复 newCIContext

CIContext本身是重量级对象,频繁创建会直接拖垮性能。

Step 2:一个最简单的 SwiftUI 结构

我们先搭一个最基础的页面结构:

structContentView:View{@Stateprivatevarintensity:Double=0.5letimage=UIImage(named:"example")!varbody:someView{VStack{Image(uiImage:image).resizable().scaledToFit()Slider(value:$intensity).padding()}}}

到这一步,UI 是没问题的,但还没有任何滤镜逻辑

Step 3:把 CoreImage 滤镜接进来

关键思路是:
不要直接操作 UIImage,而是用 CIImage 作为中间态。

我们先写一个专门负责“生成滤镜图片”的方法:

funcapplyProcessing()->UIImage{letbeginImage=CIImage(image:image)filter.inputImage=beginImage filter.radius=Float(intensity*20)guardletoutputImage=filter.outputImageelse{returnimage}ifletcgimg=context.createCGImage(outputImage,from:beginImage!.extent){returnUIImage(cgImage:cgimg)}returnimage}

这段代码做了几件事:

  1. UIImage转成CIImage
  2. 设置滤镜参数
  3. 通过CIContext渲染成CGImage
  4. 再转回UIImage

Step 4:把实时预览“接”到 SwiftUI 状态上

接下来是最关键的一步:
让 SwiftUI 在 Slider 变化时刷新图片,但不炸性能。

先引入一个新的状态:

@StateprivatevarprocessedImage:UIImage?

然后改造body

varbody:someView{VStack{Image(uiImage:processedImage??image).resizable().scaledToFit()Slider(value:$intensity).padding().onChange(of:intensity){_inprocessedImage=applyProcessing()}}}

此时你已经可以看到:

  • Slider 一动
  • 图片跟着变
  • 滤镜是实时的

但——
这还不是一个“能上线”的写法。

性能问题从哪开始暴露?

当你快速拖动 Slider 时,会发现:

  • UI 有轻微卡顿
  • 真机上比模拟器更明显
  • 图片越大,问题越严重

原因也很直接:

滤镜计算跑在主线程。

Slider 的onChange本身就在主线程,
CoreImage 渲染又是 CPU / GPU 混合操作,
自然会影响 UI 响应。

Step 5:把滤镜计算移出主线程

一个简单、有效的方式是:
Task+MainActor控制线程切换。

改造onChange

.onChange(of:intensity){_inTask.detached{letoutput=applyProcessing()awaitMainActor.run{processedImage=output}}}

这样做之后:

  • 滤镜计算在后台执行
  • UI 只负责展示结果
  • 拖动 Slider 明显顺滑很多

这一步,是“能不能实时预览”的分水岭。

再往前一步:为什么 SwiftUI 特别适合做这件事?

如果你用 UIKit 做过类似功能,会发现:

  • 手动管理线程
  • 手动刷新 ImageView
  • 状态和 UI 同步很痛苦

而 SwiftUI 的优势在于:

  • 状态驱动 UI
  • 图片只是状态的一个映射
  • 滤镜逻辑和 UI 逻辑可以完全解耦

你只需要保证一件事:

状态更新是轻的,计算是异步的。

一点真实项目里的经验总结

在真实项目中,我一般会遵守这几个原则:

  1. Slider 变化频繁时,必要时做节流
  2. 滤镜链尽量复用,不要每次 new
  3. 大图先 downscale 再做预览
  4. 最终导出时再跑一次“高质量渲染”

实时预览追求的是**“看起来对”
而不是
“每一帧都是最终质量”**。

总结

SwiftUI 并不是不适合做图像处理,
而是不能用同步思维去写异步计算

一旦你把:

  • CoreImage 的计算
  • SwiftUI 的状态刷新
  • 主线程和后台线程的职责

这三件事理顺了,
实时滤镜预览这件事,其实比 UIKit 时代要轻松得多。

http://www.jsqmd.com/news/150422/

相关文章:

  • 大模型Token成本太高?用TensorRT降低推理开销
  • 如何在博客园『个人博客』中实现自推广 -『AI实现的小程序小游戏』
  • 如何评估TensorRT对模型推理的提升幅度?
  • 视觉Transformer模型的TensorRT优化之路
  • 大数据诊断性分析中的数据可视化技巧
  • 【计算机毕业设计案例】基于Java SpringBoot的乐器推荐系统设计基于springboot的音乐周边产品乐器售卖系统设计与实现(程序+文档+讲解+定制)
  • springboot_ssm超市在线配送管理系统java论文
  • 实验进展总结
  • 碳排放计算器:量化每次推理调用的绿色指数
  • 2025年尘埃在线监测系统优质销售商排行榜单,粒子计数器/尘埃粒子计数器/台式粒子计数器尘埃在线监测系统销售厂家哪家靠谱 - 品牌推荐师
  • 2025年度总结:十五年研发路的转身:从技术专家到COE的蜕变之年
  • NVIDIA TensorRT自动调优机制背后的黑科技
  • 大模型推理成本居高不下?试试TensorRT量化方案
  • 学长亲荐10个AI论文工具,研究生论文写作不再难!
  • DELL——DELL: Generating reactions and explanations for LLM-based misinformation detection
  • NVIDIA TensorRT对Hugging Face模型的支持现状
  • License服务器搭建:企业级授权管理体系设计
  • springboot_ssm民宿推荐系统_2k78b--论文
  • 如何选择适合你的TensorRT优化级别?
  • 1.1 永磁材料、电机结构与运行原理
  • 东京节点上线公告:服务日本地区高频交易客户
  • 为什么大模型推理必须使用TensorRT?
  • 国际信用卡收款:Visa/MasterCard/PayPal接入
  • Logback.xml中日志的配置
  • 【DDD架构理解】
  • AtCoder Beginner Contest 438
  • Java毕设项目推荐-基于springboot的小区停车场车辆信息管理系统的设计与实现车位信息管理、车位预约、车辆进场管理【附源码+文档,调试定制服务】
  • 悉尼站点启用:大洋洲客户免去跨洋延迟困扰
  • 2025年专业曝气池清理厂家评选,曝气池清理推荐榜永邦环卫市场认可度高 - 品牌推荐师
  • TensorRT层融合技术原理与性能实测分析