Help us understand the problem. What is going on with this article?

UIImageの加工について

More than 3 years have passed since last update.

iOS その3 Advent Calendar

2日目を書かせていただきます!

今年は何記事書けるのかな...。

iOSということでSwiftのことではなくUIKit周りのことを書ければと思います。

といことで早速本題です。

UIImageの加工

先日作成したアプリで(S3とかにある)画像をたくさん並べる処理をして、案の定スクロールがカクツク問題にぶち当たりました。

その際に色々試したUIImageの加工について紹介します。

紹介する処理

  • リサイズ
    • 比率を保たない
    • 比率を保つ
  • 角丸
  • ボーダー

あたりを紹介できればと思います。

リサイズ

UIImage+resize.swift
extension UIImage {

    // 比率保つ版
    func resize(_ size: CGSize) -> UIImage? {
        let widthRatio = size.width / self.size.width
        let heightRatio = size.height / self.size.height
        let ratio = (widthRatio < heightRatio) ? widthRatio : heightRatio
        let resizedWidth = round(self.size.width * ratio)
        let resizedHeight = round(self.size.height * ratio)
        let resizedSize = CGSize(width: resizedWidth, height: resizedHeight)
        UIGraphicsBeginImageContextWithOptions(resizedSize, false, UIScreen.mainScreen().scale)
        let drawRect = CGRect(origin: CGPointZero, size: resizedSize)
        drawInRect(drawRect)
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resizedImage
    }

    // 比率保たない版
    func resize(_ size: CGSize) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale)
        let drawRect = CGRect(origin: CGPointZero, size: resizedSize)
        drawInRect(drawRect)
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resizedImage
    }
}

注意点は特にありません...。

角丸

UIImage+maskCorner.swift
extension UIImage {
    func maskCorner(radius r: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.mainScreen().scale)

        let rect = CGRect(origin: CGPointZero, size: self.size)
        UIBezierPath(roundedRect: rect, cornerRadius: r).addClip()
        drawInRect(rect)
        let clippedImage = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()
        return clippedImage
    }
}

注意点は特にありません...。

ボーダー

UIImage+drawBorder.swift
extension UIImage {

    func drawBorder(width borderWidth: CGFloat, color: UIColor) -> UIImage? {

        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale)

        // clip corner
        let rect = CGRect(origin: CGPointZero, size: self.size)

        let context = UIGraphicsGetCurrentContext()
        CGContextSaveGState(context!)

        drawInRect(rect)
        CGContextRestoreGState(context!)

        let insetRect = CGRectInset(rect, borderWidth / 2.0, borderWidth / 2.0)
        let path = UIBezierPath(rect: insetRect)
        color.setStroke()
        path.lineWidth = borderWidth

        path.stroke()

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

}

補足

ちなみにこのUIImageの加工の処理メインスレッド以外でも実行できます。

なのでUICollectionViewCellなどでSDWebImageと一緒に使う場合はダウンロード処理が終わった後Cellのサイズに合わせてリサイズした後に表示処理をするとスクロールの邪魔もしづらくなります。(個人の体感ですが...)

終わりに

UICollectionViewCelllayerをいじるよりだいぶ邪魔しないで済む方法になるかと思います。

ただ、もしできることならS3などの画像をリクエストでリサイズできるようお願いするともっと幸せになれるかもしれないです。

以上になります。

ryokosuge
金髪iOS エンジニア なんか色々やってます
https://ryokosuge.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away