2013年12月18日水曜日

【iOS】ALAssetのいじったときのメモまとめ、カメラロールから画像を!

もりもりに盛り上がってるiOS AdventCalender 19日め担当の@jumbOS5です。

iOS Advent Calendar 2013 - Qiita [キータ]







今回はカメラ・アルバムアプリを作る時にほぼほぼ100%使うALAssetについて色々まとめたいと思います。
  1.  ALAssetって?
  2. そもそもiOS内の画像ってどこにいるの?
  3.  どんなとき、どうやって使うの?
 この辺りをまとめます。

1、ALAssetって?


端末内に保存されている動画/写真を管理するクラス。
AssetsLibrary - Reference

アプリの持つ画像を取ってくるのに多く使われるのは
  • NSDocumentDirectoryなどからパスで参照
  • ImagePickerで選択させる
  • ALAsset

みんな大好きimagePickerはでもどちらかといえばUIで、ユーザーが画像にアクセスするための機能として提供されている。なのでメタ情報(位置、撮影日時)などは取得できない!!UIImageとしてとれるだけ。複数選択とかもできないっぽいですね


このALAsetはメタ情報含めた画像データを取得できる。

2、そもそもiOS内の画像ってどこにいるの?


普段使われている「写真アプリ」の持つカメラロールと呼ばれる場所以外に、アプリごとに固有の画像を保存できる。

アプリケーションディレクトリの構造とアクセス方法 - プログラミングノート






これに関してはこちらのリンクが詳しい。
一応前に書いたソースも載せておくと


- (void)checkDocImages{

    [SVProgressHUD show];
    NSArray*  paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
    NSString* dir   = [paths objectAtIndex:0];
    NSArray*  files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];
    NSLog(@"Secret Loading Path %@", dir);
    dirImageCtn = 0;
    for( NSString* file in files )
    {
        NSString* extention = [file pathExtension];
        if( [extention isEqualToString:@"png"] ||
           [extention isEqualToString:@"jpeg"] ||
           [extention isEqualToString:@"jpg"])
        {
            NSString* path = [dir stringByAppendingPathComponent:file];
            NSLog(@"dir : %@", path);
            UIImage *img
            = [[UIImage alloc] initWithContentsOfFile:path];
            UIImageView * imageView = [[UIImageView alloc] initWithImage:img];
            [self setImageView:imageView count:dirImageCtn];
            dirImageCtn++;
        }
    }
    [SVProgressHUD dismiss];
}


こんなかんじ。
何をしているかというと、NSFileManagerが指定のディレクトリ内のファイルを(画像も映像もなんでも)とってきてくれるのでそれらから、拡張子を抜いて画像の物だけひろってUIImageに突っ込んでる。
テキストとか使いたい時はこれでやるのもいいかもしれない。

これで取れるような画像はシミュレータなら直接いじることができる。配置や削除も可能です、実機だとやり方がわからないorz


3、 どんなとき、どうやって使うの?


 上記でも述べているようにメタ情報つきで画像を使いたいときに活躍してくれる。

・メタ情報に関して

*メタ情報は以下のような物が取れる(assetはALAsset型)
NSLog(@"%@", [[asset defaultRepresentation] metadata]);

//以下結果
2013-12-18 19:06:45.711 new_techPro[5632:60b] {
    ColorModel = RGB;
    DPIHeight = 72;
    DPIWidth = 72;
    Depth = 8;
    Orientation = 6;
    PixelHeight = 1936;
    PixelWidth = 2592;
    "{Exif}" =     {
        ApertureValue = "2.52606882168926";
        ColorSpace = 1;
        ComponentsConfiguration =         (
            1,
            2,
            3,
            0
        );
        DateTimeDigitized = "2010:08:24 16:31:43";
        DateTimeOriginal = "2010:08:24 16:31:43";
        ExifVersion =         (
            2,
            2,
            1
        );
        ExposureMode = 0;
        ExposureProgram = 2;
        ExposureTime = "0.06666666666666667";
        FNumber = "2.4";
        Flash = 16;
        FlashPixVersion =         (
            1,
            0
        );
        FocalLength = "3.85";
        ISOSpeedRatings =         (
            500
        );
        MeteringMode = 1;
        PixelXDimension = 0;
        PixelYDimension = 0;
        SceneCaptureType = 0;
        SensingMethod = 2;
        Sharpness = 2;
        ShutterSpeedValue = "3.9112";
        SubjectArea =         (
            1295,
            967,
            699,
            696
        );
        WhiteBalance = 0;
    };
    "{GPS}" =     {
        DateStamp = "2010:08:24";
        ImgDirection = "112.9100529100529";
        ImgDirectionRef = T;
        Latitude = "35.63983333333334";
        LatitudeRef = N;
        Longitude = "139.8621666666667";
        LongitudeRef = E;
        TimeStamp = "16:31:34";
    };
    "{TIFF}" =     {
        DateTime = "2010:08:24 16:31:43";
        ImageDescription = "Back Camera";
        Make = Apple;
        Model = iPhone;
        Orientation = 6;
        ResolutionUnit = 2;
        Software = "4.0";
        XResolution = 72;
        YResolution = 72;
    };
}



もうぱっと見てる感じ意味がわからないけど、よくよく見ると画像を構成するデータから位置情報、時間なども入っているのがわかる。でもだいたい必要な物は決まっていて、以下のようにして取れる。

NSDate* assetDate = [asset valueForProperty:ALAssetPropertyDate]

こんなかんじ。
それでvalueForPropertyで指定できるのは以下。

NSString *const ALAssetPropertyType;
NSString *const ALAssetPropertyLocation;
NSString *const ALAssetPropertyDuration;
NSString *const ALAssetPropertyOrientation;
NSString *const ALAssetPropertyDate;
NSString *const ALAssetPropertyRepresentations;
NSString *const ALAssetPropertyURLs;
NSString *const ALAssetPropertyAssetURL;

うん、便利。

・サムネも取れる


 UIImage* _image = [UIImage imageWithCGImage:[asset thumbnail]];

こんなかんじで写真アプリに表示されているようなサムネもALAssetから取れる!!
実はぼくこれしらなくて画像フルスクリーンで取って、四角に切ってUIViewContentModeScaleAspectFillとかしてました・・・

・最後にアルバムアプリのサンプル作った時のソースの一部

 
-(void)setImageAssets{
    // 写真一覧
    assetsLibrary = [[ALAssetsLibrary alloc] init];
    [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
                                 usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                                     
                                     // be sure to filter the group so you only get photos
                                     NSLog(@"Album name %@" ,[group valueForProperty:ALAssetsGroupPropertyName]);
                                     NSLog(@"number %d", [group numberOfAssets]);
                                     
                                     if ([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:@"Camera Roll"]) {
                                         
                                         [group setAssetsFilter:[ALAssetsFilter allPhotos]];
                                         
                                         for(int j = 0; j < 10; j++){
                                             [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:j]
                                                                     options:0
                                                                  usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                                                                      if (nil != result) {
                                                                          ALAssetRepresentation *defaultRep = [result defaultRepresentation];
 
 [self addImageAssets:result];                                                                    }
                                                                  }];
                                         }
                                     }//group
                                     [myCollectionView reloadData];
                                     
                                     *stop = NO;
                                 } failureBlock:^(NSError *error) {
                                     NSLog(@"error: %@", error);
                                 }];
}

ALAssetの情報をImageというNSMutableArrayにつっこんであとでなんやするってソースですね。これ作った時に気をつけたのが以下の2点。

1、enumerateGroupsWithTypesの指定
 ここで指定するALAssetGroupTypeっていろいろあって

aenum {
   ALAssetsGroupLibrary        = (1 << 0),
   ALAssetsGroupAlbum          = (1 << 1),
   ALAssetsGroupEvent          = (1 << 2),
   ALAssetsGroupFaces          = (1 << 3),
   ALAssetsGroupSavedPhotos    = (1 << 4),
   ALAssetsGroupPhotoStream    = (1 << 5),
   ALAssetsGroupAll            = 0xFFFFFFFF,
};

ALAssetsGroupFacesはこれかきながら初めて知ったけど、顔画像とかひょっとして取れるの?とりあえずカメラロールの写真が欲しければALAssetsGroupSavedPhotosを指定しましょう。
ALAssetGroupAlbumとかだと一件カメラロールもアルバムっぽい扱いかと誤解しますが、入ってないので気をつけてください。

2、setAssetsFilter
取得したAssetsにフィルターをかけれます。

AllAssets
AllPhotos
AllVideos

と好きなヤツを選んでください。
ALAssetの取得は全探索をしなきゃなのでなるべく探索項目はこれで減らしましょう。

*まとめ

カメラロールの写真をとって並べたり、その情報を使いたい時にいじるALAssetについて書かせていただきました!
AdventCalender見てるとけっこう皆さん高レベルなtipsをまとめてて大変恐縮なのですが
、けっこう利用頻度の高いクラスなので勉強がてらまとめました(っ˘ω˘c )

全探索が必要なALAssetの読み込みを高速化に関してならこちらの記事もおすすめです。


 Assets Library からの読み込みを高速化するための試行錯誤 - Over&Out その後





 

*iBeacon Advent Calender

iBeacon も盛り上がってます!!まだ23日が空いているので我こそはという型がいらっしゃれば是非(*u*

iBeacon Advent Calendar 2013 - Qiita [キータ]







ぼくは吉高百合子におかえりと言ってもらうために、部屋に入ると『おかえり』って言ってくれるもらえるアプリをiMacとiPhoneで実現しました
的な記事を書きましたので、こちらもよろしければ

Tech Tech walker: 【iBeacon】部屋に帰ると「おかえり」って言ってくれるiPhoneアプリを作る【iMac→iPhone】






次は@hiramatsuさんです!!
Think Big Act Local

0 件のコメント:

コメントを投稿

ShareThis