質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Swift

    7479questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4089questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

swiftでAVCaptureVideoDataOutputを使って位置情報付きの写真を撮影、保存したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 787

natting

score 2

前提・実現したいこと

xcode8.3 swiftでカメララプリを作っています。
AVCaptureVideoDataOutputで位置情報付きの写真が撮れるアプリを作るのが目標。
現在地の取得は後で付け足すとして、
http://qiita.com/oggata/items/0e35195b983187dfb7f9
http://qiita.com/swdyh/items/60d97e74058a93448a19
や書籍を参考に、exif情報つきの写真を撮れるようにしようとしています。

発生している問題・エラーメッセージ

とりあえずコンパイルして実機で動くようになりましたが、
写真は撮れても肝心のexif情報が入っていません。
ALAssetLibraryが廃止になったこともあり、参考になる情報が見つからず途方に暮れています。
位置情報付きの写真をフォトライブラリに保存する方法がわかる方、ご教授いただけたら幸いです。

エラーメッセージ

該当のソースコード

//
//  ViewController.swift
//  locationCam
//
//  Created by shinpei on 2017/06/03.
//  Copyright © 2017年 shinpei. All rights reserved.
//

import UIKit
import AVFoundation
import ImageIO
import Photos
import MobileCoreServices

class ViewController: UIViewController,AVCaptureVideoDataOutputSampleBufferDelegate {

    //プレビューを表示するview
    @IBOutlet weak var previewView: UIView!

    var input = AVCaptureDeviceInput()//入力デバイス
    var output = AVCaptureVideoDataOutput()//出力データ
    var session = AVCaptureSession()//AVCaptureのセッション開始状態
    var camera:AVCaptureDevice!//使うカメラ
    var stillImage:CGImage!

    //exif情報を準備する
    var gps = NSMutableDictionary()
    var exif = NSMutableDictionary()
    var meta = NSMutableDictionary()

    //シャッター
    @IBAction func takePhoto(_ sender: Any) {
        if var _:AVCaptureConnection? = output.connection(withMediaType: AVMediaTypeVideo){
            //UIImageWriteToSavedPhotosAlbum(self.stillImage, self, nil, nil)
            let tmpName = ProcessInfo.processInfo.globallyUniqueString
            let tmpUrl = NSURL.fileURL(withPath: NSTemporaryDirectory() + tmpName + ".jpg")
            if let dest = CGImageDestinationCreateWithURL(tmpUrl as CFURL, kUTTypeJPEG, 1, nil) {
                CGImageDestinationAddImage(dest, stillImage, meta)
                CGImageDestinationFinalize(dest)
                PHPhotoLibrary.shared()
                    .performChanges({ PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: tmpUrl) }
                )
            }
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        cameraSetup()
        previewSetup()
        exifSetup()
    }

    //カメラのセットアップ(入力、出力)
    func cameraSetup (){
        //ビデオ出力の解像度
        session.sessionPreset = AVCaptureSessionPresetHigh
        //どのカメラを使うか決める
        camera = AVCaptureDevice.defaultDevice(withDeviceType: AVCaptureDeviceType.builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
        //入力をセッションに追加
        do {
            //inputにカメラのデバイス情報を入れてみてうまくいったら
            //セッションにinputを追加する
            input = try AVCaptureDeviceInput(device: camera) as AVCaptureDeviceInput
            if(session.canAddInput(input)){
                session.addInput(input)
            } else {
                print("入力エラー")
                return
            }
        } catch let error as NSError {
            print(error)
            return
        }

        //出力設定
        //先にセッションに出力を追加?
        if(session.canAddOutput(output)){
            session.addOutput(output)
        } else {
            print("出力エラー")
            return
        }
        //ピクセルフォーマット
        output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable : Int(kCVPixelFormatType_32BGRA)]
        //フレームをキャプチャするためのサブスレッッド用のシリアルキューを用意?
        output.setSampleBufferDelegate(self, queue: DispatchQueue.main)
        output.alwaysDiscardsLateVideoFrames = true

        //セッションの開始
        session.startRunning()

        //deviceをロックして設定?意味わからん
        do {
            try camera.lockForConfiguration()
            camera.activeVideoMinFrameDuration = CMTimeMake(1, 30)
            camera.unlockForConfiguration()
        } catch _ {
        }
    }

