Skip to content

Instantly share code, notes, and snippets.

@Mariovc
Last active February 7, 2024 23:33
Show Gist options
  • Save Mariovc/f06e70ebe8ca52fbbbe2 to your computer and use it in GitHub Desktop.
Save Mariovc/f06e70ebe8ca52fbbbe2 to your computer and use it in GitHub Desktop.
Utility for picking an image from Gallery/Camera with Android Intents
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
/**
* Author: Mario Velasco Casquero
* Date: 08/09/2015
* Email: m3ario@gmail.com
*/
public class ImagePicker {
private static final int DEFAULT_MIN_WIDTH_QUALITY = 400; // min pixels
private static final String TAG = "ImagePicker";
private static final String TEMP_IMAGE_NAME = "tempImage";
public static int minWidthQuality = DEFAULT_MIN_WIDTH_QUALITY;
public static Intent getPickImageIntent(Context context) {
Intent chooserIntent = null;
List<Intent> intentList = new ArrayList<>();
Intent pickIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePhotoIntent.putExtra("return-data", true);
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context)));
intentList = addIntentsToList(context, intentList, pickIntent);
intentList = addIntentsToList(context, intentList, takePhotoIntent);
if (intentList.size() > 0) {
chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
context.getString(R.string.pick_image_intent_text));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
}
return chooserIntent;
}
private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resInfo) {
String packageName = resolveInfo.activityInfo.packageName;
Intent targetedIntent = new Intent(intent);
targetedIntent.setPackage(packageName);
list.add(targetedIntent);
Log.d(TAG, "Intent: " + intent.getAction() + " package: " + packageName);
}
return list;
}
public static Bitmap getImageFromResult(Context context, int resultCode,
Intent imageReturnedIntent) {
Log.d(TAG, "getImageFromResult, resultCode: " + resultCode);
Bitmap bm = null;
File imageFile = getTempFile(context);
if (resultCode == Activity.RESULT_OK) {
Uri selectedImage;
boolean isCamera = (imageReturnedIntent == null ||
imageReturnedIntent.getData() == null ||
imageReturnedIntent.getData().toString().contains(imageFile.toString()));
if (isCamera) { /** CAMERA **/
selectedImage = Uri.fromFile(imageFile);
} else { /** ALBUM **/
selectedImage = imageReturnedIntent.getData();
}
Log.d(TAG, "selectedImage: " + selectedImage);
bm = getImageResized(context, selectedImage);
int rotation = getRotation(context, selectedImage, isCamera);
bm = rotate(bm, rotation);
}
return bm;
}
private static File getTempFile(Context context) {
File imageFile = new File(context.getExternalCacheDir(), TEMP_IMAGE_NAME);
imageFile.getParentFile().mkdirs();
return imageFile;
}
private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
AssetFileDescriptor fileDescriptor = null;
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap actuallyUsableBitmap = BitmapFactory.decodeFileDescriptor(
fileDescriptor.getFileDescriptor(), null, options);
Log.d(TAG, options.inSampleSize + " sample method bitmap ... " +
actuallyUsableBitmap.getWidth() + " " + actuallyUsableBitmap.getHeight());
return actuallyUsableBitmap;
}
/**
* Resize to avoid using too much memory loading big images (e.g.: 2560*1920)
**/
private static Bitmap getImageResized(Context context, Uri selectedImage) {
Bitmap bm = null;
int[] sampleSizes = new int[]{5, 3, 2, 1};
int i = 0;
do {
bm = decodeBitmap(context, selectedImage, sampleSizes[i]);
Log.d(TAG, "resizer: new bitmap width = " + bm.getWidth());
i++;
} while (bm.getWidth() < minWidthQuality && i < sampleSizes.length);
return bm;
}
private static int getRotation(Context context, Uri imageUri, boolean isCamera) {
int rotation;
if (isCamera) {
rotation = getRotationFromCamera(context, imageUri);
} else {
rotation = getRotationFromGallery(context, imageUri);
}
Log.d(TAG, "Image rotation: " + rotation);
return rotation;
}
private static int getRotationFromCamera(Context context, Uri imageFile) {
int rotate = 0;
try {
context.getContentResolver().notifyChange(imageFile, null);
ExifInterface exif = new ExifInterface(imageFile.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
return rotate;
}
public static int getRotationFromGallery(Context context, Uri imageUri) {
int result = 0;
String[] columns = {MediaStore.Images.Media.ORIENTATION};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int orientationColumnIndex = cursor.getColumnIndex(columns[0]);
result = cursor.getInt(orientationColumnIndex);
}
} catch (Exception e) {
//Do nothing
} finally {
if (cursor != null) {
cursor.close();
}
}//End of try-catch block
return result;
}
private static Bitmap rotate(Bitmap bm, int rotation) {
if (rotation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
Bitmap bmOut = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
return bmOut;
}
return bm;
}
}
public class SimpleActivity {
private static final int PICK_IMAGE_ID = 234; // the number doesn't matter
public void onPickImage(View view) {
Intent chooseImageIntent = ImagePicker.getPickImageIntent(this);
startActivityForResult(chooseImageIntent, PICK_IMAGE_ID);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case PICK_IMAGE_ID:
Bitmap bitmap = ImagePicker.getImageFromResult(this, resultCode, data);
// TODO use bitmap
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@Mariovc
Copy link
Author

Mariovc commented Jul 27, 2016

I have made a Github lib with this code and a sample app. You can visit it here

@KarWL
Copy link

KarWL commented Aug 10, 2016

Hi Mariovc, thanks for the code. It help a lot. Never thought intent can do so much. (New in android mobile application development. apologize if that sounds silly)

@Mariovc
Copy link
Author

Mariovc commented Aug 11, 2016

@KarWL Your comment helps me too. Thanks! Star the gist if you liked it, and keep learning!

@ocampogeric
Copy link

Hello Mariovc, thanks so much, its work perfect. :)

@Thialyson
Copy link

Thanks!

@Gisse
Copy link

Gisse commented Sep 17, 2016

Brilliant, just brilliant

@WilliamSpruyt
Copy link

This is great very classy.

@shihabmi7
Copy link

shihabmi7 commented Jan 7, 2017

How to get File Name from this class in Activity from intent?

@suleman-siddique
Copy link

hey bro can you tell me the value of constant string that u r using in intent.chooser function i.e R.string.pick_image_intent_text
????????

@bpratapsingh
Copy link

@suleman You can use any value you want to show the title of intent like 'Select Image'.

@surveshoeb
Copy link

Thanx dude it works!!!!!

@Zaniyar
Copy link

Zaniyar commented May 30, 2017

I wanted to have dynamic file names for each image.

public Intent getPickImageIntent(Context context) {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        imageName = "Selfie_" + timeStamp + "_.jpg";
        Intent chooserIntent = null;
        //...
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context,imageName)));
        //...

