読者です 読者をやめる 読者になる 読者になる

【swift】アルバムから選択した画像をリサイズしてサーバーにアップロードする

はじめに

今回作ってみたサンプルのイメージはこんなかんじです。
使ったライブラリやキーワードとしては以下です
・Photos(アルバムへのアクセス)
・CoreImage(画像のリサイズ)
・Net(ファイルアップロードでMulti-Partリクエスト)
・SVProgressHUD(アップロード中アイコン)


1. 「アルバムを開く」ボタンをおすと端末のアルバムを開きます

2. そこから選択された画像を画面にセットします

3. で、アップロードボタンを押されたらサーバへアップロードします

アルバムへのアクセス

UIViewControllerに、アルバムを開く処理とアルバムから画像を選択後に戻ったときの処理を実装します

import UIKit
import Photos // ★追加

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { // ★デリゲートを2つ追加します

・・・

    // 「アルバムを開く」ボタン
    func onButtonAlbumOpen(sender: UIButton) {
        var ipc: UIImagePickerController = UIImagePickerController();
        ipc.delegate = self
        UIImagePickerControllerSourceType.PhotoLibrary
        self.presentViewController(ipc, animated:true, completion:nil)
    }

    // 画像が選択されたときによばれます
    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
        // アルバム画面を閉じます
        picker.dismissViewControllerAnimated(true, completion: nil);

        // 画像をリサイズしてUIImageViewにセット
        var resizeImage = resize(image, width: 480, height: 320)
        self.image = resizeImage
        imageView.image = resizeImage
        self.message?.hidden = true
    }
}

画像のリサイズ

iPhoneのカメラでとった写真はサイズが大きいの必要があればアプリ側で画像をリサイズしてからアップロードするなどの処理を実装します。
今回はサイズは適当です。画像が選択されたときにリサイズすること形にしました

// 画像をリサイズ
func resize(image: UIImage, width: Int, height: Int) -> UIImage {
    var imageRef: CGImageRef = image.CGImage
    var sourceWidth: Int = CGImageGetWidth(imageRef)
    var sourceHeight: Int = CGImageGetHeight(imageRef)

    var size: CGSize = CGSize(width: width, height: height)
    UIGraphicsBeginImageContext(size)
    image.drawInRect(CGRectMake(0, 0, size.width, size.height))

    var resizeImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return resizeImage
}

ファイルのアップロード(+読込中のアイコン)

これは外部のライブラリで「Net」と「SVProgressHUD」を使ってみました。

「Net」を使ったのはHTMLでいえば以下の形のもの送信したかったのですが、調べてたらこのライブラリ以外見つけられなかったのでこれを使いました。
他はHTTPリクエストを各々で実装するような形になるんですかね、、、

<form method="post" action="http://example.com/upload" enctype="multipart/form-data">
    <input type="file" name="file"></p>
    <input type="submit" value="送信"></p>
</form>

また、「SVProgressHUD」はアップロード中の処理中にくるくるまわるよくあるやつです。

// ファイルアップロード
func onButtonImageUpload(sender: UIButton) {
    if image != nil {
        var net: Net = Net()
        var url: String = "http://example.com/upload"
        var params: Dictionary<String,AnyObject> = [
            "id": "1",
            "file": NetData(jpegImage: image!, compressionQuanlity: 1, filename: "file")
        ]

        SVProgressHUD.showWithStatus("アップロード中")
        net.POST(url, params: params, successHandler: {
            responseData in
            // 成功
            let result = responseData.json(error: nil)
            if let status = result?["status"] as? String {
                if status == "OK" {
                    SVProgressHUD.dismiss()
                    self.message?.hidden = false
                    self.imageView.image = nil
                    self.imageView.layer.sublayers = nil
                    self.imageView.setNeedsDisplay()
                } else {
                    SVProgressHUD.showErrorWithStatus("アップロードに失敗しました")
                }
            }
            }, failureHandler: { error in
                // 失敗
                SVProgressHUD.showErrorWithStatus("アップロードに失敗しました")
        })
    }
}

サーバ側にはこんなかんじで送られてきます(PHPなんですけど)

$_POST["id"]; // 1

$_FILES["file"];
/*
array(
    "error" => 0,
    "name" => "file",
    "size" => 251418,
    "tmp_name" => "/var/tmp/phputuzXe",
    "type" => "image/jpeg",
);
*/

このへんもHTMLとJavaScriptで実装するとすぐできるイメージなんですけど、ネイティブで実装すると最初は大変ですね、、、

以上です