LoginSignup
128
93

More than 5 years have passed since last update.

UIImageのリサイズ方法と注意点

Last updated at Posted at 2017-03-07

はじめに

UIImageをリサイズしたいと思い、とりあえず「UIImage resize」とググってみたのですが、サンプルコードを動作させると思わぬ落とし穴にハマったので、備忘録として書き残しておきます。

画像が粗くなる(画像が劣化する)!?

だいたい検索すると出てくるサンプルコードはこんな感じです。(Swift3.0に書き直してます)

extension UIImage {
    func resize(size _size: CGSize) -> UIImage? {
        let widthRatio = _size.width / size.width
        let heightRatio = _size.height / size.height
        let ratio = widthRatio < heightRatio ? widthRatio : heightRatio

        let resizedSize = CGSize(width: size.width * ratio, height: size.height * ratio)

        UIGraphicsBeginImageContext(resizedSize)
        draw(in: CGRect(origin: .zero, size: resizedSize))
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return resizedImage
    }
}

これを実行すると、画像自体は希望のサイズにリサイズされたように見えますが、実際表示してみるとなんだか画像が粗い!?

原因はUIGraphicsBeginImageContext()

原因はUIGraphicsBeginImageContext(resizedSize)でした。
これを用いて実行すると、Retinaディスプレイのscaleの設定が無視され、事実上のpixelサイズで扱われてリサイズ処理がされてしまいます。
つまり1xの画像として書き出されてしまうということでした。

これで解決

ということでUIGraphicsBeginImageContext(_ size: CGSize)のかわりに、
UIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat)を使いましょう。

こちらを用いるとscaleが引数として設定されているので、Retinaディスプレイの場合も対象となるscaleを設定することで2x, 3xのような画像に対応することができます。
先ほどのコードを書き直してみます。

extension UIImage {
    func resize(size _size: CGSize) -> UIImage? {
        let widthRatio = _size.width / size.width
        let heightRatio = _size.height / size.height
        let ratio = widthRatio < heightRatio ? widthRatio : heightRatio

        let resizedSize = CGSize(width: size.width * ratio, height: size.height * ratio)

        UIGraphicsBeginImageContextWithOptions(resizedSize, false, 0.0) // 変更
        draw(in: CGRect(origin: .zero, size: resizedSize))
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return resizedImage
    }
}

UIGraphicsBeginImageContextWithOptions()の第二引数のopaqueは不透明かどうかなので、画像の不透明が保証されてる場合はtrueに指定した方がパフォーマンスがよくなるようです。
第三引数のscaleには0.0を入れておりますが、0.0を指定するとmainScreenのscaleを動的に設定してくれるので、4.7inchや5.5inchにてUIScreen.main.scaleをみて出し分ける必要はありません!

まとめ

UIImageのリサイズ処理を検索すると結構古い記事がヒットしてしまい、UIGraphicsBeginImageContext()を使っている記事を参照しやすいので、現在の環境ではUIGraphicsBeginImageContextWithOptions()を使っていきましょう。

参考

128
93
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
128
93