简体   繁体   English

从Picasa // Google +同步文件夹中获取图库中的图像不起作用

[英]Getting an image from Gallery on from the Picasa//Google + synced folders doesn't work

I am trying to get an image from the gallery app from one of the folders from the Google+ synced photos. 我正在尝试从Google+同步照片中的某个文件夹中获取图库应用中的图片。 After selecting the image, the Uri is being passed back correctly. 选择图像后,Uri正在正确传回。 But when I try to get the actual path of that image on the storage device, so that I can use it, it crashes. 但是当我试图在存储设备上获取该图像的实际路径时,我可以使用它,它会崩溃。 The problem seems to be specifically with the picasa content provider . 问题似乎与picasa内容提供商有关

Tested on Nexus S and Nexus 7, and other devices as well. 在Nexus S和Nexus 7以及其他设备上进行了测试。

E/AndroidRuntime(14572): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.google.android.gallery3d.provider/picasa/item/5427003652908228690 }}

Here, the dat field seems to be correctly passing the Uri, but when I try to fetch the image's location, it crashes with the following error. 这里,dat字段似乎正确地传递了Uri,但是当我尝试获取图像的位置时,它崩溃时出现以下错误。

W/GalleryProvider(14381): unsupported column: _data

Seems that the content provider for Picasa albums doesn't have a _data field. 似乎Picasa相册的内容提供商没有_data字段。

The code for getting the location is: 获取位置的代码是:

// imageUri is the Uri from above.
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(imageUri, proj,null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();

String filePath = cursor.getString(column_index);
cursor.close();

The only columns that seem to be supported for this image are: [user_account, picasa_id, _display_name, _size, mime_type, datetaken, latitude, longitude, orientation] 此图片似乎唯一支持的列包括:[user_account,picasa_id,_display_name,_size,mime_type,datetaken,纬度,经度,方向]

How do we get the actual location of this image. 我们如何获得此图像的实际位置。 And if we are not supposed to work with this image, these images shouldn't be shown to the user in the first place. 如果我们不应该使用此图像,则不应首先向用户显示这些图像。

The Intent to launch the gallery app is: 启动图库应用程序的意图是:

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);

I wasted now lots of hours and now i found a solution which works in all cases without any magic downloading in special threads or something. 我现在浪费了很多时间,现在我找到了一个解决方案,适用于所有情况,没有特殊线程或任何东西的魔法下载。 The following method returns a stream from the content which the user selected and this works with everything in the wild. 以下方法从用户选择的内容返回流,这适用于野外的所有内容。

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;
}

After a lot of research, I felt that there were too many workarounds to do something which seems to be quite simple. 经过大量的研究,我觉得有太多的变通方法可以做一些看起来很简单的事情。 So, I went ahead a wrote a small library that handles all the complex if elses and happens to work for all possible scenarios that I can think of. 所以,我继续编写了一个小型库,可以处理所有复杂的文件,并且适用于我能想到的所有可能的场景。 Do give it a try and see if this helps. 试一试,看看这是否有帮助。

http://techdroid.kbeanie.com/2013/03/easy-image-chooser-library-for-android.html http://techdroid.kbeanie.com/2013/03/easy-image-chooser-library-for-android.html

This is an initial implementation. 这是一个初步实施。 Although it handles almost every situation, there could be a few bugs. 虽然它几乎处理所有情况,但可能会有一些错误。 If you use this library, please let me know your feedback and if at all it could be improved any further. 如果您使用此库,请告诉我您的反馈,如果可以的话,可以进一步改进。

I faced the same problem about year ago.. I show you my solution (code is quite messy, please refactor it). 我在一年前面临同样的问题..我告诉你我的解决方案(代码很乱,请重构它)。 So, you have the image URI which was returned from gallery: 所以,你有从图库返回的图像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;                      
}

And now we need function to download image: 现在我们需要下载图像的功能:

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 is my class to store path to image and its orientation. 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;           
    }
}

Based on @drindt answer, below codes give downloaded temporary File path from Google Photo cloud-synced-but-not-in-device file. 基于@drindt答案,下面的代码从Google Photo云同步但未在设备文件中提供下载的临时File路径。

@SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {

    // Google photo uri example
    // content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919

    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String result = getDataColumn(context, uri, null, null); // 
        if (TextUtils.isEmpty(result))
            if (uri.getAuthority().contains("com.google.android")) {
                try {
                    File localFile = createImageFile(context, null);
                    FileInputStream remoteFile = getSourceStream(context, uri);
                    if(copyToFile(remoteFile, localFile))
                        result = localFile.getAbsolutePath();
                    remoteFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        return result;
    }
    // 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.
 */
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;
}


/**
 * Copy data from a source stream to destFile.
 * Return true if succeed, return false if failed.
 */
private static boolean copyToFile(InputStream inputStream, File destFile) {
    if (inputStream == null || destFile == null) return false;
    try {
        OutputStream out = new FileOutputStream(destFile);
        try {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) >= 0) {
                out.write(buffer, 0, bytesRead);
            }
        } finally {
            out.close();
        }
        return true;
    } catch (IOException e) {
        return false;
    }
}

public static String getTimestamp() {
    try {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
    } catch (RuntimeException e) {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    }
}

public static File createImageFile(Context context, String imageFileName) throws IOException {
    if (TextUtils.isEmpty(imageFileName))
        imageFileName = getTimestamp(); // make random filename if you want.

    final File root;
    imageFileName = imageFileName;
    root = context.getExternalCacheDir();

    if (root != null && !root.exists())
        root.mkdirs();
    return new File(root, imageFileName);
}


public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
    FileInputStream out = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        ParcelFileDescriptor parcelFileDescriptor =
                context.getContentResolver().openFileDescriptor(u, "r");
        FileDescriptor fileDescriptor = null;
        if (parcelFileDescriptor != null) {
            fileDescriptor = parcelFileDescriptor.getFileDescriptor();
            out = new FileInputStream(fileDescriptor);
        }
    } else {
        out = (FileInputStream) context.getContentResolver().openInputStream(u);
    }
    return out;
}

Below trick worked for me, what i am doing here is if there is any authority url in URI, then i am creating a temporary image using below code & returning the Content URI of the same. 下面的技巧对我有用,我在这里做的是如果URI中有任何权限url,那么我使用下面的代码创建一个临时图像并返回相同的内容URI。

I have answered similar question here as well.. 在这里也回答了类似的问题..

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);
}

I used this approach, works fine for me, hope this will helps you .... 我用这种方法,对我来说很好,希望这会对你有所帮助....

ACTIVITYRESULT_CHOOSEPICTURE is the int you use when calling startActivity(intent, requestCode); ACTIVITYRESULT_CHOOSEPICTURE是调用startActivity时使用的int(intent,requestCode);

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();
  }
}

if above code doesn't work than just refer this link... it will surly shows the way 如果上面的代码不起作用,只需参考这个链接...它将显示方式

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

Finally ended with a classic solution...By using Document.util, which covers all authority :-1-Inside your onActivityResult():- 最后以经典解决方案结束......通过使用Document.util,它涵盖了所有权限:-1-在你的onActivityResult()里面: -

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

                    break;

2- Create class DocumentUtils:- 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- Also you will need following function in ImageLoader.java:- 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从图库中检索要上传的Picasa图像 - Retrieve Picasa Image for Upload from Gallery 从Gallery中检索非缓存的Picasa图像。 3.0和4.0 - Retrieve a non cached Picasa image from Gallery. 3.0 and 4.0 android加载图片来自picasa相册或来自Google+照片的gallary为空 - android Load Image From gallary from a picasa album or from the Google+ Photos getting null 从图库中拍摄的图像未出现 - Image taken from gallery doesn't appear 无法替换图像视图,用于相机或图库中的图像(无效) - Can't replace image view, for image from a camera or gallery (It doesn't work) 在ICS上的缩略图中选择Picasa图片并选择图片 - Thumbnails and picking picasa images from gallery on ICS 从相机或图库上传图像时,startActivityForResult在片段中不起作用 - startActivityForResult doesn't work in a Fragment while image upload from camera or gallery 从图库中获取图像,某些图像甚至无法显示图像路径 - Getting images from gallery, some images doesn't show even image path is obtained Flutter 图像选择器无法从相册/图库中选择图像 - Flutter Image Picker doesn't pick image from Album/Gallery 在Android中从图库获取图像 - Getting Image from gallery in android
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM