Skip to content

Instantly share code, notes, and snippets.

@tdtsh
Last active January 17, 2016 07:01
Show Gist options
  • Save tdtsh/09c23884eef722cd2a2d to your computer and use it in GitHub Desktop.
Save tdtsh/09c23884eef722cd2a2d to your computer and use it in GitHub Desktop.
Swift2 で AVCaptureStillImageOutput を使ったカメラ撮影
//
// CameraViewController.swift
//
// Created by Tadatoshi Hanazaki on 2016/01/17.
// Copyright © 2016年 close-to.biz. All rights reserved.
//
import UIKit
import AVFoundation
class CameraViewController: UIViewController, UIGestureRecognizerDelegate {
// AVキャプチャセッション
var avSession: AVCaptureSession!
// AVキャプチャデバイス
var avDevice: AVCaptureDevice!
// AVキャプチャデバイスインプット
var avInput: AVCaptureInput!
// AVキャプチャアウトプット
var avOutput: AVCaptureStillImageOutput!
override func viewDidLoad() {
super.viewDidLoad()
// 画面タップで撮影
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "takePhoto:")
tapGesture.delegate = self;
self.view.addGestureRecognizer(tapGesture)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.initCamera()
}
func initCamera() {
// AVキャプチャセッション
// (AVFoundationにおけるキャプチャ入出力を管理するクラス)
avSession = AVCaptureSession()
if (avSession.canSetSessionPreset(AVCaptureSessionPresetPhoto)) {
avSession.beginConfiguration()
// キャプチャクオリティ設定
// AVCaptureSessionPresetPhoto 写真専用、デバイスの最大解像度
// AVCaptureSessionPresetHigh 最高録画品質 (静止画でも一番高画質なのはコレ)
// AVCaptureSessionPresetMedium WiFi向け
// AVCaptureSessionPresetLow 3G向け
// AVCaptureSessionPreset640x480 640x480 VGA固定
// AVCaptureSessionPreset1280x720 1280x720 HD固定
avSession.sessionPreset = AVCaptureSessionPresetPhoto
avSession.commitConfiguration()
}
// AVキャプチャデバイス
// (前背面カメラやマイク等のデバイス)
let devices = AVCaptureDevice.devices()
for capDevice in devices {
if (capDevice.position == AVCaptureDevicePosition.Back) {
// 背面カメラを取得
avDevice = capDevice as? AVCaptureDevice
}
}
if (avDevice != nil) {
// AVキャプチャデバイスインプット
// (AVキャプチャデバイスからの入力)
do {
// バックカメラからVideoInputを取得
avInput = try AVCaptureDeviceInput.init(device: avDevice!)
} catch let error as NSError {
print(error)
}
// AVキャプチャデバイスインプットをセッションに追加
if (avSession.canAddInput(avInput)) {
avSession.addInput(avInput)
// AVキャプチャアウトプット (出力方法)
// AVCaptureStillImageOutput: 静止画
// AVCaptureMovieFileOutput: 動画ファイル
// AVCaptureAudioFileOutput: 音声ファイル
// AVCaptureVideoDataOutput: 動画フレームデータ
// AVCaptureAudioDataOutput: 音声データ
avOutput = AVCaptureStillImageOutput()
// 出力設定
avOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
// AVキャプチャアウトプットをセッションに追加
if (avSession.canAddOutput(avOutput)) {
avSession.addOutput(avOutput)
}
// 画像を表示するレイヤーを生成.
let capVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session:avSession)
capVideoLayer.frame = self.view.bounds
capVideoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
// AVLayerVideoGravityResizeAspectFill
// アスペクト比維持 + 必要に応じてトリミング (縦いっぱいに表示し横をトリミング)
// AVLayerVideoGravityResizeAspect
// アスペクト比維持 (縦横とも収まる様に表示)
// AVLayerVideoGravityResize
// 利用可能な画面領域いっぱいにリサイズ
// Viewに追加.
self.view.layer.addSublayer(capVideoLayer)
// セッション開始.
avSession.startRunning()
renderView()
}
} else {
// UIAlertControllerを作成する.
let sampleAlert: UIAlertController = UIAlertController(title: "", message: "背面カメラがある実機で動かしてね。", preferredStyle: .Alert)
// アクションを作成、追加
let yesAction = UIAlertAction(title: "OK", style: .Default) {
UIAlertAction in
self.close()
}
sampleAlert.addAction(yesAction)
// UIAlertを表示する
self.presentViewController(sampleAlert, animated: true, completion: nil)
}
}
// 画面を閉じる
func close() {
self.navigationController?.popViewControllerAnimated(true)
}
// 画面になにか重ねて表示する
func renderView() {
// 角丸なLabelを作成
let labelHello: UILabel = UILabel(frame: CGRectMake(0, 0, self.view.frame.size.width - 40, 40))
labelHello.layer.masksToBounds = true
labelHello.layer.cornerRadius = 5.0
labelHello.lineBreakMode = NSLineBreakMode.ByCharWrapping
labelHello.numberOfLines = 1
// 文字と文字色、背景色をセット
labelHello.text = "画面タップで撮影&アルバム保存"
labelHello.textColor = UIColor.whiteColor()
labelHello.backgroundColor = UIColor.init(colorLiteralRed: 0.8, green: 0.2, blue: 0.3, alpha: 1.0)
// 文字を中央寄せ、ウィンドウ中央に配置
labelHello.textAlignment = NSTextAlignment.Center
labelHello.layer.position = CGPoint(x: self.view.bounds.width/2, y: self.view.bounds.height - 80)
// ViewにLabelを追加.
self.view.addSubview(labelHello)
}
// 撮影をする
func takePhoto(sender: UITapGestureRecognizer){
// ビデオ出力に接続する
let videoConnection = avOutput.connectionWithMediaType(AVMediaTypeVideo)
// 接続から画像を取得する
self.avOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (imageDataBuffer, error) -> Void in
// Jpegに変換する (NSDataにはExifなどのメタデータも含まれている)
let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)
// UIIMageを作成する
let image: UIImage = UIImage(data: imageData)!
// アルバムに追加する
UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
self.close()
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
// カメラの停止とメモリ解放
self.avSession.stopRunning()
for output in self.avSession.outputs {
self.avSession.removeOutput(output as? AVCaptureOutput)
}
for input in self.avSession.inputs {
self.avSession.removeInput(input as? AVCaptureInput)
}
self.avOutput = nil
self.avInput = nil
self.avDevice = nil
self.avSession = nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment