Losing a lot of quality on image crop - android

I'm capturing an image from camera and then saving it do sqlite database.
After that I allow user to crop it. After the whole process quality is very very poor.
I'm testing it on Nexus7 and I know it's front camera is poor but right after crop app opens, the picture is very small. It takes like 1/5 of s creen in the crop activity and I don't know why.
This what happens onActivityResult (capturing taken picture)
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
String path = Images.Media.insertImage(getActivity().getContentResolver(), bitmap, "Title", null);
Uri imageUri = Uri.parse(path);
if (!doCrop(imageUri)) saveNewAvatar(bitmap);
}
}
And here is doCrop(Uri uri) method:
private void doCrop(final Uri imageUri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/*");
List<ResolveInfo> list = getActivity().getPackageManager().queryIntentActivities( intent, 0 );
int size = list.size();
intent.setData(imageUri);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra("return-data", true);
if (size == 1) {
Intent i = new Intent(intent);
ResolveInfo res = list.get(0);
i.setComponent( new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
startActivityForResult(i, CROP);
}
}
After the whole process picture is very very small.
EDIT:
Did some research and followed code from this thread
Ended up with this:

There are many wrong (as in: maybe works, but that's not the way you do such things on Android) things about your code, but the source of the problem is that you read the image from the data key in extras. The version in extras is just a miniature, and it is of very low quality.
What you need to do is change the way you invoke the camera. This is slightly counter-intuitive, but you do not get the url to the picture taken from the camera, but just the opposite: pass an url to the camera and it will try and put the picture there.
The url might point to the SD card or to you own ContentProvider.

Related

Android : Get photo from gallery always returns bitmap not uri

I call:
Intent intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.INTERNAL_CONTENT_URI);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale", true);
intent.putExtra("outputX", 256);
intent.putExtra("outputY", 256);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("return-data", true);
startActivityForResult(intent, code);
then in my ActiviyResult():
if (requestCode == RESULT_LOAD_IMAGE && data != null) {
final Bundle extras = data.getExtras();
if (extras != null) {
//Get image
Bitmap profilePicBitmap = extras.getParcelable("data");
...
I try to get the uri by doing this:
data.getData()
but it always returns null
The problem is I need the path of the bitmap on the device so I can upload it elsewhere...but I can't get the path of it without having to convert it to uri. To convert to uri you have to request permission to write external storage, see here: (http://stackoverflow.com/questions/12555420/how-to-get-a-uri-object-from-bitmap) and I'd like to avoid that.
but it always returns null
That behavior will depend on the device and its apps.
I suspect that you will have better luck if you get rid of those undocumented extras. Presumably, rather than use an image-cropping library, you are trying to have the ACTION_PICK activity do the cropping. There are two problems with this:
There is no requirement for the ACTION_PICK activity to do any cropping, as those extras are not part of the Android SDK.
My guess is that since the cropped image does not exist as a file, they return it via the "data" extra (which is also outside the documented behavior of ACTION_PICK)
So, get rid of those extras. If you want to crop the image, use an image-cropping library.

Crop Intent doesn't work properly in Android

Here is my intent code for select picture and cropping from gallery.
int PICK_IMAGE_REQUEST = 100;
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_PICK);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString());
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 150);
intent.putExtra("aspectY", 150);
intent.putExtra("outputX", 150);
intent.putExtra("outputY", 150);
intent.putExtra("return-data", true);
getActivity().startActivityForResult(Intent.createChooser(intent,
"Complete using with."), PICK_IMAGE_REQUEST);
Here is my onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
int PICK_IMAGE_REQUEST = 100;
Bundle extras = null;
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK) {
extras = data.getExtras();
}
if (extras != null) {
Bitmap photo = extras.getParcelable("data");
ImageView profilePhoto = (ImageView) findViewById(R.id.profileImageView);
profilePhoto.setImageBitmap(photo);
}
These codes above crop&set image successfully. However, sometimes it doesn't work properly. I mean when I'm using 3rd party gallery app instead of using device's default gallery app. It doesn't set the image. This may be not getting file path correctly when using another gallery app. So , how can I implement select&crop and set image into imageview ? I researched on to internet but nothing solved this problem so far.
Here is my intent code for select picture and cropping from gallery.
No, that is code for selecting a picture. The various extras that you have on there are not part of the ACTION_PICK documentation, or any other official documentation, for that matter.
These codes above crop&set image successfully
Not generally.
However, sometimes it doesn't work properly. I mean when I'm using 3rd party gallery app instead of using device's default gallery app.
There are thousands of Android device models. There is no single "default gallery app" for all of them; there will be dozens, if not hundreds, of "default gallery app" implementations. None have to support the random extras that you are trying. Also, none have to return something in a data extra, as ACTION_PICK returns a Uri in the result Intent, as is covered in the documentation for ACTION_PICK.
So , how can I implement select&crop and set image into imageview ?
Get rid of the extras. Get rid of the extras.getParcelable("data") bit. Get the Uri of the picked image (data.getData()). Use that in conjunction with one of various image cropping libraries available for Android.

Choose a picture from the gallery only, not other application like Photos App

I am trying to pick an image from the Android Gallery only, not other applications like Photos, file manager etc
I need a solution to open the Gallery App directly, or is it possible to use the Photos Application to pick image?
1) Choose from gallery
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent,CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
2) onActivityResult result code
try {
// bimatp factory
BitmapFactory.Options options = new BitmapFactory.Options();
// downsizing image as it throws OutOfMemory Exception for larger images
options.inSampleSize = 2;
final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),options);
descimage.setImageBitmap(bitmap);
bitmap.compress(CompressFormat.JPEG, 80, new FileOutputStream(new File(fileUri.getPath())));
photostatus = 1;
pbar.setVisibility(View.VISIBLE);
txtbrowser.setEnabled(false);
new upload().execute();
} catch (NullPointerException e) {
e.printStackTrace();
}
You should be aware that Gallery no longer exists on some devices running Lollipop. The photos app is the replacement and it should have no problems handling the intent to select an image. Intent.ACTION_GET_CONTENT is usually recommended for selecting images, such as:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, ID);
Opening the gallery on devices that do have it installed is discussed here. Basically every different vendor may ship a different gallery app.
It is possible to launch a specific activity for an implicit intent (such as selecting an image) without showing the chooser dialog by using the PackageManager.queryIntentActivities() API to iterate all the available packages on the users device so you can explicitly launch the one you require.
This intent allows you to pick the image from the default gallery.
// in onCreate or any event where your want the user to select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
For receiving the selected image in onActivityResult()
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
}
}
}
i got the solution from here

Google Photos vs Stock Gallery - Intent Picker

In my app, I allow the user to pick a profile image from their gallery, like so:
When You click the first option, on my Android 5.0 device, I get this:
If I use the normal Gallery app that is based off the AOSP project, everything works fine and dandy. However, the Photo's app appears to use a different intent.
Here is how I handle code for the normal gallery:
Intent photoPickerIntent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra("outputX", 300);
photoPickerIntent.putExtra("outputY", 300);
photoPickerIntent.putExtra("aspectX", 1);
photoPickerIntent.putExtra("aspectY", 1);
photoPickerIntent.putExtra("scale", true);
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoPickerIntent.putExtra("outputFormat",
Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, RESULT_LOAD_IMAGE);
And then the intent result handler:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RESULT_LOAD_IMAGE
&& resultCode == Activity.RESULT_OK) {
if (data != null) {
tempFile = getTempFile();
filePath = Environment.getExternalStorageDirectory() + "/"
+ "temporary_holder.jpg";
Log.d("LOAD REQUEST filePath", filePath);
Bitmap selectedImage = BitmapFactory.decodeFile(filePath);
iPP.setImageBitmap(selectedImage);
}
imagePath = filePath;
new UploadImage().execute();
}
}
Some of the helper functions from above:
private static Uri getTempUri() {
return Uri.fromFile(getTempFile());
}
private static File getTempFile() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File file = new File(Environment.getExternalStorageDirectory(),
"temporary_holder.jpg");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
return null;
}
Some of that is probably not needed to show but I included it all in case it is interfering.
When I use Google Photos to pick a photo, my ImageView is blank (instead of filling with selected pick). The image is not selected and I can't go to the manual cropping view like I have it set with the Gallery. So basically, nothing happens.
NEW CODE IN RESPONSE TO ANSWER
photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra("outputX", 300);
photoPickerIntent.putExtra("outputY", 300);
photoPickerIntent.putExtra("aspectX", 1);
photoPickerIntent.putExtra("aspectY", 1);
photoPickerIntent.putExtra("scale", true);
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoPickerIntent.putExtra("outputFormat",
Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, RESULT_LOAD_IMAGE);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
Log.i("data", data.toString());
switch (requestCode) {
case RESULT_LOAD_IMAGE:
Log.i("RESULT_LOAD_IMAGE", "MARK");
// Received an image from the picker, now send an Intent for cropping
final String CROP_ACTION = "com.android.camera.action.CROP";
Intent photoCropIntent = new Intent(CROP_ACTION);
photoCropIntent.putExtra("crop", "true");
photoCropIntent.putExtra("aspectX", 1);
photoCropIntent.putExtra("aspectY", 1);
photoCropIntent.putExtra("outputX", 300);
photoCropIntent.putExtra("outputY", 300);
photoCropIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoCropIntent.putExtra("outputFormat",
Bitmap.CompressFormat.JPEG.toString());
photoCropIntent.setData(data.getData());
startActivityForResult(photoPickerIntent, RESULT_CROP_IMAGE);
break;
case RESULT_CROP_IMAGE:
Log.i("RESULT_CROP_IMAGE", "MARK");
tempFile = getTempFile();
imagePath = Environment.getExternalStorageDirectory() + "/" + "temporary_holder.jpg";
Log.i("imagePath", imagePath);
Uri selectedImageURI = data.getData();
InputStream image_stream;
try {
image_stream = getActivity().getContentResolver().openInputStream(selectedImageURI);
Bitmap bitmap = BitmapFactory.decodeStream(image_stream);
iPP.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
new UploadImage().execute();
break;
default:
// Handle default case
}
}
}
}
The above code isn't working either. I tried to make it resemble the answer below. What happens is:
I click "Choose from Gallery". And it does not give me a choice anymore, now it opens directly from the stock Gallery (that is not a big deal). I click on the image, and it ... appears to start the same intent over again -- it brings back the gallery wanting me to pick another image: instead of the Cropping Activity. Then after the second time, it will set my ImageView with the selected file.
Solution
First, update the photoPickerIntent to use ACTION_GET_CONTENT, and remove the extras related to cropping, since cropping will be handled by another Intent later:
Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.setType("image/*");
// Do not include the extras related to cropping here;
// this Intent is for selecting the image only.
startActivityForResult(photoPickerIntent, RESULT_LOAD_IMAGE);
Then, onActivityResult() will have to handle two results: RESULT_LOAD_IMAGE will send another intent for the crop, and RESULT_CROP_IMAGE will continue processing as you did before:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
switch (requestCode) {
case RESULT_LOAD_IMAGE:
// Received an image from the picker, now send an Intent for cropping
final String CROP_ACTION = "com.android.camera.action.CROP";
Intent photoCropIntent = new Intent(CROP_ACTION);
photoCropIntent.setData(data.getData());
// TODO: first get this running without extras, then test each one here
startActivityForResult(photoCropIntent, RESULT_CROP_IMAGE);
break;
case RESULT_CROP_IMAGE:
// Received the cropped image, continue processing. Note that this
// is just copied and pasted from your question and may have
// omissions.
tempFile = getTempFile();
filePath = Environment.getExternalStorageDirectory() + "/"
+ "temporary_holder.jpg";
Log.d("LOAD REQUEST filePath", filePath);
Bitmap selectedImage = BitmapFactory.decodeFile(filePath);
iPP.setImageBitmap(selectedImage);
imagePath = filePath;
new UploadImage().execute();
break;
default:
// Handle default case
}
}
}
Note that although I've tested parts of this code, I haven't tested this entire block of code at runtime. If it doesn't work right out-of-the-box, though, it should be pretty close. Please comment if you have any questions or issues, and I'll update my answer accordingly.
Background
On an Android 5.0.1 (API 21) device with both AOSP Gallery2 (com.android.gallery3d) and Photos installed, I ran your Intent. I was prompted to choose between Gallery or Photos.
When I chose Photos, a picker was presented, and I picked an image. I was immediately returned to my Activity, with no cropping options.
When I chose Gallery, a picker was presented, and I picked an image. I was then prompted to choose an app for cropping. Both Photos and Gallery were presented as options for cropping.
Here's the interesting log output when choosing Gallery:
// Send the Intent
3-07 15:20:10.347 719-817/? I/ActivityManager﹕ Displayed android/com.android.internal.app.ResolverActivity: +127ms
// Choose Gallery
03-07 15:20:27.762 719-735/? I/ActivityManager﹕ START u0 {act=android.intent.action.PICK typ=image/* flg=0x3000000 cmp=com.android.gallery3d/.app.GalleryActivity (has extras)} from uid 10084 on display 0
// (fixing highlighting after MIME type on previous line) */
03-07 15:20:27.814 22967-22967/? W/GalleryActivity﹕ action PICK is not supported
03-07 15:20:27.814 22967-22967/? V/StateManager﹕ startState class com.android.gallery3d.app.AlbumSetPage
03-07 15:20:27.967 719-817/? I/ActivityManager﹕ Displayed com.android.gallery3d/.app.GalleryActivity: +190ms
// Pick an image
3-07 15:21:45.993 22967-22967/? V/StateManager﹕ startStateForResult class com.android.gallery3d.app.AlbumPage, 1
03-07 15:21:46.011 22967-22967/? D/AlbumPage﹕ onSyncDone: ********* result=0
03-07 15:21:46.034 22967-24132/? I/GLRootView﹕ layout content pane 1080x1701 (compensation 0)
03-07 15:21:48.447 719-1609/? I/ActivityManager﹕ START u0 {act=com.android.camera.action.CROP dat=content://media/external/images/media/1000 flg=0x2000000 cmp=android/com.android.internal.app.ResolverActivity (has extras)} from uid 10100 on display 0
First, note W/GalleryActivity﹕ action PICK is not supported. I'm not sure why it works, but according to Dianne Hackborn, "...you should consider ACTION_PICK deprecated. The modern action is ACTION_GET_CONTENT which is much better supported..." I've addressed this in my solution above.
The good news is, however, it seems that after picking an image, .putExtra("crop", "true"); causes Gallery to send another Intent for cropping. And the log clearly shows the action and data to use.
I tested this cropping intent, and I was prompted to choose an app for cropping, just like before. And again, both Photos and Gallery were presented as options, and they both brought up cropping interfaces.
It seems that although Photos supports cropping by Intent, it just ignores the extras relating to cropping in ACTION_PICK, whereas Gallery responds by sending another Intent after picking an image. Regardless, having the details of a working cropping Intent leads to the solution above.
I have solved this problem this way.
Pick image:
private void pickUserImage() {
if (doHavePermission()) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra("scale", true);
photoPickerIntent.putExtra("outputX", 256);
photoPickerIntent.putExtra("outputY", 256);
photoPickerIntent.putExtra("aspectX", 1);
photoPickerIntent.putExtra("aspectY", 1);
photoPickerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
startActivityForResult(photoPickerIntent, PICK_FROM_GALLERY);
}
}
used method getTempUri() is
private Uri getTempUri() {
return Uri.fromFile(getTempFile());
}
private File getTempFile() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File file = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
try {
file.createNewFile();
} catch (IOException e) {
Log.printStackTrace(e);
}
return file;
} else {
return null;
}
}
get the picked image
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PICK_FROM_GALLERY) {
if (data!=null) {
Uri selectedImageUri = data.getData();
//String tempPath = getPath(selectedImageUri, UserProfileActivity.this);
String url = data.getData().toString();
if (url.startsWith("content://com.google.android.apps.photos.content")){
try {
InputStream is = getContentResolver().openInputStream(selectedImageUri);
if (is != null) {
Bitmap selectedImage = BitmapFactory.decodeStream(is);
//You can use this bitmap according to your purpose or Set bitmap to imageview
if (selectedImage != null) {
isImageUpdated = true;
isImageUpdated = true;
Bitmap resizedBitmap = null;
if (selectedImage.getWidth() >= 256 && selectedImage.getHeight() >= 256) {
resizedBitmap = Bitmap.createBitmap(selectedImage,
selectedImage.getWidth() - 128,
selectedImage.getHeight() - 128,
256, 256);
}
if (resizedBitmap != null) {
imageViewUserImage.setImageDrawable(ImageHelper.getRoundedCornerImage(resizedBitmap, 20));
} else {
imageViewUserImage.setImageDrawable(ImageHelper.getRoundedCornerImage(selectedImage, 20));
}
}
}
} catch (FileNotFoundException e) {
Log.printStackTrace(e);
}
} else {
File tempFile = getTempFile();
String filePath = Environment.getExternalStorageDirectory() + "/" + TEMP_PHOTO_FILE;
Log.d(TAG, "path " + filePath);
Bitmap selectedImage = BitmapFactory.decodeFile(filePath);
if (selectedImage != null) {
isImageUpdated = true;
imageViewUserImage.setImageDrawable(ImageHelper.getRoundedCornerImage(selectedImage, 20));
}
if (tempFile.exists()) {
tempFile.delete();
}
}
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Image converted to rounded corner image as follows:
public class ImageHelper {
public static RoundedBitmapDrawable getRoundedCornerImage(Bitmap bitmap, int cornerRadius) {
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(null, bitmap);
dr.setCornerRadius(cornerRadius);
return dr;
}
}
Its too late to answer but it can help someone else.

Open an image saved in SD card with option to crop it as in Gallery to apply as wallpaper

I have a application where I have some downloaded images in a folder in SD Card. I want to save it as a wallpaper.
using the below code user can set it as wallpaper.
WallpaperManager myWallpaperManager = WallpaperManager.getInstance(context);
myWallpaperManager.setBitmap(loadedImage);
However this does not bring up any UI for user to select a part of the image like crop operation when selecting a image from Gallery app to set wallpaper. I would like my code to trigger such a operation. When users click a button in my app I want to take them to gallery app with crop option to set the wallpaper.
Please let me know how to do this. Thank you.
You may want to try this:
To select from your library (SD Card included) - void selectPhoto():
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Choose photo to upload"), PICK_FROM_FILE);
To start the crop action - void doCrop():
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/*");
// Check if there is image cropper application installed.
List<ResolveInfo> list = getPackageManager().queryIntentActivities( intent, 0 );
int size = list.size();
// If no cropper application is found, throw a message.
if (size == 0) {
Toast.makeText(this, "Can not find image crop app", Toast.LENGTH_SHORT).show();
return;
// If there're cropper applications found, use the first
} else {
// Specify image path and cropping parameters
intent.setData(mImageCaptureUri);
intent.putExtra("outputX", 0);
intent.putExtra("outputY", 0);
intent.putExtra("return-data", true);
Intent i = new Intent(intent);
ResolveInfo res = list.get(0);
i.setComponent( new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
startActivityForResult(i, CROPPED_IMAGE);
Handle Activity results - void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode != RESULT_OK) return;
switch (requestCode) {
case PICK_FROM_FILE:
mImageCaptureUri = data.getData();
doCrop();
break;
case CROPPED_IMAGE:
Bundle extras = data.getExtras();
try{
if (extras != null) {
Bitmap myImage = extras.getParcelable("data");
}
}
catch(Exception e)
{
e.printStackTrace();
}
break;
This code will activate crop action right after you selected the image.
Note that mImageCaptureUri is the selected image URI, it would be pass to intent of cropping action.

Categories

Resources