Swift2で写真を合成するiPhoneアプリを作ってみた

# はじめに

iPhoneのカメラ機能を使って、あらかじめ用意したスタンプ画像と合成するアプリを作ってみました。どこを撮影しても小さなオジサンが写り込みます。笑

![IMG_2130.JPG](https://qiita-image-store.s3.amazonaws.com/0/72802/8067b810-22cd-4f46-e3f0-3a1ec4482bd3.jpeg)

[完成イメージはこんな感じ(Youtube)](https://www.youtube.com/watch?v=hAmRfL9sZLQ)です。Xcode7とSwift2での作り方を紹介します。

# 開発環境

Xcode 7.1
Swift 2.1
iOS 9.0
OS X v10.11

# 作り方

## １．プロジェクトを作る

Xcodeから[iOS]-[Application]をクリックし、[Single View Application]を選択する。

![１.png](https://qiita-image-store.s3.amazonaws.com/0/72802/25224922-d0a0-f075-1392-c3568272fdfe.png)

## ２．スタンプ画像を用意する

PNG形式のスタンプ画像を用意する。背景は透過、サイズは320x426です。

![13.png](https://qiita-image-store.s3.amazonaws.com/0/72802/23602953-cd0f-1a19-d4f2-2d361a20c807.png)

## ３．スタンプ画像をプロジェクトに読み込む

Xcodeの[File]-[Add Files to プロジェクト名]をクリックし、スタンプ画像を選択する。

![２.png](https://qiita-image-store.s3.amazonaws.com/0/72802/d436ec2b-fa72-a858-d6bb-4b5f13ac7ac6.png)

オプションの[Copy items if needed]にチェックを入れ、[Add]ボタンをクリックする。

![３.png](https://qiita-image-store.s3.amazonaws.com/0/72802/5f71d84b-34bf-fbd5-740e-e9645a252909.png)

## ４．アプリを縦画面のみに設定する

プロジェクト設定の[General]-[Deployment info]-[Device Orientation]にある、[Landscape Left]と[Landsape Right]のチェックを外す。

![４.png](https://qiita-image-store.s3.amazonaws.com/0/72802/e2dfc296-9213-b911-5bd0-2193fec00e04.png)

## ５．オートレイアウトを解除する

Xcodeの[Main storyboard]をクリックし、[Use Auto Layout]のチェックを外す。

![５.png](https://qiita-image-store.s3.amazonaws.com/0/72802/3d9ddc4c-358f-d035-fc30-be0e1c5e5421.png)

ダイアログが表示されるので[Disable Size Classes]ボタンをクリックする。

![６.png](https://qiita-image-store.s3.amazonaws.com/0/72802/afad5161-7fcf-290c-a940-1b927f7e506c.png)

## ６．コンポーネントを配置する

ViewControllerに[Image View]を配置する。サイズは幅320px、高さ426pxにする。

![７.png](https://qiita-image-store.s3.amazonaws.com/0/72802/c57e6447-21ec-8a4b-a7c6-0e9e4e5d1e39.png)

同じように[Button]を配置する。ボタンの表示文字列を[撮影]にする。

![８.png](https://qiita-image-store.s3.amazonaws.com/0/72802/942cbc7c-52d5-9595-c0c7-8531a76554a1.png)

## ７．コンポーネントをプログラムに接続する

[Image View]をソースコードに[control]キーを押しながらドラッグし、Outletを作成する。ここでは[cameraImgView]とした。

![9.png](https://qiita-image-store.s3.amazonaws.com/0/72802/1472c528-2955-4e0d-f9b1-683092e7592e.png)

同じように[Button]をドラッグし、[btnPushed]という名前のActionを作成する。

![10.png](https://qiita-image-store.s3.amazonaws.com/0/72802/dd1f81e7-d7b1-2cfd-28a3-4df900c6f4ad.png)

## ８．カメラを起動するプログラムを書く

UIViewControllerクラスにUIImagePickerControllerDelegateとUINavigationControllerDelegateクラスを継承させる。

UIImagePickerController型の変数を作成し、presentViewControllerメソッドでカメラ機能が立ち上がる。
引数に[UIImagePickerControllerSourceType.Camera]を指定することを忘れずに。

シャッターが押された際の動作は、imagePickerControllerメソッド内で指定できる。

![11.png](https://qiita-image-store.s3.amazonaws.com/0/72802/82277831-b50f-ac12-3ab0-bbf5630e6449.png)

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var cameraImgView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func btnPushed(sender: AnyObject) {
        // ----- カメラを起動する
        let picker = UIImagePickerController()
        picker.sourceType = UIImagePickerControllerSourceType.Camera
        picker.delegate = self
        presentViewController(picker, animated: true, completion: nil)
    }
    
    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
        cameraImgView.image = image                             // 撮影した画像をセットする
        
        dismissViewControllerAnimated(true, completion: nil)    // アプリ画面へ戻る
    }

}
```

iPhoneアプリを起動してみるとこんな感じ。⇒ [Youtube動画](https://www.youtube.com/watch?v=-zxBCO9DQv4)

## ９．スタンプ画像を合成して保存する

UIImage型の変数を定義して、スタンプ画像を読み込みます。
addSubviewメソッドで撮影した画像とスタンプ画像を合成します。

![12.png](https://qiita-image-store.s3.amazonaws.com/0/72802/830330fe-d954-22fc-ccd1-7bc87d79fe03.png)

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var cameraImgView: UIImageView!
    let stamp = UIImage(named: "ojisan.png")            // スタンプ画像
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func btnPushed(sender: AnyObject) {
        // ----- カメラを起動する
        let picker = UIImagePickerController()
        picker.sourceType = UIImagePickerControllerSourceType.Camera
        picker.delegate = self
        presentViewController(picker, animated: true, completion: nil)
    }
    
    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
        let stampViews = cameraImgView.subviews
        for stampView in stampViews {
            stampView.removeFromSuperview()                     // スタンプをリセットする
        }
        cameraImgView.image = image                             // 撮影した画像をセットする
        cameraImgView.addSubview(UIImageView(image: stamp))     // スタンプ画像を合成する
                
        dismissViewControllerAnimated(true, completion: nil)    // アプリ画面へ戻る
    }

}
```

## １０．合成した画像を保存する

合成した画像を保存するには、imagePickerControllerメソッドを次のように修正します。

```swift:ViewController.swift
    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
        let stampViews = cameraImgView.subviews
        for stampView in stampViews {
            stampView.removeFromSuperview()                     // スタンプをリセットする
        }
        cameraImgView.image = image                             // 撮影した画像をセットする
        cameraImgView.addSubview(UIImageView(image: stamp))     // スタンプ画像を合成する
        
        // ----- 合成した画像を保存する
        UIGraphicsBeginImageContext(cameraImgView.bounds.size)
        cameraImgView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
        UIImageWriteToSavedPhotosAlbum(UIGraphicsGetImageFromCurrentImageContext(), self, nil, nil)
        UIGraphicsEndImageContext()
        
        dismissViewControllerAnimated(true, completion: nil)    // アプリ画面へ戻る
    }
```

# サンプルダウンロード

GitHubに完成品をアップロードしておいたので、どうぞご参考ください。
⇒ [ダウンロード](https://github.com/kawai-norimitsu/ojisanCamera)

# 参考サイト

[iPhoneアプリ開発のためのSwiftレシピ](https://sites.google.com/site/swift4iphone/)