119

I'm trying to get image from gallery.

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );

After I returned from this activity I have a data, which contains Uri. It looks like:

content://media/external/images/1

How can I convert this path to real one (just like '/sdcard/image.png') ?

Thanks

davs
  • 9,226
  • 8
  • 41
  • 54
  • 1
    This is obviously a very late comment, but I just wanted to point out that the startActivityForResultCode method takes a request code as an argument, not a result code. – Tianxiang Xiong Apr 08 '15 at 22:17
  • did `uri.getPath()` did not give you real path? – Darpan Jul 09 '15 at 05:49
  • #Try This Still, if you are getting the problem to get the real path, you can try my answers. Above answers didn't help me. **Explanation**:- This method gets the URI and then check the API level of your Android device after that according to API level it will generate the Real path. **Code for generating real path is different according to API levels.** [Here is my Answer](https://stackoverflow.com/a/49687681/7584651) – Sunil Apr 06 '18 at 07:36

9 Answers9

207

This is what I do:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));

and:

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}

NOTE: managedQuery() method is deprecated, so I am not using it.

Last edit: Improvement. We should close cursor!!

cesards
  • 15,882
  • 11
  • 70
  • 65
  • Thanks so much for this - I've made a slight update in my answer below. If you edit yours I'll delete mine. – Chris Rae Jun 03 '13 at 17:58
  • 1
    http://stackoverflow.com/a/7265235/375093 This is another option, but suggested as better than above. Check this out too – Sundeep Jul 19 '13 at 20:48
  • 6
    Hi @m3n0R, In Moto G, MediaStore.Images.ImageColumns.DATA column does not exists at all. How to get image without this column? – seema Oct 13 '14 at 11:57
  • I don't think it's moto G stuff. It should be related to your OS... but still... I don't know, sorry – cesards Oct 13 '14 at 13:02
  • @m3n0R idx is always -1 : http://stackoverflow.com/questions/27103529/create-file-from-uri-type-android/27103868#27103868 can you help me please? – Chlebta Nov 24 '14 at 20:47
  • 25
    **ERROR** Make sure the Cursor is initialized correctly before accessing data from it.. checking in API 19 – Mayur R. Amipara Mar 10 '15 at 05:12
  • 1
    @ReneJuuse: Excellent resource. I finally managed to resolve this issue thanks to that - I didn't realise there were so many changes since Android's inception. I was running API 21 and when I used the API 19 implementation shown on the site you linked, it finally worked. – Milos Ivanovic May 31 '15 at 15:03
  • @Ricardo check my answer. That is working on all android versions. – ELITE Sep 21 '16 at 15:12
  • 5
    Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. – Maveňツ Aug 10 '17 at 13:26
  • Works on Meizu U20 (Android 6.0). – CoolMind Feb 22 '18 at 12:21
  • i just tested it on Android 26 and it's working, i think this is the best answer and should be the accepted one. – Achmad Naufal Syafiq Mar 25 '19 at 13:23
  • 5
    Crash: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. – hkchakladar Jun 16 '19 at 19:49
  • Works well. I was facing a problem in onActivityResult after selecting an image from the gallery. this works fine. – Bhaumik Belani Aug 05 '19 at 10:46
  • @M.Kumaran take a look at luizfelipetx's answer. – Rene Juuse Apr 16 '20 at 19:16
  • 5
    MediaStore.Images.ImageColumns.DATA is deprecated – valerybodak Jun 17 '20 at 06:26
  • Not working. Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetString(CursorWindow.java:-2) at android.database.CursorWindow.getString(CursorWindow.java:469) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53) at android.database.CursorWrapper.getString(CursorWrapper.java:141) – Vitaly Apr 27 '22 at 06:54
58

Is it really necessary for you to get a physical path?
For example, ImageView.setImageURI() and ContentResolver.openInputStream() allow you to access the contents of a file without knowing its real path.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
molnarm
  • 9,856
  • 2
  • 42
  • 60
28

@Rene Juuse - above in comments... Thanks for this link !

. the code to get the real path is a bit different from one SDK to another so below we have three methods that deals with different SDKs.

getRealPathFromURI_API19(): returns real path for API 19 (or above but not tested) getRealPathFromURI_API11to18(): returns real path for API 11 to API 18 getRealPathFromURI_below11(): returns real path for API below 11

public class RealPathUtil {

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column = { MediaStore.Images.Media.DATA };     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[]{ id }, null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) {
         filePath = cursor.getString(columnIndex);
     }   
     cursor.close();
     return filePath;
}


@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
      String[] proj = { MediaStore.Images.Media.DATA };
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null){
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      }
      return result;  
}

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
           String[] proj = { MediaStore.Images.Media.DATA };
           Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
           int column_index
      = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
           cursor.moveToFirst();
           return cursor.getString(column_index);
}

font: http://hmkcode.com/android-display-selected-image-and-its-real-path/


UPDATE 2016 March

To fix all problems with path of images i try create a custom gallery as facebook and other apps. This is because you can use just local files ( real files, not virtual or temporary) , i solve all problems with this library.

