【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
    }

 

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

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

 

 

2018/04/14追記 Swift4に対応しました!
こんな感じで!はい!


extensionにしたので使う時は
let resizeImage = image.resize(size:CGSize(width:50,height:50))
みたいにして使えます。 めちゃくちゃよく使ってます。
コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS
more