    //プレビューを表示
    func previewSetup(){
        let previewLayer = AVCaptureVideoPreviewLayer(session: session)
        guard let videoLayer = previewLayer else {
            print("プレビュー不可")
            return
        }
        videoLayer.frame = view.bounds
        videoLayer.masksToBounds = true
        videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

        previewView.layer.addSublayer(videoLayer)
    }

    //AVCaptureVideoDataOutputSampleBufferDelegateで宣言されてるfunc
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        let image:UIImage = self.captureImage(sampleBuffer)
        stillImage = image.cgImage

    }

    //画像の設定?
    func captureImage(_ sampleBuffer:CMSampleBuffer) -> UIImage{
        let imageBuffer:CVImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))
        let baseAddress:UnsafeMutableRawPointer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)!
        let bytesPerRow:Int = CVPixelBufferGetBytesPerRow(imageBuffer)
        let width:Int = CVPixelBufferGetWidth(imageBuffer)
        let height:Int = CVPixelBufferGetHeight(imageBuffer)

        //色空間
        let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()

        //let bitsPerCompornent:Int = 8
        //swift 2.0
        let newContext:CGContext = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue|CGBitmapInfo.byteOrder32Little.rawValue)!

        let imageRef:CGImage = newContext.makeImage()!
        let resultImage = UIImage(cgImage: imageRef, scale: 1.0, orientation: UIImageOrientation.up)

        return resultImage
    }

    func exifSetup(){
        //ハワイの位置情報?
        gps.setObject(1111,forKey:kCGImagePropertyGPSDateStamp as! NSCopying)
        gps.setObject(1111,forKey:kCGImagePropertyGPSTimeStamp as! NSCopying)
        gps.setObject("N",forKey:kCGImagePropertyGPSLatitudeRef as! NSCopying)
        gps.setObject(21.275468,forKey:kCGImagePropertyGPSLatitude as! NSCopying)
        gps.setObject("W",forKey:kCGImagePropertyGPSLongitudeRef as! NSCopying)
        gps.setObject(157.825294,forKey:kCGImagePropertyGPSLongitude as! NSCopying)
        gps.setObject(0,forKey:kCGImagePropertyGPSAltitudeRef as! NSCopying)
        gps.setObject(0,forKey:kCGImagePropertyGPSAltitude as! NSCopying)

        exif.setObject("test", forKey: kCGImagePropertyExifUserComment as! NSCopying)
        exif.setObject(gps, forKey: kCGImagePropertyGPSDictionary as! NSCopying)

        meta.setObject(exif,forKey:kCGImagePropertyExifDictionary as! NSCopying)
    }

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

補足情報(言語/FW/ツール等のバージョンなど)

xcode8.3.2
swift
iPhone7Plus実機でテスト

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

        exif.setObject("test", forKey: kCGImagePropertyExifUserComment as! NSCopying)
        exif.setObject(gps, forKey: kCGImagePropertyGPSDictionary as! NSCopying)

        meta.setObject(exif,forKey:kCGImagePropertyExifDictionary as! NSCopying)


を下記に書き換えたら解決しました。

        exif.setObject("test", forKey: kCGImagePropertyExifUserComment as! NSCopying)

        meta.setObject(exif,forKey:kCGImagePropertyExifDictionary as! NSCopying)
        meta.setObject(gps, forKey: kCGImagePropertyGPSDictionary as! NSCopying)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

同じタグがついた質問を見る

  • Swift

    7479questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4089questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。