0

I simply CANNOT get the path to an image chosen from the gallery thats on the SD card, but there is no problem with images stored on the device. There are dozens of similar or duplicate questions like this, but none of them are working.

The most recommended approach (by @Commonsware) is to use a ContentResolver and call openInputStream(), so I tried reading the bytes from openInputStream() then creating a temp file and using that path, no luck. My "bytes read: " System.err.println call shows 0 bytes read.

I also tried this, this, this, this, this, and this, none work. A lot of these answers lead to calling BitmapFactory#decodeStream(), problem is, I couldn't care less about displaying the image, I JUST NEED THE PATH!!.

Please Help!

Code so far:

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    if(resultCode == Activity.RESULT_OK){

        switch(requestCode){

            case SELECT_FROM_GALLERY:
                fromGallery = true;
                path = getRealPathFromURI(data.getData());
                System.err.println("*******path: " + path + "*********");

                break;

        }

    }

}

public String getRealPathFromURI(Uri contentUri) {
    String thePath = null;
    String[] filePathColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContext().getContentResolver().query(contentUri, filePathColumn, null, null, null);
    if(cursor.moveToFirst()){
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        thePath = cursor.getString(columnIndex);
    }
    cursor.close();

    if(thePath == null){
        return getImagePathExternal(contentUri);
    }else {
        return thePath;
    }
}

public String getImagePathExternal(Uri uri){
    Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null);
    cursor.moveToFirst();
    String document_id = cursor.getString(0);
    document_id = document_id.substring(document_id.lastIndexOf(":")+1);
    cursor.close();

    cursor = getContext().getContentResolver().query(
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
    cursor.moveToFirst();
    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    cursor.close();

    if(path == null){

        System.err.println("****************trying bytes route******************");
        try{

            InputStream in = getContext().getContentResolver().openInputStream(uri);

            byte[] resultBuff = new byte[0];
            byte[] buff = new byte[1024];
            int k ;
            while((k = in.read(buff, 0, buff.length)) > -1) {
                byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
                System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
                System.arraycopy(buff, 0, tbuff, resultBuff.length, k);  // copy current lot
                resultBuff = tbuff; // call the temp buffer as your result buff
            }

            System.err.println("****************bytes read: "+resultBuff.length+" ******************");

            File tem = new File(_tempImageDir, "temp.jpg");

            FileOutputStream out = new FileOutputStream(tem);

            out.write(resultBuff, 0, resultBuff.length);

            return tem.getAbsolutePath();

        }catch(Exception e){
            e.printStackTrace();
            return null;
        }

    }

    return path;
}

Logcat(this exception never changes, no matter which approach I use):

E/AndroidRuntime: FATAL EXCEPTION: main
                                                                  Process: com.venon.nakomangsp, PID: 20610
                                                                  java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=132074, result=-1, data=Intent { dat=content://media/external/images/media/4147 (has extras) }} to activity {com.venon.nakomangsp/com.venon.nakomangsp.SignUpActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
                                                                      at android.app.ActivityThread.deliverResults(ActivityThread.java:4058)
                                                                      at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101)
                                                                      at android.app.ActivityThread.access$1400(ActivityThread.java:177)
                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                      at android.os.Looper.loop(Looper.java:145)
                                                                      at android.app.ActivityThread.main(ActivityThread.java:5942)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at java.lang.reflect.Method.invoke(Method.java:372)
                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
                                                                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
                                                                      at id.zelory.compressor.ImageUtil.getScaledBitmap(ImageUtil.java:62)
                                                                      at id.zelory.compressor.ImageUtil.compressImage(ImageUtil.java:161)
                                                                      at id.zelory.compressor.Compressor.compressToFile(Compressor.java:48)
                                                                      at com.venon.nakomangsp.SignUpFragment.preparePicture(SignUpFragment.java:870)
                                                                      at com.venon.nakomangsp.SignUpFragment.onActivityResult(SignUpFragment.java:783)
                                                                      at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
                                                                      at com.venon.nakomangsp.SignUpActivity.onActivityResult(SignUpActivity.java:37)
                                                                      at android.app.Activity.dispatchActivityResult(Activity.java:6549)
                                                                      at android.app.ActivityThread.deliverResults(ActivityThread.java:4054)
                                                                      at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101) 
                                                                      at android.app.ActivityThread.access$1400(ActivityThread.java:177) 
                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497) 
                                                                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                      at android.os.Looper.loop(Looper.java:145) 
                                                                      at android.app.ActivityThread.main(ActivityThread.java:5942) 
                                                                      at java.lang.reflect.Method.invoke(Native Method) 
                                                                      at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) 
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 
Community
  • 1
  • 1
BiGGZ
  • 503
  • 4
  • 17
  • There is no path. Why do you want a path? – ianhanniballake Apr 07 '17 at 03:49
  • There is no path to the image in the gallery? That cant be because if i select an image thats NOT on the sd card, i get a path. I need it to make a compressed version of the image and send it to my server – BiGGZ Apr 07 '17 at 03:50
  • You don't need a path to call [compress()](https://developer.android.com/reference/android/graphics/Bitmap.html#compress(android.graphics.Bitmap.CompressFormat,%20int,%20java.io.OutputStream)) on a Bitmap created by [BitmapFactory.decodeStream()](https://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeStream(java.io.InputStream)). What makes you think you need a path to do that? – ianhanniballake Apr 07 '17 at 03:53
  • means you want to path of image which is choosen from gallery [SD Card]...??? – Sagar Aghara Apr 07 '17 at 03:59
  • @ianhanniballake im not using that for compression, Im using a custom library that requires a path to compress. – BiGGZ Apr 07 '17 at 04:02
  • @SagarAghara yes sir – BiGGZ Apr 07 '17 at 04:02
  • hey are you there...i think...i can help you..tell me if you want..i post my Code here.tell me if it helps you – Sagar Aghara Apr 07 '17 at 04:03
  • @SagarAghara yes sir, still here – BiGGZ Apr 07 '17 at 04:04
  • you open your Gallery using Intent()..and choose image from there...? – Sagar Aghara Apr 07 '17 at 04:07

3 Answers3

2

Apps do not have direct file access to any of the contents of the SD card. Therefore even if you could get a 'path' of some sort, your app would not have the ability to read anything from that location.

The only way to reliably access the contents of these files is through ContentResolver.openInputStream() (or the other open methods if you need an AssetFileDescriptor, etc).

You can most definitely copy the file to your own cache directory and then do whatever you want with the image.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Can that file be copied without getting it's path? – Waqas Ahmed Ansari Apr 07 '17 at 04:31
  • 1
    @WaqasAhmedAnsari - sure, you `openInputStream()` and write it to a `FileOutputStream`. No path needed. – ianhanniballake Apr 07 '17 at 04:50
  • I see. Some weird behaviour just occurred. I deleted all the pics from the device and left just the ones on the sd card, then took one picture from outside my app and saved it to the device, and viola...everything is working as expected.I selected a picture from both locations and managed to get the path without using openInputStream. do you have any clue as to why that could have occured? – BiGGZ Apr 07 '17 at 04:50
  • i wrapped the code in a try-catch block and have the openInputStream route as a fallback because i doubt it will work on other android versions – BiGGZ Apr 07 '17 at 04:52
  • Since the `openInputStream` does work on any `content://` Uri (like those from the SD card) or `file://` Uri, I'd just use that and skip the hacks. – ianhanniballake Apr 07 '17 at 04:54
1

If you are using API 24, then you should use FileProvide, the official website of the introduction: https: //developer.android.com/reference/android/support/v4/content/FileProvider.html You should write like this:

  1. Specify a the contents of the storage area and path in XML, using child elements of the element. For example , The following pathsmann tells FileProvider that you intend to request content URIs for the images / subdirectory of your private file area.

    <Manifest>
        <Application>
            <Provider
                Android: name = "android.support.v4.content.FileProvider"
                Android: authorities = "com.mydomain.fileprovider"
                Android: exported = "false"
                Android: grantUriPermissions = "true"
               <Meta-data
               Android: name = "android.support.FILE_PROVIDER_PATHS"
               Android: resource = "@ xml / file_paths" />
            </ Provider>
        </ Application>
    </ Manifest>
    
    
    <? Xml version = "1.0" encoding = "utf-8"?>
    <Resources>
        <Paths>
            <External-path
                Name = "external_files"
                Path = "." />
            <Root-path
                Name = "external_files"
                Path = "/ storage /" />
        </ Paths> `enter code here`
    </ Resources>
    
  2. The third step: file is your path

    Uri contentUri = getUriForFile (getContext (), getPackageName () + ".provider", file);
    
Mr Lister
  • 45,515
  • 15
  • 108
  • 150
李胜辉
  • 11
  • 3
0

There are some different behaviors possessed by different phones. After a lot of research and trying different possibilities, I came up with a solution which is working on all phones on which I tested it (LG G2, Nexus 5, ZTE, Note 5, Nexus 6, Infinix Note 3 Pro and some others I don't remember). Try this if it works. Take according to your needs. It also includes capturing picture from camera, copy it and getting it's path.

//SELECT PICTURE FROM GALLERY OR CAPTURE FROM CAMERA
private void selectPicture(View view) {
    tempView = view;
    final CharSequence[] items;
    if(view.getClass().getName().equalsIgnoreCase("android.widget.ImageView"))
            items = new CharSequence[]{ "Take Photo", "Choose from Library", "Remove Photo", "Cancel" };
    else items = new CharSequence[]{ "Take Photo", "Choose from Library", "Cancel" };

    AlertDialog.Builder builder = new AlertDialog.Builder(ActivityAddMemory.this);
    builder.setTitle("Add Image");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                showCamera();
            } else if (items[item].equals("Choose from Library")) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(
                        Intent.createChooser(intent, "Select File"),
                        SELECT_FILE);
            } else if(items[item].equals("Remove Photo")) {
                imgLinearLayout.removeView(tempView);
                imagesList.remove(tempView.getId());
                if(imagesList.size() < 1) {
                    imgLinearLayout.setVisibility(View.GONE);
                }

                if(btnAddPhoto.getVisibility() == View.GONE)
                    btnAddPhoto.setVisibility(View.VISIBLE);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}


//OPEN CAMERA IF WANT TO CAPTURE
private void showCamera() {

    try {
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "DCIM");
        if (!file.exists()) {
            file.mkdirs();
        }

        File localFile2 = new File(file + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        imageUri = Uri.fromFile(localFile2);

        Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");

        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            cameraIntent.setClipData(ClipData.newRawUri(null, Uri.fromFile(localFile2)));
        }

        startActivityForResult(cameraIntent, REQUEST_CAMERA);
    } catch (Exception localException) {
        Toast.makeText(ActivityAddMemory.this, "Exception:" + localException, Toast.LENGTH_SHORT).show();
    }
}


//GET PATH FROM URI IF SELECTED FROM GALLERY
public String getRealPathFromURI(Uri uri){
    String filePath = "";
    String[] filePahColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(uri, filePahColumn, null, null, null);
    if (cursor != null) {
        if(cursor.moveToFirst()){
            int columnIndex = cursor.getColumnIndex(filePahColumn[0]);
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();
    }
    return filePath;
}


//DO WHAT YOU WANT WHEN RESULT IS RETURNED
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    if(resultCode == RESULT_OK) {

        String path=null;
        Uri uri;

        if (intent == null || intent.getData() == null)
            uri = this.imageUri;
        else
            uri = intent.getData();

        if(requestCode == SELECT_FILE) {
            path = getRealPathFromURI(uri);
        } else if(requestCode == REQUEST_CAMERA){
            path = uri.getEncodedPath();
        }

        //THIS IS THE PATH YOU WOULD NEED

    }

}
Waqas Ahmed Ansari
  • 1,683
  • 15
  • 30