https://github.com/nohana/Laevatein (this library is to take photo from camera or choose from galery , if you choose from gallery he have a drawer with albums and just show local files)

luizfelipetx
  • 388
  • 4
  • 7
  • @Clocker on Samsung S4 neither – Ricardo Dec 07 '15 at 23:30
  • Im really its hard to manage all types of source images in android. If you upload, or take choose from galery, the best solution is create as a galery from facebook. Its a custom gallery with just real images in device , no virtual or temporary. I fix all problems in my app using this library . https://github.com/nohana/Laevatein Its really good library. To customize is not simple, but you can open code and made your changes. I hope this can help you. – luizfelipetx Mar 25 '16 at 05:15
  • Broken on my Samsung S2 with 4.4.1 – Oliver Dixon Apr 06 '16 at 10:08
  • I need to get the files like pdf or doc, I am unable to get the path. Can you please help me? – Anish Kumar Sep 01 '16 at 08:39
  • @felipeteixeira no need to include all these methods. Use library mentioned in my answer. That is the best solution i found. – ELITE Sep 21 '16 at 15:12
  • 2
    Awesome! Finally something that really works. Was looking for this for a long time. Thanks. – Javatar Nov 27 '16 at 14:32
  • Add the following code to the class: public static String getRealPath(Context context, Uri uri){ int versionCode = 0; try { versionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } if(versionCode >= Build.VERSION_CODES.KITKAT){ return getRealPathFromURI_API19(context, uri); }else{ return getRealPathFromURI_API11to18(context, uri); } } – Moti Aug 06 '17 at 12:30
  • Not working in Asus Zenfone 2 when I select pdf file from Downloads. And One Improvement is also requirement that I have found some time 'wholeID' does not need regex. so you have to make condition before use of regex – Nik May 21 '18 at 14:01
18

Note This is an improvement in @user3516549 answer and I have check it on Moto G3 with Android 6.0.1
I have this issue so I have tried answer of @user3516549 but in some cases it was not working properly. I have found that in Android 6.0(or above) when we start gallery image pick intent then a screen will open that shows recent images when user select image from this list we will get uri as

content://com.android.providers.media.documents/document/image%3A52530

while if user select gallery from sliding drawer instead of recent then we will get uri as

content://media/external/images/media/52530

So I have handle it in getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) {
    String filePath = "";
    if (uri.getHost().contains("com.android.providers.media")) {
        // Image pick from recent 
        String wholeID = DocumentsContract.getDocumentId(uri);

        // Split at colon, use second item in the array
        String id = wholeID.split(":")[1];

        String[] column = {MediaStore.Images.Media.DATA};

        // where id is equal to
        String sel = MediaStore.Images.Media._ID + "=?";

        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                column, sel, new String[]{id}, null);

        int columnIndex = cursor.getColumnIndex(column[0]);

        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();
        return filePath;
    } else {
        // image pick from gallery 
       return  getRealPathFromURI_BelowAPI11(context,uri)
    }
}

EDIT1 : if you are trying to get image path of file in external sdcard in higher version then check my question

EDIT2 Here is complete code with handling virtual files and host other than com.android.providers I have tested this method with content://com.adobe.scan.android.documents/document/

Gary Chen
  • 248
  • 2
  • 14
Jaiprakash Soni
  • 4,100
  • 5
  • 36
  • 67
  • Hi Friend, yes thats true. but this is happening because now google have a default format to upload all photos from your phone to google docs. And just save thumbinal in your phone. If you get this uri from google docs, you need download the photo before you use this. This is not good in general. So, To fix all problems here, now im using this library. (this library just use local files , and with this solution your problems will be solved) , or you can extract the code from library and improve yourself to attend your problem. https://github.com/nohana/Laevatein I hope this can help you. – luizfelipetx May 12 '16 at 12:48
  • 1+, Its work perfect for me. As @JaiprakasSoni said in his answer that i have faced same problem when i run my app in Moto G4 play but when i use above code it works fine for me. Thanks you. You save my time – Farmer Mar 23 '17 at 11:17
11

EDIT: Use this Solution here: https://stackoverflow.com/a/20559175/2033223 Works perfect!

First of, thank for your solution @luizfelipetx

I changed your solution a little bit. This works for me:

public static String getRealPathFromDocumentUri(Context context, Uri uri){
    String filePath = "";

    Pattern p = Pattern.compile("(\\d+)$");
    Matcher m = p.matcher(uri.toString());
    if (!m.find()) {
        Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString());
        return filePath;
    }
    String imgId = m.group();

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            column, sel, new String[]{ imgId }, null);

    int columnIndex = cursor.getColumnIndex(column[0]);

    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }
    cursor.close();

    return filePath;
}

Note: So we got documents and image, depending, if the image comes from 'recents', 'gallery' or what ever. So I extract the image ID first before looking it up.

Community
  • 1
  • 1
Javatar
  • 2,518
  • 1
  • 31
  • 43
9

One easy and best method copy file to the real path and then get their path I checked it 10 devices on android API-16 to API-30 working fine.

