カメラロールの写真から画像を取得(iOS, Objective-C)

カメラロールの写真から画像を取得する方法を調べていたら以外とシンプルなものがなかったのでポスト. これは最小限の実装だと思っていますが,もっと減らせるのですかね.

ヘッダーファイルはこんな感じです.

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end

実装ファイルはこんな感じです.

UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:imagePicker animated:YES completion:nil];

写真が選ばれると,以下のメソッドが呼ばれます.

- (void)imagePickerController :(UIImagePickerController *)picker
        didFinishPickingImage :(UIImage *)image editingInfo :(NSDictionary *)editingInfo {
    NSLog(@"selected");
    [self.imageView setImage:image];
    [self dismissViewControllerAnimated:YES completion:nil];
}

ここでは画像をself.imageViewに設定し,dismissしています. これだけです.

広告

UISearchBarのフォーカスを外す

UISearchBarにはキャンセルボタンがありますが, SearchBar以外がタップされたらキャンセルする方がスマートではないでしょうか. というわけでこれを実装. といってもここに全て書いてありました.

これを少し変えて以下のコードを追加しました.

- (void)touchesBegan😦NSSet *)touches withEvent😦UIEvent *)event 
{    
    UITouch *touch = [[event allTouches] anyObject];
    if ([self.mySearchBar isFirstResponder] && [touch view] != self.mySearchBar) 
    {
        [self.mySearchBar resignFirstResponder];
    }
    [super touchesBegan:touches withEvent:event];
}

ちなみにキャンセルボタンも試したのですが,まず表示されなかった. がんばって表示までたどり着いたのですが,キャンセルボタンのスタイルを簡単に変えられないみたいなので このアプローチをとりました.こっちの方が直感的な気がしますよね.

NSURLで日本語の含むURLを使用する場合(iOS, Objective-C, NSURL)

この前,NSURLSessionでGoogleImageSearchAPIを使う というのを書きましたが, クエリが日本語である場合うまく動きません. urlstringをエスケープ?してやる必要があるみたいです. ここに解決法がありました.ほんと助かりました.

前回は,

NSURL *url = [NSURL URLWithString:urlString];

こう書いていたのですが,これを,

NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

に直してやれば無事動きます.多分他言語でもいけると思います. 前の記事直しておこう.

html.canvasのdrawImageをiOSで実装してみる.(iOS, Objective-C)

canvasはjavascriptを使っていろんな絵を描画できます. この中に,drawImageというものがあります. これはcanvasに画像を描画するためのメソッドです. toDataURLで作った画像を保存することもできる大変便利なやつです. (ちなみに他ドメインの画像は描画することはできますが,toDataURLで出力することはできません涙).

さて,今回はObjective-CでdrawImageを実装してみたいと思います. 難しそうだったんですけど意外と簡単にできました. ちなみにこんな感じの画像を作れます.

wpid-2014-01-31-18-53-55.jpg

コードはこんな感じです.

CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat insetX = 20;
CGFloat insetY = 100;
CGFloat marginX = 1;
CGFloat marginY = 1;
CGFloat size = screenWidth - 2*insetX;
UIImageView *canvas = [[UIImageView alloc]initWithFrame:CGRectMake(insetX, insetY, size, size)];
UIImage *img = [UIImage imageNamed:@"OrangeLogo.jpg"];
int numX = 3; int numY = 3;

int x = marginX; int y = marginY;
int imageWidth = (size - (marginX*numX+1)) / numX;
int imageHeight = (size - (marginY*numY+1)) / numY;
UIGraphicsBeginImageContext(canvas.frame.size);

for (int i=0; i<numX*numY; i++) {
    if (i != 0 && i%numX == 0) {
        x = marginX;
        y = y + imageHeight + marginY;
    }
    [img drawInRect:CGRectMake(x, y, imageWidth, imageHeight)];
    x = x + imageWidth + marginX;
}

canvas.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view addSubview:canvas];

ほとんどはサイズとかマージンの設定なので必要な部分を抜き出すとこんな感じです.

// 描画用UIImageView
UIImageView *canvas = [[UIImageView alloc]initWithFrame:CGRectMake(insetX, insetY, size, size)];
// テスト画像
UIImage *img = [UIImage imageNamed:@"OrangeLogo.jpg"];
// 描画領域の作成 今は領域いっぱいに
UIGraphicsBeginImageContext(canvas.frame.size);  
// テスト画像を描画
[img drawInRect:CGRectMake(x, y, imageWidth, imageHeight)];
// 描いたものをcanvasへ設定 表示させないならなくてもよい
canvas.image = UIGraphicsGetImageFromCurrentImageContext();
// 描画終了
UIGraphicsEndImageContext();

UIImageViewをcanvas,drawInRectをdrawImageだと考えると分かりやすいですかね. こんな感じでcanvasのdrawImageをObjective-Cでも実装することができました. これ,保存できるんですかねー.ということで次回は保存を.

NSURLSessionを使ってJSONデータの取得(iOS, Objective-C)

NSURLSession関連のポストが増えてきましたね.いい感じです. 今回はNSURLSessionを使ってJSONデータを取得してみます.格納はまた後日. ここまで行けば格納は問題ないと思います.
JSONデータはここ から取得します. JSON Generator – tool for generating random JSON data を使えば簡単にテストJSONデータが作成できるみたいです. ソースコードは以下のようになりました.

NSString *urlString = @"http://www.json-generator.com/j/bYArmwnBQi?indent=4";
NSURL *url = [NSURL URLWithString:urlString];

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil  ];

NSURLSessionDataTask *jsonData = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error) {
        NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *) response;
        if (httpResp.statusCode == 200) {
            NSError *jsonError;

            NSArray *testJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
            if (!jsonError) {
                // something for json data
                dispatch_async(dispatch_get_main_queue(), ^{
                    // something after parsing json data
                });
            }
        }
    }
}];
[jsonData resume];

somethingの所に格納処理を書けば良いかと思います. testJSONの型をNArrayにしていますが,ここは扱うJSONによって適宜変更で. とりあえずこれでやっかいな所は終わりそうだ.次は格納も含めてGoogle Image Search APIを使ってみたいと思います. あくまでも予定.

URLから画像をダウンロードして表示(iOS, Objective-C, NSURLSession)

前回,URLから画像を取得し表示 をやりましたが,今回はURLから画像をダウンロードして表示します. これには,NSURLSessionを使います. NSURLSessionについては NSURLSession Tutorial で学べます. 僕もまだ詳しいことはわかっていないのですが,こんな流れだそうです.

  1. NSURLSessionConfigurationを作る(config)。
  2. configからNSURLSessionを作る(session)。
  3. sessionからTaskを作る(task)。
  4. タスク(task)をスタート。

コードはこんな感じになりました.imageViewというUIImageViewを定義していると仮定します.

NSString *urlString = @"http://images.moneysavingexpert.com/images/OrangeLogo.jpg";
NSURL *url = [NSURL URLWithString:urlString];

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
    UIImage *downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
    dispatch_async(dispatch_get_main_queue(), ^{
        _imageView.image = downloadedImage;
    });
}];
[getImageTask resume];

今回は画像のダウンロードということで,タスクにdownloadTaskWithURLを使っています. ということはいろいろなタスクが用意されている,ということになりそうですね. そして完了したらcompletionHandlerで定義した関数が実行されます. これらは非同期処理なので,resumeをお忘れなく.

ちなみに以下のようにも書けるみたいだ.
ヘッダーファイル(別にViewControllerでなくても良い)

@interface ViewController : UIViewController <NSURLSessionDownloadDelegate>

実装ファイル

NSString *urlString = @"http://images.moneysavingexpert.com/images/OrangeLogo.jpg";
NSURL *url = [NSURL URLWithString:urlString];

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil  ];

NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:url];
[getImageTask resume];

最後に以下のメソッドを実装ファイルに追加する.

-(void)URLSession😦NSURLSession *)session downloadTask😦NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL😦NSURL *)location {
    UIImage *downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
    dispatch_async(dispatch_get_main_queue(), ^{
        _imageView.image = downloadedImage;
    });
}

NSURLSessionでGoogleImageSearchAPIを使う(iOS, Objective-C)

自分用備忘録です. NSURLSessionを使ってJSONを取得する方法をやったので,今回はGoogle Image Search APIをObjective-Cで使ってみたいと思います. このAPIをJavascript, Pythonで触ったことがあるのでAPIについては割愛. 今回の目標はあるクエリ(orangeとした)で検索して1ページ目全8件の画像を取得し,それぞれのURLを,

@property (nonatomic, strong) NSMutableArray *imageURLs;

こいつに格納する.その後格納された件数を出力する,というものです.あまり楽しくはないか. 前回のポストとほとんど同じで,このAPI用に何か特別な処理をする,ということはない. コードはこんな感じ.

NSString *keyword = @"orange";

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *urlBaseString = @"http://ajax.googleapis.com/ajax/services/search/images?v=1.0&hl=ja&rsz=large&start=0&q=%@";
NSString *urlString = [NSString stringWithFormat:urlBaseString, keyword];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil  ];

NSURLSessionDataTask *jsonData = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error) {
        NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *) response;
        if (httpResp.statusCode == 200) {
            NSLog(@"success!");
            NSError *jsonError;

            NSDictionary *rawJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];

            NSMutableArray *imageURLsFound = [[NSMutableArray alloc]init];

            if (!jsonError) {
                NSArray *results = rawJSON[@"responseData"][@"results"];
                for (NSDictionary *result in results) {
                    NSURL *imageURL = [NSURL URLWithString:result[@"url"]];
                    [imageURLsFound addObject:imageURL];
                }
                self.imageURLs = imageURLsFound;

                dispatch_async(dispatch_get_main_queue(), ^{
                    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
                    NSLog(@"%lu", _imageURLs.count);
                });
            }
        }
    }
}];
[jsonData resume];

個人的に気になるのは以下の二つ.まずこれ.

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

これをYES, NOで切り替えてるのだけどもなんなんだろうこれは. 名前的に上のネットワーク使用中の出すか出さないかだと思うんだが,と思ったらその通りだった. 気になる方は是非消して実行してみてほしい.
次にこれ.

dispatch_async(dispatch_get_main_queue(), ^{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    NSLog(@"%lu", _imageURLs.count);
});

dispatch_asyncで非同期処理の終わりを意味するのでしょうか. とりあえず書いておいて,JSON解析後の処理をここに書くのがよろしいのではないでしょうか. そんな感じ.全くわかってないけど,一歩一歩ってやつだよね.