and in the getImageFromResult() I have right after the if(isCamera)else part:

            setImageFile(imageFile);

In my MainActivity I have a Button, which I use to upload my image to the server.

  File file = imagePicker.getImageFile();
  //file that should be uploaded

This works for the Image created by the Camera, but not the images selected from the Gallery.

E/Upload error:: /storage/emulated/0/Android/data/me.acme.myApp/cache/Selfie_20170530_032715_.jpg: open failed: ENOENT (No such file or directory)

How can I achieve that the upload button can find the original image from the gallery but upload it under the new generated name?

@JosueCarrillo
Copy link

Can someone help me please, i'm triying to use this library to set and image into a Cardview inside a RecyclerView.Adapter how can this been done with the onActivityResult. Cheers

@caneryilmaz
Copy link

caneryilmaz commented Aug 14, 2017

thx for your effort but i think could use static instance and public method to singleton structure.Have good job :)

@Coder1121
Copy link

Thanx alot for this code snippet however i was facing two issues
one of them was on saving picture from camera my activities were destroying and app was crashing but i fixed it by adding android:configChanges="orientation|screenSize"in my menifest file and the other issue for which i am still looking for solution is that when i click on imageview to call onPickImage and then pressback or cancel it my imageview disappears.

@kawnayeen
Copy link

Thanks for your complete guideline. I've created an android library from this example for easy integration with existing project.

I've added method to get the image file also for uploading at server.

@AppHero2
Copy link

AppHero2 commented Oct 3, 2017

How come it returns null data as result for camera? I have tested 2 devices LG (21), Sumsung (21)

@avierose
Copy link

Works perfectly for up to API 23, but API 24 and up when selecting the camera option from the chooser, instead of opening the camera it returns to the activity and fills the imageView with white space.

Does anyone know how to get around this?

Tried it on both emulator and physical device running 7.0

@nathan-mersha
Copy link

Thank you for a beautiful code.

@saddahussain
Copy link

Does not work on Android Kitkat

@MakFCT
Copy link

MakFCT commented Jul 9, 2018

Hello, when i use the camera option my data from the "Bitmap bitmap = ImagePicker.getImageFromResult(this, resultCode, data);" comes null any idea why? Been debugging for hours can't figure out why.
Thanks for the awesome code so helpful!!

@jiya250
Copy link

jiya250 commented Oct 1, 2018