@Nullable
public static String createCopyAndReturnRealPath(
       @NonNull Context context, @NonNull Uri uri) {
    final ContentResolver contentResolver = context.getContentResolver();
    if (contentResolver == null)
        return null;

    // Create file path inside app's data dir
    String filePath = context.getApplicationInfo().dataDir + File.separator + "temp_file";
    File file = new File(filePath);
    try {
        InputStream inputStream = contentResolver.openInputStream(uri);
        if (inputStream == null)
            return null;
        OutputStream outputStream = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int len;
        while ((len = inputStream.read(buf)) > 0)
            outputStream.write(buf, 0, len);
        outputStream.close();
        inputStream.close();
    } catch (IOException ignore) {
        return null;
    }
    return file.getAbsolutePath();
}
Attaullah
  • 3,856
  • 3
  • 48
  • 63
  • 1
    EASILY the best solution there is. Absolutely perfect for my use case where I need to get the path for a small file. No need for an file picking library or some other complicated solution to getting the real path. Best part is, it worked on all my devices. Thanks for sharing – DIRTY DAVE Nov 07 '21 at 20:18
  • for some reason, when I used this, the file is not created on the app folder and then I get it does not exist – Yakir Malka Jan 02 '22 at 11:41
  • @YakirMalka created with the name of temp_file but with no extension like jpg, png .... etc – Attaullah Jan 03 '22 at 03:49
  • Yeah figured it out yesterday :) thanks! – Yakir Malka Jan 03 '22 at 08:36
1

Hii here is my complete code for taking image from camera or galeery

//My variable declaration

protected static final int CAMERA_REQUEST = 0;
    protected static final int GALLERY_REQUEST = 1;
    Bitmap bitmap;
    Uri uri;
    Intent picIntent = null;

//Onclick

if (v.getId()==R.id.image_id){
            startDilog();
        }

//method body

private void startDilog() {
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this);
    myAlertDilog.setTitle("Upload picture option..");
    myAlertDilog.setMessage("Where to upload picture????");
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(Intent.ACTION_GET_CONTENT,null);
            picIntent.setType("image/*");
            picIntent.putExtra("return_data",true);
            startActivityForResult(picIntent,GALLERY_REQUEST);
        }
    });
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(picIntent,CAMERA_REQUEST);
        }
    });
    myAlertDilog.show();
}

//And rest of things

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==GALLERY_REQUEST){
        if (resultCode==RESULT_OK){
            if (data!=null) {
                uri = data.getData();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                try {
                    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    options.inSampleSize = calculateInSampleSize(options, 100, 100);
                    options.inJustDecodeBounds = false;
                    Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    imageofpic.setImageBitmap(image);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        }else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            if (data.hasExtra("data")) {
                bitmap = (Bitmap) data.getExtras().get("data");
                uri = getImageUri(YourActivity.this,bitmap);
                File finalFile = new File(getRealPathFromUri(uri));
                imageofpic.setImageBitmap(bitmap);
            } else if (data.getExtras() == null) {

                Toast.makeText(getApplicationContext(),
                        "No extras to retrieve!", Toast.LENGTH_SHORT)
                        .show();

                BitmapDrawable thumbnail = new BitmapDrawable(
                        getResources(), data.getData().getPath());
                pet_pic.setImageDrawable(thumbnail);

            }

        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private String getRealPathFromUri(Uri tempUri) {
    Cursor cursor = null;
    try {
        String[] proj = { MediaStore.Images.Media.DATA };
        cursor = this.getContentResolver().query(tempUri,  proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);
}
Tanmay Sahoo
  • 471
  • 1
  • 6
  • 16
  • How you know is 100 in this line `options.inSampleSize = calculateInSampleSize(options, 100, 100);` – John Joe Jan 11 '17 at 09:22
1

This helped me to get uri from Gallery and convert to a file for Multipart upload

File file = FileUtils.getFile(this, fileUri);

https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java

Veeresh Charantimath
  • 4,641
  • 5
  • 27
  • 36
1

This code work for me in android 11 and 12

private static String getRealPathFromURI(Uri uri, Context context) {
                Uri returnUri = uri;
                Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
                int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                returnCursor.moveToFirst();
                String name = (returnCursor.getString(nameIndex));
                String size = (Long.toString(returnCursor.getLong(sizeIndex)));
                File file = new File(context.getFilesDir(), name);
                try {
                    InputStream inputStream = context.getContentResolver().openInputStream(uri);
                    FileOutputStream outputStream = new FileOutputStream(file);
                    int read = 0;
                    int maxBufferSize = 1 * 1024 * 1024;
                    int bytesAvailable = inputStream.available();
        
                    //int bufferSize = 1024;
                    int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        
                    final byte[] buffers = new byte[bufferSize];
                    while ((read = inputStream.read(buffers)) != -1) {
                        outputStream.write(buffers, 0, read);
                    }
                    Log.e("File Size", "Size " + file.length());
                    inputStream.close();
                    outputStream.close();
                    Log.e("File Path", "Path " + file.getPath());
                    Log.e("File Size", "Size " + file.length());
                } catch (Exception e) {
                    Log.e("Exception", e.getMessage());
                }
                return file.getPath();
            }
shubomb
  • 672
  • 7
  • 20