-
Notifications
You must be signed in to change notification settings - Fork 3
/
ContentView.swift
140 lines (116 loc) · 4.83 KB
/
ContentView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//
// ContentView.swift
// P13E InstaFilter
//
// Created by Julian Moorhouse on 10/04/2021.
//
import CoreImage
import CoreImage.CIFilterBuiltins
import SwiftUI
struct ContentView: View {
@State private var image: Image?
@State private var filterIntensity = 0.5
@State private var showingFilterSheet = false
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
@State private var processedImage: UIImage?
@State var currentFilter: CIFilter = CIFilter.sepiaTone()
let context = CIContext()
var body: some View {
let intensity = Binding<Double>(
get: {
self.filterIntensity
},
set: {
self.filterIntensity = $0
self.applyProcessing()
}
)
return NavigationView {
VStack {
ZStack {
Rectangle()
.fill(Color.secondary)
if image != nil {
image?
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
}
.onTapGesture {
self.showingImagePicker = true
}
HStack {
Text("Intensity")
Slider(value: intensity)
}
.padding(.vertical)
HStack {
Button("Change Filter") {
self.showingFilterSheet = true
}
Spacer()
Button("Save") {
guard let processedImage = self.processedImage else { return }
let imageSaver = ImageSaver()
imageSaver.successHandler = {
print("Success!")
}
imageSaver.errorHandler = {
print("Oops: \($0.localizedDescription)")
}
imageSaver.writeToPhotoAlbum(image: processedImage)
}
}
}
.padding([.horizontal, .bottom])
.navigationBarTitle("Instafilter")
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
ImagePicker(image: self.$inputImage)
}
.actionSheet(isPresented: $showingFilterSheet) {
ActionSheet(title: Text("Select a filter"), buttons: [
.default(Text("Crystallize")) { self.setFilter(CIFilter.crystallize()) },
.default(Text("Edges")) { self.setFilter(CIFilter.edges()) },
.default(Text("Guaussian Blur")) { self.setFilter(CIFilter.gaussianBlur()) },
.default(Text("Pixellate")) { self.setFilter(CIFilter.pixellate()) },
.default(Text("Sepia Tone")) { self.setFilter(CIFilter.sepiaTone()) },
.default(Text("Unsharp Mask")) { self.setFilter(CIFilter.unsharpMask()) },
.default(Text("Vignette")) { self.setFilter(CIFilter.vignette()) },
.cancel()
])
}
}
}
func loadImage() {
guard let inputImage = inputImage else { return }
let beginImage = CIImage(image: inputImage)
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
applyProcessing()
}
func applyProcessing() {
let inputKeys = currentFilter.inputKeys
if inputKeys.contains(kCIInputIntensityKey) { currentFilter.setValue(filterIntensity, forKey: kCIInputIntensityKey) }
if inputKeys.contains(kCIInputRadiusKey) { currentFilter.setValue(filterIntensity * 200, forKey: kCIInputRadiusKey) }
if inputKeys.contains(kCIInputScaleKey) { currentFilter.setValue(filterIntensity * 10, forKey: kCIInputScaleKey) }
guard let outputImage = currentFilter.outputImage else { return }
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
let uiImage = UIImage(cgImage: cgimg)
image = Image(uiImage: uiImage)
processedImage = uiImage
}
}
func setFilter(_ filter: CIFilter) {
currentFilter = filter
loadImage()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}