12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Swift5での正方形カメラ

Last updated at Posted at 2019-05-27

#はじめに
 Swift5で正方形の写真を撮影するカメラの作り方を勉強してみました。
 iPhoneのWidthと同じ長さの正方形の写真をカメラロールに保存してみます。
##カメラアプリを作る2種類の方法
###・UIImagePickerController
 簡単にカメラで撮影するアプリが作れます。正方形で撮影するのは難しそう。
###・AVFoundation
 動画を撮影したり、いろいろできる賢いやつです。←今回はこちらです。

#実装方法
##あらかじめinfo.plistに二つの記述が必要です。
・Privacy - Camera Usage Description
 「カメラを使います」的な内容を記載
・Privacy - Photo Library Additions Usage Description
 「カメラロールに保存します」的な内容を記載
##ソースコード

ViewController.swift
import UIKit
import AVFoundation

class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    var device: AVCaptureDevice!
    var session: AVCaptureSession!
    var output: AVCapturePhotoOutput!
    var tempImage:UIImage!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        setPicture()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //カメラ準備
    func setPicture(){
        //セッションを生成
        session = AVCaptureSession()
        //背面カメラを選択
        device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
        //背面カメラからキャプチャ入力生成
        guard let input = try? AVCaptureDeviceInput(device: device) else {
            print("例外発生")
            return
        }
        session.addInput(input)
        output = AVCapturePhotoOutput()
        session.addOutput(output)
        session.sessionPreset = .photo
        // プレビューレイヤーを生成
        let pvSize = self.view.frame.width
        let pvLayer = AVCaptureVideoPreviewLayer(session: session)
        pvLayer.frame = view.bounds
        pvLayer.frame = CGRect(x: 0, y: 90, width: pvSize, height: pvSize)
        pvLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
        view.layer.addSublayer(pvLayer)
        // セッションを開始
        session.startRunning()
        // 撮影ボタンを生成
        let shutterBtn = UIButton()
        shutterBtn.setTitle("◯", for: .normal)
        shutterBtn.titleLabel?.font = UIFont.systemFont(ofSize: 74)
        shutterBtn.contentMode = .center
        shutterBtn.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
        shutterBtn.layer.cornerRadius = 0.5 * shutterBtn.bounds.size.width
        shutterBtn.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        shutterBtn.setTitleColor(UIColor.black, for: UIControl.State())
        shutterBtn.layer.position = CGPoint(x: view.frame.width / 2, y: self.view.bounds.size.height - 80)
        shutterBtn.addTarget(self, action: #selector(photoshot), for: .touchUpInside)
        view.addSubview(shutterBtn)
        //キャンセルボタンを生成
        let cancelBtn = UIButton()
        cancelBtn.setTitle("×", for: .normal)
        cancelBtn.titleLabel?.font = UIFont.systemFont(ofSize: 32)
        cancelBtn.contentMode = .center
        cancelBtn.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
        cancelBtn.setTitleColor(UIColor.white, for: UIControl.State())
        cancelBtn.layer.position = CGPoint(x: 20, y: 40)
        cancelBtn.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
        view.addSubview(cancelBtn)
    }
    //撮影
    @objc func photoshot(_ sender: AnyObject) {
        let settings = AVCapturePhotoSettings()
        settings.flashMode = .off
        settings.isAutoStillImageStabilizationEnabled = true
        output.capturePhoto(with: settings, delegate: self)
    }
    //撮影結果・再撮影・保存ボタンの表示
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if error == nil {
            let outputImageView = UIImageView()
            let pvSize = self.view.frame.width
            outputImageView.frame = CGRect(x: 0, y: 90, width: pvSize, height: pvSize)
            outputImageView.image = UIImage(data: photo.fileDataRepresentation()!)?.croppingToCenterSquare()
            tempImage = UIImage(data: photo.fileDataRepresentation()!)?.croppingToCenterSquare()
            self.view.addSubview(outputImageView)
            session.stopRunning()
            //再撮影ボタン
            let retryBtn = UIButton()
            retryBtn.setTitle("再撮影", for:.normal)
            retryBtn.frame = CGRect(x:self.view.frame.width/2 - 150,y:self.view.frame.height - 115,width: 70,height: 70)
            retryBtn.addTarget(self, action: #selector(retryPhoto), for: .touchUpInside)
            view.addSubview(retryBtn)
            //保存ボタン
            let saveBtn = UIButton()
            saveBtn.setTitle("保存", for: .normal)
            saveBtn.frame = CGRect(x:self.view.frame.width/2 + 80,y:self.view.frame.height - 115,width: 70,height: 70)
            saveBtn.addTarget(self, action: #selector(savePhoto), for: .touchUpInside)
            view.addSubview(saveBtn)
        }
    }
    //再撮影
    @objc func retryPhoto(sender:UIButton){
        let subViews = view.subviews
        for subView in subViews {
            subView.removeFromSuperview()
        }
        setPicture()
    }
    //カメラロールへの保存
    @objc func savePhoto(sender:UIButton){
        UIImageWriteToSavedPhotosAlbum(tempImage, self, nil, nil)
        let subViews = view.subviews
        for subView in subViews {
            subView.removeFromSuperview()
        }
        setPicture()
    }
    //キャンセル
    @objc func cancelAction(sender:UIButton){
        //
    }
}

extension UIImage {
    func croppingToCenterSquare() -> UIImage {
        let cgImage = self.cgImage!
        var newWidth = CGFloat(cgImage.width)
        var newHeight = CGFloat(cgImage.height)
        if newWidth > newHeight {
            newWidth = newHeight
        } else {
            newHeight = newWidth
        }
        let x = (CGFloat(cgImage.width) - newWidth)/2
        let y = (CGFloat(cgImage.height) - newHeight)/2
        let rect = CGRect(x: x, y: y, width: newWidth, height: newHeight)
        let croppedCGImage = cgImage.cropping(to: rect)!
        return UIImage(cgImage: croppedCGImage, scale: self.scale, orientation: self.imageOrientation)
    }
}

#環境
・Xcode 10.2.1
・Swift 5
・iOS 12.3.1

#参考文献
AVCapturePhotoSettings
#おわりに
Mahalo

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?