ActionSheetを使用してフィルターをカスタマイズする
Customizing our filter using ActionSheet
//
// ContentView.swift
// Instafilter-2
//
// Created by Naoki Abe on 2020/08/23.
// Copyright © 2020 Naoki Abe. All rights reserved.
//
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
struct ContentView: View {
@State private var image: Image?
@State private var filterIntensity = 0.5
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
//画像を処理
//@State private var currentFilter = CIFilter.sepiaTone()
@State private var currentFilter: CIFilter = CIFilter.sepiaTone()
let context = CIContext()
@State private var showingFilterSheet = false
//画像を処理するメソッド
func applyProcessing() {
//currentFilter.intensity = Float(filterIntensity)
//currentFilter.setValue(filterIntensity, forKey: kCIInputIntensityKey)
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)
}
}
func setFilter(_ filter: CIFilter) {
currentFilter = filter
loadImage()
}
func loadImage() {
guard let inputImage = inputImage else { return }
let beginImage = CIImage(image: inputImage)
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
applyProcessing()
}
//------------------------------------------------------
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)
// display the image
if image != nil {
image?
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
}
.onTapGesture {
// select an image
self.showingImagePicker = true
}
HStack {
Text("Intensity")
Slider(value: intensity)
}.padding(.vertical)
HStack {
Button("Change Filter") {
// change filter
self.showingFilterSheet = true
}
Spacer()
Button("Save") {
// save the picture
}
}
}
.padding([.horizontal, .bottom])
.navigationBarTitle("Instafilter")
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
ImagePicker(image: self.$inputImage)
}
.actionSheet(isPresented: $showingFilterSheet) {
// action sheet here
ActionSheet(title: Text("Select a filter"), buttons: [
.default(Text("Crystallize")) { self.setFilter(CIFilter.crystallize()) },
.default(Text("Edges")) { self.setFilter(CIFilter.edges()) },
.default(Text("Gaussian 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()
])
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
UIImageWriteToSavedPhotosAlbum()を使用してフィルターされた画像を保存する
このプロジェクトを完了するには、[保存]ボタンを有効にして、フィルター処理された写真をユーザーの写真ライブラリに保存し、ユーザーがさらに編集したり、共有したりできるようにします。
Privacy – Photo Library Additions Usage Description
We want to save the filtered photo.
Info.plistを開く
空白スペースを右クリック
[行を追加]を選択します
キー名として「プライバシー-フォトライブラリ追加機能の使用法の説明」を選択します。
「フィルタリングされた写真を保存したい」と入力します。値として。
import UIKit
class ImageSaver: NSObject {
var successHandler: (() -> Void)?
var errorHandler: ((Error) -> Void)?
func writeToPhotoAlbum(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
}
@objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
// save complete
if let error = error {
errorHandler?(error)
} else {
successHandler?()
}
}
}
//
// ContentView.swift
// Instafilter-2
//
// Created by Naoki Abe on 2020/08/23.
// Copyright © 2020 Naoki Abe. All rights reserved.
//
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
struct ContentView: View {
@State private var image: Image?
@State private var filterIntensity = 0.5
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
//画像を処理
//@State private var currentFilter = CIFilter.sepiaTone()
@State private var currentFilter: CIFilter = CIFilter.sepiaTone()
let context = CIContext()
@State private var showingFilterSheet = false
@State private var processedImage: UIImage?
//画像を処理するメソッド
func applyProcessing() {
//currentFilter.intensity = Float(filterIntensity)
//currentFilter.setValue(filterIntensity, forKey: kCIInputIntensityKey)
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()
}
func loadImage() {
guard let inputImage = inputImage else { return }
let beginImage = CIImage(image: inputImage)
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
applyProcessing()
}
//------------------------------------------------------
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)
// display the image
if image != nil {
image?
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
}
.onTapGesture {
// select an image
self.showingImagePicker = true
}
HStack {
Text("Intensity")
Slider(value: intensity)
}.padding(.vertical)
HStack {
Button("Change Filter") {
// 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) {
// action sheet here
ActionSheet(title: Text("Select a filter"), buttons: [
.default(Text("Crystallize")) { self.setFilter(CIFilter.crystallize()) },
.default(Text("Edges")) { self.setFilter(CIFilter.edges()) },
.default(Text("Gaussian 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()
])
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}