Swift

[Swift] iPhoneの写真をAPIにPOSTする際の、上下反転問題とファイルサイズ制限への対策

概要

iPhoneで撮影した写真を画像解析のWeb APIにPOSTするケースで、以下のような課題に直面しました。

課題1
iPhoneで撮影した写真は、iPhoneやMac上で見ると正常に見えますが、他の環境で見ると上下反転していることがあります。
APIの解析処理が正常動作しないため、上下反転を補正してからPOSTする必要が生じました。

課題2
APIの仕様上、「POSTする画像は○MB以下」というようなファイルサイズ制限がありました。
ファイルサイズを判定し、制限以下に圧縮する必要が生じました。

以下のようなExtensionを作って、これらの課題をクリアしました。

環境

Item Version
Xcode 8.3
Swift 3.1

UIImage Extension

Swift
extension UIImage {

    /// 上下逆になった画像を反転する
    func fixedOrientation() -> UIImage? {
        if self.imageOrientation == UIImageOrientation.up {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(self.size, false, scale)
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
            return nil
        }
        UIGraphicsEndImageContext()
        return newImage
    }

    /// イメージ縮小
    func resizeImage(maxSize: Int) -> UIImage? {

        guard let jpg = UIImageJPEGRepresentation(self, 1) as NSData? else {
            return nil
        }
        if isLessThanMaxByte(data: jpg, maxDataByte: maxSize) {
            return self
        }
        // 80%に圧縮
        let _size: CGSize = CGSize(width: (self.size.width * 0.8), height: (self.size.height * 0.8))
        UIGraphicsBeginImageContext(_size)
        self.draw(in: CGRect(x: 0, y: 0, width: _size.width, height: _size.height))
        guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
            return nil
        }
        UIGraphicsEndImageContext()
        // 再帰処理
        return newImage.resizeImage(maxSize: maxSize)
    }

    /// 最大容量チェック
    func isLessThanMaxByte(data: NSData?, maxDataByte: Int) -> Bool {

        if maxDataByte <= 0 {
            // 最大容量の指定が無い場合はOK扱い
            return true
        }
        guard let data = data else {
            fatalError("Data unwrap error")
        }
        if data.length < maxDataByte {
            // 最大容量未満:OK ※以下でも良いがバッファを取ることにした
            return true
        }
        // 最大容量以上:NG
        return false
    }
}

Usage

Swift
let image = UIImage(named: "Donald_Trump.jpg")
// 上下反転を補正しつつ4MB未満にする
let arrangedImage = image?.fixedOrientation()?.resizeImage(maxSize: 4194304)

参考リンク

iPhoneで撮影した画像の上下左右バラバラ問題
最大容量/最大サイズを指定してUIImageをNSDataに変換する