100 Days of SwiftUI(DAY 63(Project13 part 2))

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へ続く!!