Swift2 stillImageStabilizationSupported(手ぶれ補正対応)の確認の仕方

カメラアプリを作る時、手ぶれ補正対応をする為にstillImageStabilizationSupportedがTrueになる事を確認する必要があるのですが、対応機種(iPhone6sPlus)でもTrueにならなかったので調べた事をメモします。

NGパターン

// 手ぶれ補正
if myImageOutput.stillImageStabilizationSupported == true {
    myImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable = true
}

// セッションをOutputに追加.
mySession.addOutput(myImageOutput)

OKパターン

// セッションをOutputに追加.
mySession.addOutput(myImageOutput)

// 手ぶれ補正
if myImageOutput.stillImageStabilizationSupported == true {
    myImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable = true
}

セッションをaddOutputした後じゃないとstillImageStabilizationSupportedを確認することは出来ないという事でした。

参考URL

stackoverflow.com

Swift2 Exif Declaration Keys を調べてみた

カメラアプリを作成する時にmetadataを設定しただけでは、標準カメラと比べるとExif情報が足りない。そこで撮影後に取得出来るExifの初期設定項目を調べてみた。撮影はフラッシュなし。

CGImageProperties Reference

Constants - EXIF Dictionary Keys より

○は設定値あり。×は設定値なし。空欄は項目なし。

Declaration 意味 有無
kCGImagePropertyExifExposureTime 露光時間
kCGImagePropertyExifFNumber Fナンバー
kCGImagePropertyExifExposureProgram 露出プログラム
kCGImagePropertyExifSpectralSensitivity スペクトル感度
kCGImagePropertyExifISOSpeedRatings ISO感度の評価 ×
kCGImagePropertyExifOECF OECF
kCGImagePropertyExifVersion バージョン
kCGImagePropertyExifDateTimeOriginal オリジナル日時
kCGImagePropertyExifDateTimeDigitized DateTimeのデジタル化
kCGImagePropertyExifComponentsConfiguration コンポーネントの構成
kCGImagePropertyExifCompressedBitsPerPixel ピクセルあたりの圧縮ビット
kCGImagePropertyExifShutterSpeedValue スピード値のシャッター
kCGImagePropertyExifApertureValue 絞り値
kCGImagePropertyExifBrightnessValue 輝度値
kCGImagePropertyExifExposureBiasValue 露出バイアス値
kCGImagePropertyExifMaxApertureValue 最大絞り値
kCGImagePropertyExifSubjectDistance 被写体距離
kCGImagePropertyExifMeteringMode 測光モード
kCGImagePropertyExifLightSource 光源
kCGImagePropertyExifFlash フラッシュ
kCGImagePropertyExifFocalLength 焦点距離
kCGImagePropertyExifSubjectArea 被写体領域SubjectArea
kCGImagePropertyExifMakerNote メーカーノート
kCGImagePropertyExifUserComment ユーザーコメント
kCGImagePropertyExifSubsecTime Subsec時間
kCGImagePropertyExifSubsecTimeOrginal Subsec時間Orginal
kCGImagePropertyExifSubsecTimeDigitized Subsec時間デジタル化
kCGImagePropertyExifFlashPixVersion フラッシュピックスバージョン
kCGImagePropertyExifColorSpace カラースペース
kCGImagePropertyExifPixelXDimension ピクセルX寸法
kCGImagePropertyExifPixelYDimension ピクセルY寸法
kCGImagePropertyExifRelatedSoundFile 関連サウンドファイル
kCGImagePropertyExifFlashEnergy フラッシュエネルギー
kCGImagePropertyExifSpatialFrequencyResponse 空間周波数応答
kCGImagePropertyExifFocalPlaneXResolution 焦点面X解像度
kCGImagePropertyExifFocalPlaneYResolution 焦点面Y解像度
kCGImagePropertyExifFocalPlaneResolutionUnit 焦点面解像度単位
kCGImagePropertyExifSubjectLocation 件名場所
kCGImagePropertyExifExposureIndex 露出インデックス
kCGImagePropertyExifSensingMethod 検知方法
kCGImagePropertyExifFileSource ファイルソース
kCGImagePropertyExifSceneType シーンタイプ
kCGImagePropertyExifCFAPattern CFAパターン
kCGImagePropertyExifCustomRendered カスタムレンダリング
kCGImagePropertyExifExposureMode 露出モード
kCGImagePropertyExifWhiteBalance ホワイトバランス
kCGImagePropertyExifDigitalZoomRatio デジタルズーム倍率
kCGImagePropertyExifFocalLenIn35mmFilm 35mmフィルムで焦点レン
kCGImagePropertyExifSceneCaptureType 撮影シーンタイプ
kCGImagePropertyExifGainControl ゲインコントロール
kCGImagePropertyExifContrast コントラスト
kCGImagePropertyExifSaturation 飽和
kCGImagePropertyExifSharpness シャープネス
kCGImagePropertyExifDeviceSettingDescription 設定説明デバイス
kCGImagePropertyExifSubjectDistRange 件名ディストレンジ
kCGImagePropertyExifImageUniqueID 画像ユニークID
kCGImagePropertyExifGamma ガンマ
kCGImagePropertyExifCameraOwnerName カメラの所有者名
kCGImagePropertyExifBodySerialNumber ボディのシリアル番号
kCGImagePropertyExifLensSpecification レンズ仕様
kCGImagePropertyExifLensMake レンズメイク
kCGImagePropertyExifLensModel レンズモデル
kCGImagePropertyExifLensSerialNumber レンズのシリアル番号

またメーカー名、モデル名、ソフトウェア名、撮影日、作成日はDeclaration Keys使わない方法があると思っている。次はそれを調べたい。

Swift2.1 Camera Application Demo

Swift2.1でAVFoundationを使って最高画質で撮影できるサンプルを作ってみました。 ググれば沢山出てくるのですがSwiftのバージョンが古いものばかりで苦労したのでメモ替わりに記事にしておきます。

import UIKit
import AVFoundation


class ViewController: UIViewController {

    var deviceInput:AVCaptureDeviceInput!
    var stillImageOutput: AVCaptureStillImageOutput!
    var session: AVCaptureSession!
    var captureSession: AVCaptureSession!
    var videoconnection: AVCaptureConnection!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let notificationCenter = NSNotificationCenter.defaultCenter()
        
        //アプリがアクティブになったとき
        notificationCenter.addObserver(
            self,
            selector: "avCamera",
            name:UIApplicationDidBecomeActiveNotification,
            object: nil)
        
    }
    
    func avCamera() -> Bool {
        // init camera device
        var captureDevice: AVCaptureDevice?
        let devices: NSArray = AVCaptureDevice.devices()
        
        // find back camera
        for device: AnyObject in devices {
            if device.position == AVCaptureDevicePosition.Back {
                captureDevice = device as? AVCaptureDevice
            }
        }
        
        if captureDevice == nil {
            return false
        }
        
        // init device input
        do {
            deviceInput = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput
        } catch let error as NSError {
            print(error)
        }
        
        self.stillImageOutput = AVCaptureStillImageOutput()
        
        // init session
        self.session = AVCaptureSession()
        self.session.sessionPreset = AVCaptureSessionPresetPhoto // 最高画質に設定
        self.session.addInput(deviceInput as AVCaptureInput)
        self.session.addOutput(self.stillImageOutput)
        
        // layer for preview
        let previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
        previewLayer.frame = self.view.bounds
        self.view.layer.addSublayer(previewLayer)
        
        self.session.startRunning()
        
        // UIボタンを作成.
        let myButton = UIButton(frame: CGRectMake(0,0,120,50))
        myButton.backgroundColor = UIColor.redColor();
        myButton.layer.masksToBounds = true
        myButton.setTitle("Shutter", forState: .Normal)
        myButton.layer.cornerRadius = 20.0
        myButton.layer.position = CGPoint(x: self.view.bounds.width/2, y:self.view.bounds.height-50)
        myButton.addTarget(self, action: "takePhoto:", forControlEvents: .TouchUpInside)
        
        // UIボタンをViewに追加.
        self.view.addSubview(myButton);

        return true
    }

    func takePhoto(sender: UIButton){
        // ビデオ出力に接続.
        let myVideoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo)
        
        // 接続から画像を取得.
        self.stillImageOutput.captureStillImageAsynchronouslyFromConnection(
            myVideoConnection, completionHandler: {
            
                (imageDataBuffer, error) -> Void in
                
                // 取得したImageのDataBufferをJpegに変換.
                let myImageData : NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)
                
                // JpegからUIIMageを作成.
                let myImage : UIImage = UIImage(data: myImageData)!
                
                // アルバムに追加.
                UIImageWriteToSavedPhotosAlbum(myImage, self, nil, nil)
            }
        )
    }

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

}

Scala + Play2.4 anormの設定

Play2.3まではbuild.sbtでAnormを設定するには下記のように記述してましたが  

libraryDependencies ++= Seq(
  jdbc,
  anorm
)

Play2.4からは下記のように記述するようになった。

libraryDependencies ++= Seq(
  jdbc,
  "com.typesafe.play" %% "anorm" % "2.4.0"
)

Could not find a suitable constructor in 〜 エラーの対処方法

環境:ScalaIDE(eclipse4.2) + Scala + Play2.4

下記エラーが出た時の対処方法

1) Could not find a suitable constructor in controllers.UserController. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
  at controllers.UserController.class(UserController.scala:11)
  while locating controllers.UserController
    for parameter 5 at router.Routes.<init>(Routes.scala:43)
  while locating router.Routes
  while locating play.api.inject.RoutesProvider
  while locating play.api.routing.Router

eclipse上で.scalaファイルを開き*マークが付いてるファイルが無いか探す。

あった場合、下記リンク参照して全てのファイルを消すとエラーが無くなる。

英語版の場合、フォルダ上で右クリックして「Team」→「Apply Patch...」

対象ファイルを選択して「Finish」する。

f:id:mani023:20151019163218p:plain

hack.aipo.com

以上。

OSX EI Capitan + Node.js

Scala + Play2.4 の勉強しているのですがターミナルに下記の警告が出てしまう。

Warning: node.js detection failed, sbt will use the Rhino based Trireme JavaScript engine instead to run JavaScript assets compilation, which in some cases may be orders of magnitude slower than using node.js.

対処方法は下記リンクにあるけど、

stackoverflow.com

ターミナルで「brew install node」をすると

Warning: You are using OS X 10.11.
We do not provide support for this pre-release version.
You may encounter build failures or other breakage.

Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.

Error: Failure while executing: /usr/bin/otool -L /usr/bin/install_name_tool

となりエラーになる。

OSX EI CapitanのNode.jsはまだ未対応のようだ。

 

追記:2015/10/18

coolestguidesontheplanet.com

brewを使わないでパッケージからインストールすれば警告無くなった。