Core ImageとSwiftUIの統合
Integrating Core Image with SwiftUI
struct ContentView: View {
@State private var image: Image?
var body: some View {
VStack {
image?
.resizable()
.scaledToFit()
}
.onAppear(perform: loadImage)
}
func loadImage() {
image = Image("Example")
}
}
SwiftUIのImageビューとは別に、他の3つのイメージタイプは次のとおりです。
UIImage、これはUIKitから来ています。これは、ビットマップ(PNGなど)、ベクター(SVGなど)、さらにはアニメーションを形成するシーケンスなど、さまざまな画像タイプを処理できる非常に強力な画像タイプです。UIImageUIKitの標準の画像タイプで、3つのうちSwiftUIのImageタイプに最も近いタイプです。
CGImage、Core Graphicsによるものです。これは、実際には単なるピクセルの2次元配列である単純なイメージタイプです。
CIImage、Core Imageから来ています。これは、画像の生成に必要なすべての情報を保存しますが、要求されない限り、実際にはそれをピクセルに変換しません。AppleはCIImage、実際の画像ではなく「画像レシピ」と呼んでいます。
いくつかの相互運用性があります。
私たちは、作成することができますUIImageからしCGImageて、作成CGImageからUIImage。
私たちは、作成することができますCIImageからUIImageからCGImage、および作成することができますCGImageからCIImage。
私たちは、SwiftUI作成することができImage、Aの両方からUIImageとCGImage。
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
struct ContentView: View {
@State private var image: Image?
var body: some View {
VStack {
image?
.resizable()
.scaledToFit()
}
.onAppear(perform: loadImage)
}
//--------------
func loadImage() {
//CIImageこれはCore Imageで使用したいものです。
guard let inputImage = UIImage(named: "IMG_1308") else { return }
let beginImage = CIImage(image: inputImage)
// more code to come
//コンテキストとフィルターを作成します。
let context = CIContext()
//セピアは単純なフィルターであるため、2つのプロパティしかありません。
//セピア効果を適用する強さを0(元の画像)と1(フルセピア)の範囲で指定します。
let currentFilter = CIFilter.sepiaTone()
//フィルターをカスタマイズして、動作を変更できます。
currentFilter.inputImage = beginImage
currentFilter.intensity = 1
// let currentFilter = CIFilter.pixellate()
// currentFilter.inputImage = beginImage
// currentFilter.scale = 50
// let currentFilter = CIFilter.crystallize()
// currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
// currentFilter.radius = 200
// guard let currentFilter = CIFilter(name: "CITwirlDistortion") else { return }
// currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
// currentFilter.setValue(2000, forKey: kCIInputRadiusKey)
// currentFilter.setValue(CIVector(x: inputImage.size.width / 2, y: inputImage.size.height / 2), forKey: kCIInputCenterKey)
// get a CIImage from our filter or exit if that fails
guard let outputImage = currentFilter.outputImage else { return }
// attempt to get a CGImage from our CIImage
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
// convert that to a UIImage
let uiImage = UIImage(cgImage: cgimg)
// and convert that to a SwiftUI image
image = Image(uiImage: uiImage)
}
}
//--------------
}
SwiftUIビューでのUIViewControllerのラップ
Wrapping a UIViewController in a SwiftUI view
このプロジェクトでは、ユーザーにフォトライブラリから画像をインポートするように依頼します。UIKitには、これを行うための専用コードが付属していますが、これはSwiftUIに移植されていないため、そのブリッジを自分で作成する必要があります。
ライブラリから写真を選択するようにユーザに尋ねるのUIKitののシステムと呼ばれるビューコントローラを使用するためUIImagePickerController、およびデリゲートプロトコルと呼ばれるUINavigationControllerDelegateとUIImagePickerControllerDelegate。SwiftUIはこれら2つを直接使用できないため、ラップする必要があります。
UIKitビューコントローラーをラップするには、UIViewControllerRepresentableプロトコルに準拠した構造体を作成する必要があります。
もう1つはと呼ばれ、updateUIViewController()SwiftUIの状態が変化したときにビューコントローラーを更新できるように設計されています。
//
// ImagePicker.swift
// Core-Image
//
// Created by Naoki Abe on 2020/08/22.
// Copyright © 2020 Naoki Abe. All rights reserved.
//
import Foundation
import SwiftUI
//struct ImagePicker: UIViewControllerRepresentable {
// typealias UIViewControllerType = UIImagePickerController
//}
////Type 'ImagePicker' does not conform to protocol 'UIViewControllerRepresentable'
////Do you want to add protocol stubs?
//// Fix ↓
struct ImagePicker: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
typealias UIViewControllerType = UIImagePickerController
}
import SwiftUI
struct ContentView: View {
@State private var image: Image?
@State private var showingImagePicker = false
var body: some View {
VStack {
image?
.resizable()
.scaledToFit()
Button("Select Image") {
self.showingImagePicker = true
}
}
.sheet(isPresented: $showingImagePicker) {
ImagePicker()
}
}
}
ただし、選択したばかりの画像は表示されません。SwiftUI Imageをビューに配置したにもかかわらず、からの選択をどこにも割り当てていないことがわかりますUIImagePickerController。
それを実現するには、まったく新しいコンセプトであるコーディネーターが必要です。
PART3へ続く!!