Skip to content

Instantly share code, notes, and snippets.

@Mariovc
Last active April 27, 2022 14:29
Show Gist options
  • Save Mariovc/cedb5f4372510f7c39f1 to your computer and use it in GitHub Desktop.
Save Mariovc/cedb5f4372510f7c39f1 to your computer and use it in GitHub Desktop.
[Android] Advanced utility for picking an image from Gallery/Camera with Android Intents (Crop included)
...
dependencies {
...
compile 'com.soundcloud.android:android-crop:1.0.1@aar'
}
...
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.widget.Toast;
import com.soundcloud.android.crop.Crop;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
/**
* Author: Mario Velasco Casquero
* Date: 08/09/2015
*/
public class ImagePicker {
public static final int REQUEST_PICK = Crop.REQUEST_PICK;
public static final int REQUEST_CROP = Crop.REQUEST_CROP;
public static final int DEFAULT_MIN_WIDTH_QUALITY = 400; // min pixels
private static final String TAG = "ImagePicker";
private static final String TEMP_IMAGE_NAME = "tempImage";
private static final String CROPPED_IMAGE_NAME = "croppedImage";
private static boolean isCamera;
private static Uri selectedImage;
public enum ResizeType {
MIN_QUALITY, FIXED_SIZE
}
public static void pickImage(Activity activity) {
Intent intent = getPickImageIntent(activity);
activity.startActivityForResult(intent, REQUEST_PICK);
}
private 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);
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 void beginCrop(Activity activity, int resultCode, Intent imageReturnedIntent) {
Uri selectedImage = getImageUri(activity, resultCode, imageReturnedIntent);
if (selectedImage != null) {
Uri destination = Uri.fromFile(new File(activity.getExternalCacheDir(), CROPPED_IMAGE_NAME));
Crop.of(selectedImage, destination).asSquare().start(activity);
}
}
private static Uri getImageUri(Activity activity, int resultCode, Intent imageReturnedIntent) {
Log.d(TAG, "getImageUri, resultCode: " + resultCode);
File imageFile = getTempFile(activity);
if (resultCode == Activity.RESULT_OK) {
+ isCamera = (imageReturnedIntent == null ||
+ imageReturnedIntent.getData() == null ||
+ imageReturnedIntent.getData().equals(Uri.fromFile(imageFile)));
if (isCamera) { /** CAMERA **/
selectedImage = Uri.fromFile(imageFile);
} else { /** ALBUM **/
selectedImage = imageReturnedIntent.getData();
}
Log.d(TAG, "selectedImage: " + selectedImage);
}
return selectedImage;
}
public static Bitmap getImageCropped(Activity activity, int resultCode, Intent result,
ResizeType resizeType, int size) {
Bitmap bm = null;
if (resultCode == Activity.RESULT_OK) {
Uri croppedImageUri = Crop.getOutput(result);
bm = getImageResized(activity, croppedImageUri, resizeType, size);
int rotation = getRotation(activity, selectedImage, isCamera);
bm = rotate(bm, rotation);
} else if (resultCode == Crop.RESULT_ERROR) {
Toast.makeText(activity, Crop.getError(result).getMessage(), Toast.LENGTH_SHORT).show();
}
return bm;
}
private static File getTempFile(Context context) {
File imageFile = new File(context.getExternalCacheDir(), TEMP_IMAGE_NAME);
imageFile.getParentFile().mkdirs();
return imageFile;
}
/**
* Resize to avoid using too much memory loading big images (e.g.: 2560*1920)
**/
private static Bitmap getImageResized(Context context, Uri selectedImage,
ResizeType resizeType, int size) {
Bitmap bm;
int[] sampleSizes = new int[]{5, 3, 2, 1};
int i = 0;
do {
bm = decodeBitmap(context, selectedImage, sampleSizes[i]);
Log.d(TAG, "Resizer: sample " + sampleSizes[i] + ", new bitmap width=" +
bm.getWidth() + " height=" + bm.getHeight());
i++;
} while (bm.getWidth() < size && i < sampleSizes.length);
if (resizeType == ResizeType.FIXED_SIZE) {
bm = Bitmap.createScaledBitmap(bm, size, size, true);
}
Log.d(TAG, "Resizer: finalSize, width=" + bm.getWidth() + " height=" + bm.getHeight());
return bm;
}
private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) {
Bitmap actuallyUsableBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
AssetFileDescriptor fileDescriptor = null;
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
if (fileDescriptor != null) {
actuallyUsableBitmap = BitmapFactory.decodeFileDescriptor(
fileDescriptor.getFileDescriptor(), null, options);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return actuallyUsableBitmap;
}
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) {
String[] columns = {MediaStore.Images.Media.ORIENTATION};
Cursor cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
if (cursor == null) return 0;
cursor.moveToFirst();
int orientationColumnIndex = cursor.getColumnIndex(columns[0]);
return cursor.getInt(orientationColumnIndex);
}
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 MainActivity {
public void pickImage() {
ImagePicker.pickImage(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == ImagePicker.REQUEST_PICK) {
ImagePicker.beginCrop(this, resultCode, data);
} else if (requestCode == ImagePicker.REQUEST_CROP) {
Bitmap bitmap = ImagePicker.getImageCropped(this, resultCode, data,
ImagePicker.ResizeType.FIXED_SIZE, AVATAR_SIZE);
if (imagePickerListener != null) {
imagePickerListener.onImagePicked(bitmap);
}
Log.d(this, "bitmap picked: " + bitmap);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
</manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
...
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
</application>
</manifest>
<style name="AppTheme" parent="Base.AppTheme">
<item name="cropImageStyle">@style/Widget.CropImageView</item>
</style>
<style name="Widget.CropImageView" parent="android:Widget">
<item name="showThirds">false</item>
<item name="showCircle">true</item>
<item name="showHandles">always</item>
<item name="highlightColor">?attr/colorAccent</item>
</style>
@drewlarsen
Copy link

Great, very helpful! Can I suggest adding a public method that supports calling your ImagePicker from a Fragment:

public static void pickImage(Activity activity, Fragment fragment) {
    Intent intent = getPickImageIntent(activity);
    fragment.startActivityForResult(intent, REQUEST_PICK);
}

@cristinaITdeveloper
Copy link

Hi! I used your class in fragment but after crop image, onActivityResult not called, I cannot set my ImageView with image

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK && requestCode == ImagePicker.REQUEST_PICK) {
            ImagePicker.beginCrop((LoginActivity)context, resultCode, data);
        }
        else if (requestCode == ImagePicker.REQUEST_CROP) {
            Bitmap bitmap = ImagePicker.getImageCropped((LoginActivity)context, resultCode, data,
                    ImagePicker.ResizeType.FIXED_SIZE, 100);
            this.profileImageView.setImageBitmap(bitmap);
            Log.d("IMAGE PICKER", "bitmap picked: " + bitmap);
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

Where I'm wrong?
Thank you

@Nicollas21
Copy link

Hi LadyDeveloper, for you do this , you need the beginCrop receive Context and YourFragment , as follows:

@Override 
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK && requestCode == ImagePicker.REQUEST_PICK) {
            ImagePicker.beginCrop(YourFragment, context, resultCode, data);
        }
        else if (requestCode == ImagePicker.REQUEST_CROP) {
            Bitmap bitmap = ImagePicker.getImageCropped((LoginActivity)context, resultCode, data,
                    ImagePicker.ResizeType.FIXED_SIZE, 100);
            this.profileImageView.setImageBitmap(bitmap);
            Log.d("IMAGE PICKER", "bitmap picked: " + bitmap);
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

In beginCrop method, you have to change the start method of Crop.of , and pass parameters of context and his Fragment.

public static void beginCrop(Fragment fragment, Context context, int resultCode, Intent imageReturnedIntent) {
        Uri selectedImage = getImageUri(context, resultCode, imageReturnedIntent);
        if (selectedImage != null) {
            Uri destination = Uri.fromFile(new File(context.getExternalCacheDir(), CROPPED_IMAGE_NAME));
            Crop.of(selectedImage, destination).asSquare().start(context, fragment);
        }
    }

 Hope Helpful. 

@Jeevuz
Copy link

Jeevuz commented Mar 2, 2016

Thank you for the gist! Very helpful.

@suleman-siddique
Copy link

Hey bro can you please tell me the type of imagePickerListener in if check of onActivityForResults in activity? and where we declare this variable?

@FahimaGold
Copy link

FahimaGold commented Apr 10, 2019

Hi, nice work.However, got "TransactionTooLargeException" in oreo when, any idea how to fix it?, this issue shows up when I click a button to show the image picker dialog

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