2013年1月3日木曜日

GalleryからPicasaの画像を取得する

GalleryからPicasaの画像を取得する

Galleryを起動するには次のようにする。
    Intent it = new Intent();
    it.setType("image/*");
    it.setAction(Intent.ACTION_PICK);
    startActivityForResult(it, ID_Result_Gallery);

Galleryから戻ってくると、onActivityResultメソッドで値を取得する。
    protected void onActivityResult(int r, int resultCode, Intent data) {
    if(r==ID_Result_Gallery){
        if(resultCode==RESULT_OK){
            Uri u = data.getData();
            //この記事は、この場所で何をするのかという内容です
        }
        else{//Galleryの操作途中でキャンセルした場合
        }

Galleryから取得したUriのデータ内容が端末に存在する画像ファイルを指す場合、そのUriのデータを、フルパスファイル名(String型)に変換できる。次がそのprogramです。
    ContentResolver cr = getContentResolver();
    String[] columns = { MediaColumns.DATA };
    Cursor c = cr.query(u, columns, null, null, null);
    if(c==null) return;
    c.moveToFirst();
    i = c.getColumnIndex(MediaColumns.DATA);
    s = c.getString(i);
    c.close();

しかし、Uriのデータ内容が、Picasaの画像を指す場合、そのUriのデータからフルパスファイル名(String型)には変換できない。Cursor#getString()の戻値はnullになる。
ただし、次のようにprogramすれば表示用の名前(実行上はファイル名)を取得できる。
    ContentResolver cr = getContentResolver();
    String[] columns = { MediaColumns.DATA,  MediaColumns.DISPLAY_NAME};
    Cursor c = cr.query(u, columns, null, null, null);
    if(c==null) return;
    c.moveToFirst();
    i = c.getColumnIndex(MediaColumns.DISPLAY_NAME);
    s = c.getString(i);
    c.close();

Picasaの画像データは端末に存在しないため、ファイルのパス名を取得できない仕掛けになっているのであろう。

上記プログラムで知り得たUriの値をメモしておいて、その値を使って、onCreate()の時点で、Picasaの画像を呼び出すと、アプリがクラッシュする。面白いので、読者諸兄も下記のプログラムを実行してみよう。読者諸兄をショウモナイことに誘う。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Uri u;
        Uri.Builder ub = new Uri.Builder();
        ub.scheme(ContentResolver.SCHEME_CONTENT);
        
        // * test pattern 1 Picasaのファイル
        ub.authority("com.google.android.gallery3d.provider");
        ub.path("/picasa/item/0000000000000000000");
        
        // * test pattern 2 端末内のファイル
        //ub.authority("media");
        //ub.path("/external/images/media/142");
        
        u = ub.build();
        
        ContentResolver cr = getContentResolver();
        
        //pattern 1 の場合次の行でクラッシュする。
        Cursor c = cr.query(u, null, null, null, null);

Picasaの画像データは「保護されている状態」にあるのかもしれない。プログラムで直接参照しに行くと死に行くことになる(シャレ)。
Galleryから戻って来た後であれば、当該Uriを指定して当該画像を取得することはできる。

ただし、ある画像ファイルをGalleryで選択した後で、(Picasaの)別の画像ファイルをプログラムで直接参照しに行くと死に行くことになる(再度シャレ)。
つまり、端末の利用者がGalleryでPicasaの画像を選択した後でなければ、そのPicasaの画像をプログラムで取り扱えないのである。

利用者がGalleryで選択しなければ当該画像を取得できない。Uriのデータだけを使えばPicasaデータを取得できるというものではない。端末に存在する画像ファイルであればUriのデータだけで取得できるのに。
利用者にいちいちGalleryで選択して頂くのは面倒である。このため、アプリを構築する場合には、取得した画像を自分の端末に保存することになるであろう。


次に留意点を書いておく。
androidのバージョンが4.0以上である場合
Uriの<scheme>にはcontentが代入されている。
画像データを取得するにはContentResolver#openInputStream()を使う。
AndroidManifestファイルにpermissionを設定する必要は無い。

androidのバージョンが2.3の場合
Uriの<scheme>にはhttpsが代入されている。
画像データを取得するにはHttpGet等を使う。
HttpGet等を使うのであるから、AndroidManifestファイルにInternet関係のpermissionを設定する必要がある。

4.0はpermissionを設定する必要がないので優れていると評価できる。私の手元には3.0の端末が無いため検証はできない。

sample programは次のサイトに掲載した。
GalleryからPicasaの画像を取得する

以下はファイル名の話である
PicasaにおけるMediaColumns.DISPLAY_NAMEのデータも保存しておく必要はある。このデータをアプリのタイトルバーに表示するのである。また、「保存した画像を選択する」時に表示する文字列としても利用する。

MediaColumns.DISPLAY_NAMEはDISPLAYの名前であって、(実行上はファイルの名前ではあるが)正確にはファイルの名前では無い。もしかして、nullである可能性もある。このため、nullの場合には"unknown"という文字列をprogramで挿入すれば良い。
ファイル名として取り扱えない文字が含まれている可能性を考慮しなければならない。何故考慮しなければならないのか。何故なら、私は、この仕様の詳細を知らないからである(ここで笑う)。
このため、MediaColumns.DISPLAY_NAMEで取得した文字列は、あくまで表示用として使い、ファイル名に応用するのはやめた方が良い。

不確実な前提を基に、適当な情報の提供をしているが、この情報が諸兄のお役に立てれば不幸中の幸いである(再度ここで笑う)。

0 件のコメント:

コメントを投稿