【iOS】書類スキャンライブラリ「WeScan」の紹介と日本語化など

# WeScanとは
>WeScan makes it easy to add scanning functionalities to your iOS app! It's modelled after UIImagePickerController, which makes it a breeze to use.
https://github.com/WeTransfer/WeScan
![wescan2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/587acb70-35da-e338-cdb7-28d6ae5226e7.gif)



このように、カメラやローカルの画像を取り込んで書類っぽい部分をcropできるライブラリ。例えば[Evernote Scannable](https://help.evernote.com/hc/ja/articles/208430668-Evernote-Scannable-%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%AC%E3%82%A4%E3%83%89)の撮影機能に近い。

2020年に入っても活発に開発されており、いまは紹介映像よりもう少しリッチになっている。

# 使い方
## インストール
Podfileに`pod 'WeScan'`を追加して`pod install`。

## カメラを起動してスキャン
**ImageScannerController**のインスタンスを作ってDelegateを設定、presentすると紹介映像のような画面が出てくる。

```swift
import UIKit
import WeScan // ←忘れずに
class MyViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    func startCamera() {
        let scannerViewController = ImageScannerController()
        scannerViewController.imageScannerDelegate = self
        present(scannerViewController, animated: true)
    }
}
```

**ImageScannerControllerDelegate**を使ってスキャンの結果を取得できる。

```swift
extension MyViewController: ImageScannerControllerDelegate {
    func imageScannerController(_ scanner: ImageScannerController, didFailWithError error: Error) {
        print(error)
    }
    func imageScannerController(_ scanner: ImageScannerController, didFinishScanningWithResults results: ImageScannerResults) {
        let croppedImage = results.croppedScan.image // UIImage
        imageView.image = croppedImage
        scanner.dismiss(animated: true)
    }
    func imageScannerControllerDidCancel(_ scanner: ImageScannerController) {
        scanner.dismiss(animated: true)
    }
}
```

## ライブラリ等から画像を渡してクロッピング
### インスタンス作成時に画像を渡すだけ
**ImageScannerController**のインスタンス作成時に画像を渡すと、カメラは起動せずに渡した画像の編集画面となる。

```swift
let scannerViewController = ImageScannerController(image: image, delegate: self) // どこかから画像を渡す。ついでにdelegateも設定
present(scannerViewController, animated: true)
```
すっごい使いやすい…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/657d239f-921e-ed77-364f-769cc6246c83.png)


### iOS標準のUIImagePickerControllerで画像を持ってきて渡す例
```swift
class MyViewController: UIViewController {
    func openLibrary() {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        present(imagePicker, animated: true)
    }
}
extension MyViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        picker.dismiss(animated: true)
        
        guard let image = info[.originalImage] as? UIImage else { return }
        let scannerViewController = ImageScannerController(image: image, delegate: self) //❗️選んだ画像をWeScanに渡す
        present(scannerViewController, animated: true)
    }
}

extension MyViewController: ImageScannerControllerDelegate { //❗️ここは前と同じ
    func imageScannerController(_ scanner: ImageScannerController, didFailWithError error: Error) {
        print(error)
    }
    func imageScannerController(_ scanner: ImageScannerController, didFinishScanningWithResults results: ImageScannerResults) {
        let croppedImage = results.croppedScan.image
        imageView.image = croppedImage
        scanner.dismiss(animated: true)
    }
    func imageScannerControllerDidCancel(_ scanner: ImageScannerController) {
        scanner.dismiss(animated: true)
    }
}
```

# 日本語化とカスタマイズ
すごく良いライブラリなのだが、ちょっと変更したいところもあって…

日本語がない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/99855708-01de-88c8-30ad-42f749dfe2a7.png)

また、今回の用途だとクロップ設定の初期範囲が少し狭いのが気になった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/2784a323-6059-1a7c-0dea-ab1d774dc9fd.png)

## Fork
なので、Forkしてカスタマイズします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/26939a9c-6a10-9c0c-c4f3-45f6ac215d88.png)

ForkしたリポジトリをPodfileに登録して使う方法は以下に単体で記事を作りました。
[【CocoaPods】iOSのライブラリをForkして使う](https://qiita.com/hiroism/items/79a913625f6407b7724d)

ちなみにWeScanはMITライセンス。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/c7d79ef3-e8f6-cf61-c4e8-0f9b13525be5.png)

## 日本語化
ForkしたWeScanをXcodeで開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/999105a9-51f0-7ae1-5abd-4d99634512f3.png)
↓選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/a233f085-926e-309c-3066-5e8dadc29f1d.png)
↓選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/c556c532-f42f-2fb6-38e6-f68031044749.png)
↓＋を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/55d8d2b8-4a72-f3c4-1e2b-9351c362757e.png)
↓選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/2b27a9a9-eca0-91c4-4a63-b84975cc1069.png)
↓チェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/4ab8bf41-146e-368b-6282-10969d6f109a.png)
↓選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/b256030b-8cea-dcc3-faba-c46c9749054f.png)
WeScan/Localizable.strings以下にJapaneseが追加されるので、例えば以下のように編集。

```
"wescan.edit.button.next" = "次へ";
"wescan.edit.title" = "切り取り";

"wescan.review.title" = "プレビュー";

"wescan.scanning.cancel" = "キャンセル";
"wescan.scanning.auto" = "オート";
"wescan.scanning.manual" = "マニュアル";
```

## 初期クロップ範囲を変更する

このあたりを

```swift:WeScan/Edit/EditScanViewController.swift
    /// Generates a `Quadrilateral` object that's centered and one third of the size of the passed in image.
    private static func defaultQuad(forImage image: UIImage) -> Quadrilateral {
        let topLeft = CGPoint(x: image.size.width / 3.0, y: image.size.height / 3.0)
        let topRight = CGPoint(x: 2.0 * image.size.width / 3.0, y: image.size.height / 3.0)
        let bottomRight = CGPoint(x: 2.0 * image.size.width / 3.0, y: 2.0 * image.size.height / 3.0)
        let bottomLeft = CGPoint(x: image.size.width / 3.0, y: 2.0 * image.size.height / 3.0)
        
        let quad = Quadrilateral(topLeft: topLeft, topRight: topRight, bottomRight: bottomRight, bottomLeft: bottomLeft)
        
        return quad
    }
```

このように変更すると、

```swift
        let topLeft = CGPoint(x: 0, y: 0)
        let topRight = CGPoint(x: image.size.width, y: 0)
        let bottomRight = CGPoint(x: image.size.width, y: image.size.height)
        let bottomLeft = CGPoint(x: 0, y: image.size.height)
```

画像全体が選択された状態から始まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/203038dd-ecf5-3d35-b965-abca35087b81.png)

## Podfile
コードを書き換えたらpushし、自分のアプリに戻ってPodfileを編集。
repoとbranchを指定してpod installすれば完了。

```ruby
  pod 'WeScan', :git => 'git@github.com:{{ your name }}/WeScan.git', :branch => '{{ your branch }}'
```