ライブラリを利用して画像トリミング機能を実装

## はじめに
画像を円形と四角形にトリミングできる機能を実装するために、[Mantisライブラリ](https://github.com/guoyingtao/Mantis)を利用しました。

### Mantisライブラリ
ライブラリが提供する代表的な機能は以下のとおりです。
- トリミングの形指定(四角形、円形、ハート型、五角形、楕円、ひし形...)
- 四角形の場合は比率変更（original, square, 3:2, 4:3, 16:9...）
- 回転
- 反転（左右、上下）

 
## 作成物
<img width="200" alt="IMG_0191.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588694/d455a5ea-e342-5dd7-d308-156231fc441c.png">
<img width="200" alt="IMG_0190.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588694/07d3cc2f-904c-b4db-7a07-af28d35efa85.png">

## トリミング機能
`Mantis`をインポートします。
```swift:ImageCropper.swift
import SwiftUI
import Mantis
```

`Coordinator`クラスを作成します。
```swift:ImageCropper.swift
class CropCoordinator: NSObject, CropViewControllerDelegate{
    @Binding var image: UIImage?
    @Binding var isCropViewShowing: Bool // トリミングviewを出すかどうか
    init(image: Binding<UIImage?>, isCropViewShowing: Binding<Bool>){
        _image = image
        _isCropViewShowing = isCropViewShowing
    }
    
    func cropViewControllerDidFailToCrop(_ cropViewController: Mantis.CropViewController, original: UIImage) {
    
    }
    
    func cropViewControllerDidCancel(_ cropViewController: Mantis.CropViewController, original: UIImage) {
        isCropViewShowing = false
    }
    
    func cropViewControllerDidBeginResize(_ cropViewController: Mantis.CropViewController) {
        
    }
    
    func cropViewControllerDidEndResize(_ cropViewController: Mantis.CropViewController, original: UIImage, cropInfo: Mantis.CropInfo) {
        
    }
    
    func cropViewControllerDidCrop(_ cropViewController: CropViewController, cropped: UIImage, transformation: Transformation, cropInfo: CropInfo) {
        image = cropped
        isCropViewShowing = false
    }
}
```

`Coordinator`をインスタンス化します。
トリミングの形は`cropShapeType`で指定しています。`func makeUIViewController`で`config.cropShapeType = cropShapeType`とトリミングの形を指定しない場合は、デフォルトで四角形になります。

```swift:ImageCropper.swift
struct ImageCropper: UIViewControllerRepresentable{
    typealias Coordinator = CropCoordinator
    @Binding var image: UIImage?
    @Binding var isCropViewShowing: Bool
    @Binding var cropShapeType: Mantis.CropShapeType //　トリミングの形(丸や四角)
        
    func makeCoordinator() -> Coordinator{
        return Coordinator(image: $image, isCropViewShowing: $isCropViewShowing)
    }
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImageCropper>) -> Mantis.CropViewController {
        var config = Mantis.Config()
        config.cropShapeType = cropShapeType // トリミングの形変更に必要
        let Editor = Mantis.cropViewController(image: image ?? UIImage(), config: config)
        Editor.delegate = context.coordinator
        return Editor
    }
}
```


## 呼び出し元
`.fullScreenCover()`で上記の`ImageCropper()`を呼び出しています。
```swift:ImageView.swift
import SwiftUI
import Mantis

struct ImageDetailView: View {
    @State var image: UIImage?
    @State var isCropViewShowing = false
    @State private var cropShapeType: Mantis.CropShapeType = .rect //　トリミングの形を指定
    
    var body: some View {
        VStack{          
            Spacer()
            Image(uiImage: image!) // 画像表示
                .resizable()
                .scaledToFit()
            
            Spacer()
            HStack{
                Spacer()
                Button{ // 丸トリミングボタン
                    cropShapeType = .circle()
                    isCropViewShowing = true
                }label:{
                    Image(systemName: "circle.square")
                        .font(.title2)
                }
                .padding()
                Spacer()
                Button{ // 四角トリミングボタン
                    cropShapeType = .rect
                    isCropViewShowing = true
                }label:{
                    Image(systemName: "crop")
                        .font(.title2)
                }
                .padding()
                Spacer()
            }
        }
        // トリミング画面の表示
        .fullScreenCover(isPresented: $isCropViewShowing){
            ImageCropper(image: $image, isCropViewShowing: $isCropViewShowing, cropShapeType: $cropShapeType)
                    .ignoresSafeArea()
        }
    }
```

## 参考
- Mantis ライブラリ
https://github.com/guoyingtao/Mantis
- 四角形トリミングのコード参考
https://www.youtube.com/watch?v=2wOsaHzbA1U