61

Google+ 同期写真のフォルダの 1 つからギャラリー アプリから画像を取得しようとしています。画像を選択すると、Uri が正しく返されます。しかし、ストレージ デバイス上のそのイメージの実際のパスを取得して使用できるようにしようとすると、クラッシュします。問題は特にpicasa コンテンツ プロバイダにあるようです。

Nexus S と Nexus 7、およびその他のデバイスでもテスト済みです。

E/AndroidRuntime(14572): java.lang.RuntimeException: 結果の配信に失敗しました ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.google.android.gallery3d.provider /picasa/item/5427003652908228690 }}

ここでは、dat フィールドが Uri を正しく渡しているように見えますが、画像の場所を取得しようとすると、次のエラーでクラッシュします。

W/GalleryProvider(14381): サポートされていない列: _data

Picasa アルバムのコンテンツ プロバイダには _data フィールドがないようです。

場所を取得するためのコードは次のとおりです。

// imageUri は上記の Uri です。
String[] proj = { MediaStore.Images.Media.DATA };
カーソル cursor = context.getContentResolver().query(imageUri, proj,null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
カーソル.moveToFirst();

文字列 filePath = cursor.getString(column_index);
カーソル.close();

この画像でサポートされていると思われる列は次のとおりです: [user_account, picasa_id, _display_name, _size, mime_type, datetaken, latitude, longitude, orientation]

この画像の実際の位置を取得するにはどうすればよいですか。そして、この画像を扱うことが想定されていない場合、これらの画像はそもそもユーザーに表示されるべきではありません。

ギャラリー アプリを起動する意図は次のとおりです。

インテント インテント = 新しいインテント();
インテント.setType("画像/*");
インテント.setAction(インテント.ACTION_GET_CONTENT);
4

7 に答える 7

17

私は今、多くの時間を無駄にしており、特別なスレッドなどで魔法のダウンロードをしなくても、すべての場合に機能するソリューションを見つけました。次のメソッドは、ユーザーが選択したコンテンツからストリームを返します。これは、実際のすべてのもので機能します。

FileInputStream getSourceStream(Uri u) throws FileNotFoundException {
    FileInputStream out = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        ParcelFileDescriptor parcelFileDescriptor =
                mContext.getContentResolver().openFileDescriptor(u, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        out = new FileInputStream(fileDescriptor);
    } else {
        out = (FileInputStream) mContext.getContentResolver().openInputStream(u);
    }
    return out;
}
于 2014-01-13T19:34:34.863 に答える
5

私は約1年前に同じ問題に直面しました..私の解決策を示します(コードはかなり面倒です。リファクタリングしてください)。したがって、ギャラリーから返された画像 URI があります。

    ImageInfo getImage(URI imageUri) {

        ImageInfo result = null;

        final String[] cursorColumns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION};

        // some devices (OS versions return an URI of com.android instead of com.google.android
        if (imageUri.toString().startsWith("content://com.android.gallery3d.provider"))  {
            // use the com.google provider, not the com.android provider.
            imageUri = Uri.parse(imageUri.toString().replace("com.android.gallery3d","com.google.android.gallery3d"));
        }

        Cursor cursor = App.getContext().getContentResolver().query(imageUri, cursorColumns, null, null, null);
        if (cursor != null) {

            int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            int orientationColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);

            cursor.moveToFirst();

            // if it is a picasa image on newer devices with OS 3.0 and up
            if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {

                result = new ImageInfo(downloadImage(imageUri), "0");                       

            } else { // it is a regular local image file

                result = new ImageInfo(cursor.getString(dataColumnIndex), cursor.getString(orientationColumnIndex));

            }

            cursor.close();

        } else {
            result = new ImageInfo(downloadImage(imageUri), "0");
        }

        return result;                      
}

そして今、画像をダウンロードする関数が必要です:

private String downloadImage(URI imageUri) {

    File cacheDir;
    // if the device has an SD card
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
        cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),".OCFL311");
    } else {
        // it does not have an SD card
        cacheDir = App.getContext().getCacheDir();
    }

    if(!cacheDir.exists()) cacheDir.mkdirs();
    File f = new File(cacheDir, PUT_HERE_FILE_NAME_TO_STORE_IMAGE);

    try {

        InputStream is = null;
        if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
            is = App.getContext().getContentResolver().openInputStream(imageUri);
        } else {
            is = new URL(imageUri.toString()).openStream();
        }

        OutputStream os = new FileOutputStream(f);
        Utils.InputToOutputStream(is, os);

        return f.getAbsolutePath();
    } catch (Exception ex) {
        Log.d(this.getClass().getName(), "Exception: " + ex.getMessage());
        // something went wrong
        ex.printStackTrace();
        return null;
    }
}

ImageInfo は、画像へのパスとその向きを格納するクラスです。

public static class ImageInfo {
    public final String filePath;
    public final String imageOrientation;

    public ImageInfo(String filePath, String imageOrientation) {
        this.filePath = filePath;

        if (imageOrientation == null) imageOrientation = "0";
        this.imageOrientation = imageOrientation;           
    }
}
于 2012-12-30T17:17:47.650 に答える
1

以下のトリックは私にとってはうまくいきました.URIに権限URLがある場合、私は以下のコードを使用して一時的な画像を作成し、同じコンテンツURIを返します.

ここでも同様の質問に答えています..

public static String getImageUrlWithAuthority(Context context, Uri uri) {
    InputStream is = null;
    if (uri.getAuthority() != null) {
        try {
            is = context.getContentResolver().openInputStream(uri);
            Bitmap bmp = BitmapFactory.decodeStream(is);
            return writeToTempImageAndGetPathUri(context, bmp).toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}
于 2015-09-30T17:17:57.727 に答える
0

私はこのアプローチを使用しましたが、私にとってはうまくいきます。これがあなたに役立つことを願っています....

ACTIVITYRESULT_CHOOSEPICTURE は、startActivity(intent, requestCode); を呼び出すときに使用する int です。

public void onActivityResult(int requestCode, int resultCode, Intent data) {
  if(requestCode == ACTIVITYRESULT_CHOOSEPICTURE) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    final InputStream ist = ontext.getContentResolver().openInputStream(intent.getData());
    final Bitmap bitmap = BitmapFactory.decodeStream(ist, null, options);
    ist.close();
  }
}

上記のコードが機能しない場合は、このリンクを参照するだけでは不十分です...確かに方法が示されます

http://dimitar.me/how-to-get-picasa-images-using-the-image-picker-on-android-devices-running-any-os-version/

于 2014-05-14T10:47:22.810 に答える
0

最後に、古典的なソリューションで終了しました...すべての権限をカバーするDocument.utilを使用することにより:-1-onActivityResult()内:-

case GALLERY_CAPTURE_IMAGE_REQUEST_CODE:
                    String filePath = DocumentUtils.getPath(MainContainerActivity.this,data.getData();

                    break;

2- クラス DocumentUtils を作成します:-

public class DocumentUtils {

@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[]{split[1]};

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        // Return the remote address
        String url;
        if (isGooglePhotosUri(uri)) {
            url = getDataColumnWithAuthority(context, uri, null, null);
            return getDataColumn(context, Uri.parse(url), null, null);
        }

        return getDataColumn(context, uri, null, null);

    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}



/**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context       The context.
 * @param uri           The Uri to query.
 * @param selection     (Optional) Filter used in the query.
 * @param selectionArgs (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 */
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}
/**
 * Function for fixing synced folder image picking bug
 *
 * **/
public static String getDataColumnWithAuthority(Context context, Uri uri, String selection, String[] selectionArgs) {
    Bitmap bitmap = null;
    InputStream is = null;
    if (uri.getAuthority()!=null){
        try {
            is = context.getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Bitmap bmp = BitmapFactory.decodeStream(is);
        return ImageLoader.getImageUri(context,bmp).toString();
    }

    return null;
}




/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    if(uri.getAuthority()!=null)
        return true;
    return false;
}

}

3- また、ImageLoader.java で次の関数が必要になります:-

public static Uri getImageUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}
于 2015-05-26T08:41:08.103 に答える