前言
学如逆水行舟,不进则退。共勉!!!
苹果在Core Image API中提供了14个大类、共174个图像处理方式以及一些常见滤镜,其中一些滤镜还能处理视频甚至是实时视频,各个滤镜详情参见:developer.apple.com/library/arc…
首先是如何看这个网页,也就是说这个网页提供了哪些信息,这对我们使用时非常有帮助的。以下面这个截图为例,来讲一下如何看。原文|地址
按照各部分来介绍:
-
滤镜名称。一般情况下,和部分3的本地名称一样。
-
滤镜功能的介绍。这里是“使用盒形卷积内核模糊图像”。
-
这个是本地显示名称,是我们在代码中调用滤镜的时候需要使用的名称。
-
参数及参数介绍。这是我们在调用滤镜时需要告诉代码的一些信息,比如这里的inputImage是输入的图片,几乎每个滤镜都会有这个参数。这里的inputRadius是滤镜模糊的程度,如果我们不做调整也就是默认值10.00。不同滤镜的参数都不一样,要自己在使用的时候查阅一下。使用的时候名称需要变形一下,需要加上加上kCI-和-Key,这个等会使用的时候细说。
-
这部分是滤镜所属的大类,看网页的时候可以发现苹果将其分成多个大类,我们可以通过查看这里的大类来查找相似的。但是我们会发现这里有的大类已经没有了,可能是苹果删除调整了一些滤镜和大类,但是每个滤镜下的还没有调整。
-
滤镜的使用效果。大部分滤镜都会有这部分来展示使用效果。
-
可以使用这些滤镜的系统。由于这些API都很早了,所以目前的设备都是可以使用的。
苹果将其分成17个大类,如下:
- CICategoryBlur(模糊)
- CICategoryColorAdjustment(颜色调整)
- CICategoryColorEffect(颜色特效)
- CICategoryCompositeOperation(合成操作)
- CICategoryDistortionEffect(变形特效)
- CICategoryGenerator(生成,例如条形码二维码)
- CICategoryGeometryAdjustment(几何调整)
- CICategoryGradient(渐变)
- CICategoryHalftoneEffect(网格特效)
- CICategoryReduction(简化图片)
- CICategorySharpen(锐化图片)
- CICategoryStylize(风格化图片,就是杂项)
- CICategoryTileEffect(瓦片特效)
- CICategoryTransition(过渡、渐变) 各位可以根据需求去查找自己需要的。
接下来我们具体说说,在SwiftUI中如何使用这些官方提供的filter(滤镜或者处理方式)。 首先我们需要创建一个函数,来调用filter API,就调用刚才举例子的CIBoxBlur吧。头文件是import SwiftUI即可。我对几乎每一行代码都进行了注释,以确保各位都能很好的理解:
func blurFilter(inputImage: UIImage) -> UIImage {
//创建一个CIContext(),用来放置处理后的内容
let context = CIContext()
//将输入的UIImage转变成CIImage
let inputCIImage = CIImage(image: inputImage)!
//创建用于处理图片的滤镜(Filter)
let filter = CIFilter(name: "CIBoxBlur")!
//这个setValue设置值的时候,后面的forKey参数跟的是文档给的参数的名字的变形,比如这里官网给的是inputRadius,加上kCI-和-Key就是应该填的参数了。
//这里设置模糊度————也可以不写这个,就会按照默认的来
filter.setValue(10, forKey: kCIInputRadiusKey)
//设置输入图片
filter.setValue(inputCIImage, forKey: kCIInputImageKey)
// 获取经过滤镜处理之后的图片,并且将其放置在开头设置好的CIContext()中
let result = filter.outputImage!
let cgImage = context.createCGImage(result, from: result.extent)
//返回处理好的图片
return UIImage(cgImage: cgImage!)
}
这时候我们就可以很简单的使用这个滤镜了,如下:
//设置输入的图片
let image: UIImage = UIImage(named: "test")!
//获取输出图片
let outputImage = blurFilter(inputImage: image)
struct FilterView: View {
var body: some View {
Image(uiImage: outputImage)
.resizable()
}
}
我们就能看到处理之后的图片显示在屏幕上啦!我们来处理一下之前的截图。
效果还不错!
由于这些API都非常古早了,和SwiftUI搭配使用会有一些小坑,之前查阅了半天没找到解决办法,也是自己研究了才发现解决之道。
但是别看是很老的API,一些效果也过时了,就觉得这个没啥用。他们是可以嵌套的,就能做出更多的效果。
获取系统相册里的照片
SwiftUI没办法自己获取系统相册内容,所以得依靠一下UIKit,头文件如下:
import SwiftUI
import UIKit
首先我们创建一个ImagePicker结构体供我们获取系统相册内容:
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) private var presentationMode
let sourceType: UIImagePickerController.SourceType
let onImagePicked: (UIImage) -> Void
final class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@Binding private var presentationMode: PresentationMode
private let sourceType: UIImagePickerController.SourceType
private let onImagePicked: (UIImage) -> Void
init(presentationMode: Binding<PresentationMode>,
sourceType: UIImagePickerController.SourceType,
onImagePicked: @escaping (UIImage) -> Void) {
_presentationMode = presentationMode
self.sourceType = sourceType
self.onImagePicked = onImagePicked
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
onImagePicked(uiImage)
presentationMode.dismiss()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
presentationMode.dismiss()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentationMode: presentationMode,
sourceType: sourceType,
onImagePicked: onImagePicked)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = sourceType
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}
然后我们就可以很简单地从系统相册中获取照片了:
struct ContentView: View {
@State private var showImagePicker = false
//这里的image用于放置等会获取的照片
@State private var image: UIImage = UIImage()
var body: some View {
List{
Button(action: {
showImagePicker = true
}, label: {
Text("Select Image")
})
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
}
.sheet(isPresented: $showImagePicker,
content: {
ImagePicker(sourceType: .photoLibrary) { image in
self.image = image
}
})
}
}
不过这样只能一次获取一张照片,但是我们也算可以获取了。
调用系统相机拍照
SwiftUI调用相机和调用相册其实是一个思路,只用修改一个地方。
我们继续来说相机调用,SwiftUI没办法自己获取相机,所以得依靠一下UIKit,所以头文件如下:
import SwiftUI
import UIKit
然后和调用相册一样,我们创建一个ImagePicker结构体供我们获取系统相册内容(所以如果我们需要在一个软件里调用相册和相机的话,就只用创建一个ImagePacker结构体即可):
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) private var presentationMode
let sourceType: UIImagePickerController.SourceType
let onImagePicked: (UIImage) -> Void
final class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@Binding private var presentationMode: PresentationMode
private let sourceType: UIImagePickerController.SourceType
private let onImagePicked: (UIImage) -> Void
init(presentationMode: Binding<PresentationMode>,
sourceType: UIImagePickerController.SourceType,
onImagePicked: @escaping (UIImage) -> Void) {
_presentationMode = presentationMode
self.sourceType = sourceType
self.onImagePicked = onImagePicked
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
onImagePicked(uiImage)
presentationMode.dismiss()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
presentationMode.dismiss()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentationMode: presentationMode,
sourceType: sourceType,
onImagePicked: onImagePicked)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = sourceType
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}
不一样的地方在调用的时候,在相册调用的时候,sourceType部分我们使用的是.photoLibrary,这里我们只要将其改成.camera就可以啦,如下:
struct ContentView: View {
@State private var showCameraPicker = false
//这里的image用于放置等会拍摄了的照片
@State private var image: UIImage = UIImage()
var body: some View {
List{
Button(action: {
showCameraPicker = true
}, label: {
Text("Camera")
})
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
}
.sheet(isPresented: $showCameraPicker,
content: {
ImagePicker(sourceType: .camera) { image in
self.image = image
}
})
}
}
这样我们就能调用系统相机。希望可以帮到需要的人。
iOS技术资料|地址