うるおいらんど

【Swift】カメラで撮影した画像を用いた時に向きがおかしい時の対策【UIImagePickerController】

追記があります。

UIImagePickerControllerを用いてカメラを起動し、撮影した際に取得した画像からCGImageを取り出すとどうも向きがおかしいことになってしまいます。

縦向きで撮影した写真も、横向きで撮影した写真も縦横の長さが変わらないのです。

横向きで撮影した写真についてはそのままで大丈夫なのですが、縦向きで撮影した写真も横長の写真として認識されてしまうのです(90度回転しているのかな・・・?)

 

一応解決したのでついでにリサイズ・切り抜き処理とともに紹介していきます。

向きがおかしい〜については少し飛ばして下さいな

UIImagePickerControllerを用意する

UIAlertControllerの中に用意してください。iOS7にも対応するには場合わけでUIActionSheetも使用してください。

let pickerController = UIImagePickerController()
pickerController.delegate = self
//これがあると写真撮影後に編集ができる
//pickerController.allowsEditing = true
pickerController.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(pickerController,animated:true,completion:nil)

 

あと、ViewControllerのところにデリゲートを追加するのをお忘れなく!

class ViewController:UIViewController,UIImagePickerControllerDelegate{
  //....
}

 

撮影後に呼び出されるメソッドはimagePickerController:didFinishPickingImage:editingInfoとなります。

(ちょっと調べてみるとこのメソッド随分前にobjective-cでは非推奨になってるとかどうとか・・・でもSwift2.0環境で普通に使用できるし、選択画面に出てくるしどうなんでしょう・・・?)

 

func imagePickerController(picker:UIImagePickerController!, didFinishPickingImage image:UIImage!,editingInfo:[NSObject : AnyObject]!){
        var resizeImage = UIImage()
        resizeImage = resizeCamera(image, width:Int(screenWidth) * 2, height: Int(screenHeight) * 2)
        //適当に用意したUIImageViewにのせています
        mainImageView.image = resizeImage
        self.dismissViewControllerAnimated(true,completion:nil)
}

ここでresizeCameraという関数を作成して画像をリサイズ・切り抜きしていきます。

 

画像をリサイズ・切り抜きする

今回画面サイズにぴったりあうようなサイズで画像を加工していきます。

    func resizeCamera(image: UIImage, width: Int, height: Int) -> UIImage {
        // リサイズ処理
        let origRef    = image.CGImage;
        let origWidth  = Int(CGImageGetWidth(origRef))
        let origHeight = Int(CGImageGetHeight(origRef))
        var resizeWidth:Int = 0, resizeHeight:Int = 0

       if (origWidth < origHeight) {
            resizeWidth = width
            resizeHeight = origHeight * resizeWidth / origWidth
        } else {
            resizeHeight = height
            resizeWidth = origWidth * resizeHeight / origHeight
        }
        let resizeSize = CGSizeMake(CGFloat(resizeWidth), CGFloat(resizeHeight))
        UIGraphicsBeginImageContext(resizeSize)
        
        image.drawInRect(CGRectMake(0, 0, CGFloat(resizeWidth), CGFloat(resizeHeight)))
        
        let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        // 切り抜き処理
        
        let cropRect  = CGRectMake(
            CGFloat((resizeWidth - width) / 2),
            CGFloat((resizeHeight - height) / 2),
            CGFloat(width), CGFloat(height))
        let cropRef   = CGImageCreateWithImageInRect(resizeImage.CGImage, cropRect)
        let cropImage = UIImage(CGImage: cropRef!)
        
        return cropImage
    }

 

そして冒頭の問題です。

縦向きで撮った写真なのに横幅のが広くなっている??

縦向きで撮った写真も横向きで撮った写真もそれぞれ縦横をprintしてみると、どちらも同じになってしまいます。

そういった場合は一度オリジナル画像を描き直してあげるとうまくいきました。

var imageOriginal = image
//UIGraphicsBeginImageContext(imageOriginal.size)
UIGraphicsBeginImageContextWithOptions(imageOriginal.size, false, 0.0)
imageOriginal.drawInRect(CGRectMake(0,0,imageOriginal.size.width,imageOriginal.size.height))
imageOriginal = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

これを先ほどのresizeCameraの最初に入れてあげます。

ちなみにUIGraphicsBeginImageContextとUIGraphicsBeginImageContextWithOptionsですが、前者より後者の方が画質良く取得することができます。

UIGraphicsBeginImageContextWithOptions(サイズ,透過可否,倍率 )となっていて倍率は0にするとデバイスに合わせて自動で設定してくれるそう(1.0にしたままリリースしちゃったゾー・・・笑)

メモリ使用量とも相談して使い分けると良いかもです。

resizeCamera内の最終コード

    func resizeCamera(image: UIImage, width: Int, height: Int) -> UIImage {
        // リサイズ処理
        var imageOriginal = image
        //UIGraphicsBeginImageContext(imageOriginal.size)
        UIGraphicsBeginImageContextWithOptions(imageOriginal.size, false, 0.0)
        imageOriginal.drawInRect(CGRectMake(0,0,imageOriginal.size.width,imageOriginal.size.height))
        imageOriginal = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        let origRef    = imageOriginal.CGImage;
        let origWidth  = Int(CGImageGetWidth(origRef))
        let origHeight = Int(CGImageGetHeight(origRef))
        var resizeWidth:Int = 0, resizeHeight:Int = 0
        
        if (origWidth < origHeight) {
            resizeWidth = width
            resizeHeight = origHeight * resizeWidth / origWidth
        } else {
            resizeHeight = height
            resizeWidth = origWidth * resizeHeight / origHeight
        }
        let resizeSize = CGSizeMake(CGFloat(resizeWidth), CGFloat(resizeHeight))
        UIGraphicsBeginImageContext(resizeSize)
        
        image.drawInRect(CGRectMake(0, 0, CGFloat(resizeWidth), CGFloat(resizeHeight)))
        
        let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        // 切り抜き処理
        
        let cropRect  = CGRectMake(
            CGFloat((resizeWidth - width) / 2),
            CGFloat((resizeHeight - height) / 2),
            CGFloat(width), CGFloat(height))
        let cropRef   = CGImageCreateWithImageInRect(resizeImage.CGImage, cropRect)
        let cropImage = UIImage(CGImage: cropRef!)
        
        return cropImage
    }

 

こんな感じで取得できました。

実際縦長写真がちょっとうまく縮小できてない気もします。画面サイズ比率にするなら、横幅を合わせた時に画面サイズより縦が短いか長いかの判断も必要ということですかね・・?

 

 

参考リンク

Additional Notes追記

Swift4に対応しました!

こんな感じで!はい!

extensionにしたので使う時は

let resizeImage = image.resize(size:CGSize(width:50,height:50))

みたいにして使えます。

めちゃくちゃよく使ってます。

Comments

コメントはありません。

現在コメントフォームは工事中です。