Entertainer Engineering

人を楽しませられる技術者を目指すあおかびんのブログ

Swiftでカメラロールから写真データを保存する話

おはようございます。あおかび (ん)です。

この間やっとアプリケーション作りがひと段落したので、
その間に学んだことをずらずらっと書いていこうと思っております。

今回はSwiftを使ってカメラロールから写真データを引っ張ってくる方法を書いていきたいと思います。

ボタンを一つ置いて、そのボタンがクリックされたらカメラロールにアクセス、
その画像をローカルデータとして保存しておくところまでやっておきたいと思います。
DBの部分は今回は割愛します。


1.ボタンを配置して、カメラロールにアクセス
ViewController.swiftにまず、AssetsLibraryをimportした後、
UIViewControllerに加えてUIImagePickerControllerDelegateとUINavigationControllerDelegateを継承(?)しましょう。

/* ViewController.swift */
import UIKit
import AssetsLibrary

class testViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

つづいてviewDidLoadメソッドにてボタンを配置、アクションは今回はaccessCamerarollとしました。

    override func viewDidLoad() {
        self.view.backgroundColor = UIColor.whiteColor()
        super.viewDidLoad()
        
        let button: UIButton = UIButton()
        button.frame = CGRectMake(100, 100, 100, 100)
        button.setTitle("Access!", forState: UIControlState.Normal)
        button.backgroundColor = UIColor.blueColor()
        button.addTarget(self, action: Selector("accessCameraroll:"), forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(button)
    }

そのaccessCamerarollメソッドは次のようになっています。

    // カメラロールから写真を選ぶためのメソッド
    func accessCameraroll(button: UIButton) {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
            let controller = UIImagePickerController()
            controller.delegate = self
            controller.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
            self.presentViewController(controller, animated: true, completion: nil)
        }
    }

ここまででとりあえずカメラロールにアクセスすることはできました!
次はカメラロールから選択した写真を保存しましょう。

2.選択した写真をローカルストレージに保存
写真を選択した時に呼ばれるメソッド

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
    }

というメソッドがあります。この関数内で、選択した画像を保存していきましょう。

    // 写真を選択した時に呼ばれるメソッド
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
        if info[UIImagePickerControllerOriginalImage] != nil {
            let image: UIImage? = info[UIImagePickerControllerOriginalImage] as! UIImage?
            let pictURL: NSURL = info[UIImagePickerControllerReferenceURL] as! NSURL
            var library: ALAssetsLibrary = ALAssetsLibrary()
            var data: NSData?
            
            let sema: dispatch_semaphore_t = dispatch_semaphore_create(0)
            let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
            
            var getImage: UIImage?
            
            dispatch_async(queue, {() -> Void in
                library.assetForURL(pictURL, resultBlock: {(asset: ALAsset!) -> Void in
                    let representation: ALAssetRepresentation? = asset.defaultRepresentation()
                    getImage = UIImage(CGImage: representation!.fullResolutionImage().takeUnretainedValue())!
                    data = UIImagePNGRepresentation(getImage!)
                    dispatch_semaphore_signal(sema)
                    }, failureBlock: {(error: NSError!) -> Void in
                        println(error)
                        dispatch_semaphore_signal(sema);
                })
            })
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            
            saveImage(data!)
        }
        picker.dismissViewControllerAnimated(true, completion: nil)
        let mainViewController: MainViewController = MainViewController()
        self.navigationController?.pushViewController(mainViewController, animated: true)
    }

    // 画像をローカルストレージに保存するメソッド
    func saveImage(data: NSData) {
        let dataPath = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as! Array<String>).first!.stringByAppendingPathComponent("test.jpg")
        var fileManager: NSFileManager = NSFileManager()
        data.writeToFile(dataPath, atomically: true)
    }

これで画像が保存されたはずです。

最初はAVFoundationとか使ってカメラにアクセスしたりしてたんですが、なんかうまくいかなかったですね...

コーディング能力、プログラミング能力の両方がこのままではやばい気がするよなー
勉強頑張っていきます。ありがとうございました、かびでした。。。


P.S.

コードの全容

import UIKit
import AssetsLibrary

class testViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    override func viewDidLoad() {
        self.view.backgroundColor = UIColor.whiteColor()
        super.viewDidLoad()
        
        let button: UIButton = UIButton()
        button.frame = CGRectMake(100, 100, 100, 100)
        button.setTitle("Access!", forState: UIControlState.Normal)
        button.backgroundColor = UIColor.blueColor()
        button.addTarget(self, action: Selector("accessCameraroll:"), forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(button)
        
    }
    
    // カメラロールから写真を選ぶためのメソッド
    func accessCameraroll(button: UIButton) {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
            let controller = UIImagePickerController()
            controller.delegate = self
            controller.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
            self.presentViewController(controller, animated: true, completion: nil)
        }
    }
    
    // 写真を選択した時に呼ばれるメソッド
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
        if info[UIImagePickerControllerOriginalImage] != nil {
            let image: UIImage? = info[UIImagePickerControllerOriginalImage] as! UIImage?
            let pictURL: NSURL = info[UIImagePickerControllerReferenceURL] as! NSURL
            var library: ALAssetsLibrary = ALAssetsLibrary()
            var data: NSData?
            
            let sema: dispatch_semaphore_t = dispatch_semaphore_create(0)
            let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
            
            var getImage: UIImage?
            
            dispatch_async(queue, {() -> Void in
                library.assetForURL(pictURL, resultBlock: {(asset: ALAsset!) -> Void in
                    let representation: ALAssetRepresentation? = asset.defaultRepresentation()
                    getImage = UIImage(CGImage: representation!.fullResolutionImage().takeUnretainedValue())!
                    data = UIImagePNGRepresentation(getImage!)
                    dispatch_semaphore_signal(sema)
                    }, failureBlock: {(error: NSError!) -> Void in
                        println(error)
                        dispatch_semaphore_signal(sema);
                })
            })
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            
            saveImage(data!)
        }
        picker.dismissViewControllerAnimated(true, completion: nil)
        let mainViewController: MainViewController = MainViewController()
        self.navigationController?.pushViewController(mainViewController, animated: true)
    }
    
    // 画像をローカルストレージに保存するメソッド
    func saveImage(data: NSData) {
        let dataPath = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as! Array<String>).first!.stringByAppendingPathComponent("test.jpg")
        var fileManager: NSFileManager = NSFileManager()
        data.writeToFile(dataPath, atomically: true)
    }
    

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}