Worked like charm.
I added permission check for camera because on API lower than 23,my app had crashed.
And modified....

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult( requestCode, resultCode, data );

    if (requestCode == PICK_IMAGE_ID && resultCode == RESULT_OK){
        //Bundle bundle = data.getExtras();
        Bitmap bitmap = ImagePicker.getImageFromResult(this, resultCode, data);
        circleImageView.setImageBitmap(bitmap);

    }
    else{
   //To get image captured by camera
        Bundle bundle = data.getExtras();
        bitmap = (Bitmap) bundle.get("data");
        circleImageView.setImageBitmap(bitmap);
    }

}

@imran-samed
Copy link

imran-samed commented Oct 12, 2018

what if i want an uri onActivityResult
and not able to pick full size image in lollipop

@var2611
Copy link

var2611 commented Oct 26, 2018

Update with file please use following changes,


public static Intent getPickImageIntent(Context context) {
        Intent chooserIntent = null;

        List<Intent> intentList = new ArrayList<>();

        Intent pickIntent = new Intent(Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intentList = addIntentsToList(context, intentList, pickIntent);
        intentList = addIntentsToList(context, intentList, takePhotoIntent);

        if (intentList.size() > 0) {
            chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
                    "Select Image");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
        }

        return chooserIntent;
    }

public static Bitmap getImageFromResult(Context context, int resultCode,
                                            Intent intentData) {
        Log.d(TAG, "getImageFromResult, resultCode: " + resultCode);
        Bitmap bm = null;
        if (resultCode == Activity.RESULT_OK) {
            Uri selectedImage;
            boolean isCamera = (intentData == null || intentData.getData() == null);
            if (isCamera) {     /** CAMERA **/
                bm = (Bitmap) intentData.getExtras().get("data");
                String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), bm, "Image123", null);
                selectedImage = Uri.parse(path);
            } else {            /** ALBUM **/
                selectedImage = intentData.getData();
            }
            Log.d(TAG, "selectedImage: " + selectedImage);

            bm = getImageResized(context, selectedImage);
            int rotation = getRotation(context, selectedImage, isCamera);
            bm = rotate(bm, rotation);
        }
        return bm;
    }

Use Of Intent same as describe :

Intent intent = ImagePicker.getPickImageIntent(MainActivity.this); startActivityForResult(intent, 999);

On ActWithResult :
bitmap = ImagePicker.getImageFromResult(this, resultCode, data);

@var2611
Copy link

var2611 commented Oct 27, 2018

Works perfectly for up to API 23, but API 24 and up when selecting the camera option from the chooser, instead of opening the camera it returns to the activity and fills the imageView with white space.

Does anyone know how to get around this?

Tried it on both emulator and physical device running 7.0

Try this https://gist.github.com/Mariovc/f06e70ebe8ca52fbbbe2#gistcomment-1593066

@var2611
Copy link

var2611 commented Oct 27, 2018

what if i want an uri onActivityResult
and not able to pick full size image in lollipop

Check out my solution I solved it. https://gist.github.com/Mariovc/f06e70ebe8ca52fbbbe2#gistcomment-1593066

@mahmudinm
Copy link

i got blurred image on when i set on imgThumbnail ? how to fixed it ?

@arifrahman2592
Copy link

Hi mario,

I got a problem, my application crash on Samsung A6, get this message

D/ImagePicker: Intent: android.intent.action.PICK package: com.sec.android.gallery3d
D/ImagePicker: Intent: android.intent.action.PICK package: com.google.android.apps.photos
D/ImagePicker: Intent: android.media.action.IMAGE_CAPTURE package: com.sec.android.app.camera
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.arif.celmira, PID: 32369
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.example.arif.celmira/cache/tempImage exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1958)
at android.net.Uri.checkFileUriExposed(Uri.java:2356)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:944)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10492)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10498)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10477)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1616)
at android.app.Activity.startActivityForResult(Activity.java:4564)
at android.support.v4.app.BaseFragmentActivityApi16.startActivityForResult(BaseFragmentActivityApi16.java:54)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:68)
at android.app.Activity.startActivityForResult(Activity.java:4522)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:751)
at com.example.arif.celmira.Kirimpembayaran.showFileChooser(Kirimpembayaran.java:186)
at com.example.arif.celmira.Kirimpembayaran.access$100(Kirimpembayaran.java:31)
at com.example.arif.celmira.Kirimpembayaran$2.onClick(Kirimpembayaran.java:112)
at android.view.View.performClick(View.java:6909)
at android.widget.TextView.performClick(TextView.java:12693)
at android.view.View$PerformClick.run(View.java:26200)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Application terminated.

@K01egA
Copy link

K01egA commented May 28, 2019

Add code for Android 8.1:

    public static Intent getPickImageIntent(Context context) {
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
        Intent chooserIntent = null;

https://stackoverflow.com/questions/48117511/exposed-beyond-app-through-clipdata-item-geturi

@nutechmobile
Copy link

WHY are you removing an item from the intent list after having added it??? Doesnt that defeat the purpose???

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment