LoginSignup
12
12

More than 5 years have passed since last update.

Objective-C 画像をリサイズしてサーバにUpload

Last updated at Posted at 2015-03-26

やりたかったこと

よくあるプロフィール写真を選択して、トリミングして設定。がやりたかったので
実装してみました。今回は一つの画像だけでよかったけど
検索したサイトの実装の流れで、以下のようになってしまった。

テキストのPOST送信と画像のUploadをマルチパートで行う。
NSURLSessionDataTaskデリゲートでの実装でなく、
Blocksで成功/エラーのコールバックを返す。
なお、画像はUIImagePickerControllerでアルバムから選択し
トリミングとリサイズした画像を使用する。
アルバムからでなく、カメラで撮影したものを使いたければ、UIImagePickerControllerSourceTypePhotoLibraryの箇所をUIImagePickerControllerSourceTypeCameraと変更すればOKです

POST送信については、この辺を参考にしました。

自作のReqHTTPクラス


//ReqHTTP.h
#import <CoreImage/CoreImage.h>
@interface ReqHTTP : NSObject
- (void)postMultiDataWithTextDictionary:(NSDictionary*)textDictionary
                        imageDictionary:(NSDictionary*)imageDictionary
                                    url:(NSURL*)url done:(void(^)(NSDictionary *responseData)) doneHandler fail:(void(^)(NSInteger status)) failHandler;
@end

//ReqHTTP.m
@implementation ReqHTTP
{
    void (^requestDoneHandler)(NSDictionary *data);
    void (^requestFailHandler)(NSInteger status);
}
- (void)postMultiDataWithTextDictionary:(NSDictionary*)textDictionary
                        imageDictionary:(NSDictionary*)imageDictionary
                                    url:(NSURL*)url done:(void(^)(NSDictionary *responseData)) doneHandler fail:(void(^)(NSInteger status)) failHandler
{
    requestDoneHandler = doneHandler;
    requestFailHandler = failHandler;

    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSString* boundary = @"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    config.HTTPAdditionalHeaders =
    @{
      @"Content-Type" : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
      };

    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
    // postデータの作成
    NSMutableData* data = [NSMutableData data];
    // テキスト部分の設定
    for (id key in [textDictionary keyEnumerator])
    {
        NSString* value = [textDictionary valueForKey:key];

        [data appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data;"] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"%@\r\n", value] dataUsingEncoding:NSUTF8StringEncoding]];
    }

    // 画像の設定
    for (int i = 0; i < [imageDictionary count]; i++)
    {
        NSString* key = [[imageDictionary allKeys] objectAtIndex:i];
        NSData* value = [imageDictionary valueForKey:key];
        NSString* name = [NSString stringWithFormat:@"upload_file%d", i];

        [data appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data;"] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"name=\"%@\";", name] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"filename=\"%@\"\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[[NSString stringWithFormat:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:value];
        [data appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    }

    // 最後にバウンダリを付ける
    [data appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    request.HTTPMethod = @"POST";
    request.HTTPBody = data;
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        [session invalidateAndCancel];//メモリリーク対策
        if(error){
            requestFailHandler(-1);
        }else{
            NSError *err = nil;
            NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
                                                                 options:NSJSONReadingMutableContainers
                                                                   error:&err];
            if (err) {
                requestFailHandler(-1);
                return;
            }
            requestDoneHandler(json);
        }

    }];

    [task resume];
}
@end

写真の選択


//viewController.h
@interface viewController : UIViewController<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end

//viewController.m
@implementation viewController
{
       UIImage *resizedImage;
}

- (void)photoSelect{
   UIImagePickerController *picker = [[UIImagePickerController alloc] init];
   picker.delegate = self;
   picker.allowsEditing = YES;//写真選択後編集
   if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary]== NO){
        NSLog(@"Photo Library not available.");
        return;
   }
   picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
   [self presentViewController:picker animated:YES completion:nil];

}

//写真を選択/編集完了
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
    if(!image){
        image = [info objectForKey:UIImagePickerControllerOriginalImage];
    }
    //保持
    resizedImage = [self resizedImage:image width:100 height:100];

    [self dismissViewControllerAnimated:YES completion:NULL];
}

//画像をリサイズ
- (UIImage *)resizedImage:(UIImage *)image width:(CGFloat)width height:(CGFloat)height
{
    //UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, [[UIScreen mainScreen] scale]);
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 1.0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetInterpolationQuality(context, kCGInterpolationDefault);

    [image drawInRect:CGRectMake(0.0, 0.0, width, height)];

    UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resizedImage;
}

アップロード処理

 -(void)upload
{
     NSURL *url = [NSURL URLWithString:@"http://xxxxx/upload.php"];
     NSData *imageData = [[NSData alloc] initWithData:UIImageJPEGRepresentation(thumb.image, 1.0)];

     NSMutableDictionary* texts = [NSMutableDictionary dictionary];
     NSMutableDictionary* images = [NSMutableDictionary dictionary];

     [texts setObject:@"値" forKey:@"キー"];//複数ある場合はこれを追加
     [images setObject:imageData forKey:@"thumbnail.jpg"];//複数ある場合はこれを追加

     ReqHTTP *reqHTTP = [[ReqHTTP alloc] init];
     [reqHTTP postMultiDataWithTextDictionary:texts
                                 imageDictionary:images
                                             url:url
                                            done:^(NSDictionary *responseData) {
                                                NSInteger status = [[responseData objectForKey:@"status"] integerValue];
                                                if (status < 0) {
                                                    NSLog(@"画像のUploadに失敗");
                                                    return;
                                                }
                                                //成功
                                                NSLog(@"success %@", responseData);

                                            } fail:^(NSInteger status) {
                                                NSLog(@"画像のUploadに失敗");
                                            }];
}

PHP

※Uploadエラー処理などは省略。
この辺が参考になるかも


<?php
    $idx = count($_FILES) - 1;
    //今回は1つのみの画像Uploadだが
    //複数の場合はforで回して取得
    $tmp_path = $_FILES['upload_file'.$idx]['tmp_name'];
    $target_path = 'upload/';//保存ディレクトリ
    $target_path = $target_path.basename($_FILES['upload_file'.$idx]['name']);
    //→upload/thumbnail.jpg

    //一時保存画像を保存デジレクトリに移動
    if(move_uploaded_file($tmp_path, $target_path)){
        //保存成功
        echo json_encode(array(
            'status' => 0
        ));
        return;
    }
    //ここでは、失敗の場合statusにマイナス値を返している
    echo json_encode(array(
        'status' => -1
    ));
?>

PHPはよくわからないので、コードがダサいかもしれません。
あしからず

12
12
0

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
12
12