UIImageの加工について

## iOS その３ Advent Calendar

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

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

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

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

## UIImageの加工

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

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

## 紹介する処理

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

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

## リサイズ

```swift: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
    }
}
```

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

## 角丸

```swift: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
    }
}
```

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

## ボーダー

```swift: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のサイズに合わせてリサイズした後に表示処理をするとスクロールの邪魔もしづらくなります。（個人の体感ですが...)

## 終わりに

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

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

以上になります。