I am creating an android application. It takes a picture then allows you to crop it and then displays it. Problem is that it only saves the taken image not the cropped one. Basically i need it to save the cropped image. how can I save a file after cropping?
Code:
private void performCrop(){
//take care of exceptions
try {
//call the standard crop action intent (the user device may not support it)
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1.5);
//indicate output X and Y
cropIntent.putExtra("outputX", 256);
cropIntent.putExtra("outputY", 256);
//retrieve data on return
cropIntent.putExtra("return", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, PIC_CROP);
}
//respond to users whose devices do not support the crop action
catch(ActivityNotFoundException anfe){
//display an error message
String errorMessage = "Your device does not support cropping";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Just add something like this:
try{
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
), fileName+".png"); //save to your pictures folder
outputFileURI = Uri.fromFile(file);
cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileURI);
startActivityForResult(cropIntent, PIC_CROP);
} catch (IOException ioe){
// handle your exception
}
Remember to refresh the gallery after saving so that its instantly available in the gallery. So use this code maybe in your onActivityResult method?
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse
("file://" + Environment.getExternalStorageDirectory())));
Edit: Found a better way to refresh the gallery since sendBroadcast can be a inefficient if you are just refreshing for one image. Use a MediaScanner to scan the file like so
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(outputFileURI); // Add the path to the file
sendBroadcast(intent);
This will just scan for the new file and refresh that instead of the whole gallery.
Related
I am struggling with a problem already for few days and I can't figure out any solution, all my researches are done.
I have a simple Camera/Gallery intent followed by a crop intent.
I have encountered 2 problems by now.
On Huawei P9 the intent seems to be successful with a toast with the message "Saving picture" but it seems like the crop screen is not finished because nothing happens after.
On Samsung Galaxy S8 & S8 plus the image after the crop has bad quality.
My crop method is below:
protected void performCrop(File file) {
// take care of exceptions
try {
// call the standard crop action intent (the user device may not
// support it)
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
cropIntent.setDataAndType(Uri.fromFile(file), "image/*");
// set crop properties
cropIntent.putExtra("crop", "true");
// indicate aspect of desired crop
cropIntent.putExtra("aspectX", ASPECT_X);
cropIntent.putExtra("aspectY", ASPECT_Y);
// // indicate output X and Y
// cropIntent.putExtra("outputX", 256);
// cropIntent.putExtra("outputY", 256);
// retrieve data on return
cropIntent.putExtra("return-data", true);
// start the activity - we handle returning in onActivityResult
cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
startActivityForResult(cropIntent, CROP_PIC);
}
// respond to users whose devices do not support the crop action
catch (ActivityNotFoundException anfe) {
Toast toast = Toast
.makeText(this, "This device doesn't support the crop action!", Toast.LENGTH_SHORT);
toast.show();
}
}
As you can see I tried different possibilities and solutions, nothing worked. If anyone has any idea how I could solve this, please let me know.
In my application the user selects an image. When the CROP_IMAGE intent is launched it displays the dialog to select one of the available image croppers installed on the device. I would like to solve that one of the installed programs launch default that user don't have to choose all time which program wants to use.
Is it possible to skip this chooser dialog and launch one image cropper automatically?
I found an answer :
Intent cropApps = new Intent("com.android.camera.action.CROP");
cropApps.setType("image/*");
List<ResolveInfo> list = this.getPackageManager().queryIntentActivities(cropApps, 0);
int size = list.size();
if (size == 0)
{
Toast.makeText(this, "Can not find image crop app", Toast.LENGTH_SHORT).show();
}
else
{
ResolveInfo res = list.get(0);
Intent cropIntent = new Intent();
cropIntent.setClassName(res.activityInfo.packageName, res.activityInfo.name);
cropIntent.setDataAndType(picUri, "image/*");
cropIntent.putExtra("outputX", 800);
cropIntent.putExtra("outputY", 800);
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
cropIntent.putExtra("scale", true);
cropIntent.putExtra("return-data", true);
startActivityForResult(cropIntent, PIC_CROP);
}
I tried below code to crop large image with pixel (2448*3264). But, This process is not working fine. Please correct the below code or give me another solution to achieve this images cropping process. Advance thanks to all.
private void performCrop(){
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(UrlGambar, "image/*");
cropIntent.putExtra("crop", "true");
cropIntent.putExtra("aspectX", 2);
cropIntent.putExtra("aspectY", 3);
//cropIntent.putExtra("outputX", 256);
//cropIntent.putExtra("outputY", 256);
cropIntent.putExtra("return-data", true);
startActivityForResult(cropIntent, PIC_CROP);
}
catch(ActivityNotFoundException anfe){
String errorMessage = "Whoops - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
}
Intent com.android.camera.action.CROP is not a standard android intent and there are many devices that donot support this intent. Please refer to my answer in this post. I am using a library from github to do the cropping.
My Galaxy Nexus is now running on Android 4.3 allowing me to test my application with this new version. Everything seems fine except cropping.
I have an application that uses the camera to take picture and then crop the image through the gallery app.
I am also able to choose a picture from the gallery and crop it after.
Since Android 4.3, the gallery application changed.
If i take a picture with the camera api and then ask the gallery to crop it in my onActivityResult method the resultCode is set to 0 (meaning cancel) whereas i clicked on "Save" from the crop view.
But if i choose a picture from the gallery and crop it everything works, the resultCode parameter is set to -1.
I call the same method to crop the picture in both cases.
I have quickpic (an alternative to the gallery app) on my phone, with it everything works !
private void performCrop(Uri picUri) {
try {
int aspectX = 750;
int aspectY = 1011;
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(picUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale", "true");
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCurrentPhotoPath)));
startActivityForResult(intent, CROP);
}
catch (ActivityNotFoundException anfe) {
String errorMessage = "Your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Everything worked fine on Android 4.2.2.
Thank you for your help !
Have you considered just using a library like this one:
https://github.com/biokys/cropimage
I find the com.android.camera.action.CROP can sometimes behave differently from phone to phone and is not always available, so it could cause some problems for you anyway if you are looking to release it.
UPDATE:
I have tested the above library with Android 4.3 and it works with no problem. You just need to add the library to your project.
You can then write your method in a very similar way:
private void performCrop(Uri picUri) {
//you have to convert picUri to string and remove the "file://" to work as a path for this library
String path = picUri.toString().replaceAll("file://", "");
try {
int aspectX = 750;
int aspectY = 1011;
Intent intent = new Intent(this, CropImage.class);
//send the path to CropImage intent to get the photo you have just taken or selected from gallery
intent.putExtra(CropImage.IMAGE_PATH, path);
intent.putExtra(CropImage.SCALE, true);
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCurrentPhotoPath)));
startActivityForResult(intent, CROP);
}
catch (ActivityNotFoundException anfe) {
String errorMessage = "Your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Above library is only useful if your cropping into a lot smaller images. If you want to crop to a better resolution images, it is best to use the Android Crop Intent.
picUri must be a valid URI which points to your image and outputUri should be a new file you created for writing the cropped image. It works on all devices and 4.3 Source code does indeed have com.android.camera.action.CROP intent available for usage. I've tested this on many devices and it works well.
private void performCrop(Uri picUri, Uri outputUri) {
try {
int aspectX = 2000;
int aspectY = 1200;
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(picUri, "image/*");
intent.putExtra("scale", "true");
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
startActivityForResult(intent, CROP);
}
catch (ActivityNotFoundException anfe) {
String errorMessage = "Your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
I've encountered this problem on a Nexus 10 as well. the crop intent returns a cancelled code. after some tweaking I've found a solution:
In my case the input file set in setDataAndType() was the same file as the output set using the MediaStore.EXTRA_OUTPUT extra. Using the same file for input and output worked fine on most devices, specifically on devices below 4.3. However on 4.3 it would result in canceled crops. Simply using different files for input and output resolved the issue.
So what you need to make sure of is that your picUri parameter points to a file that is not the same as your mCurrentPhotoPath. I'm not sure what exactly changed from 4.2 to 4.3 to cause this issue. But using different files seems to resolve it easily.
I'm trying to use a method to crop a image. Exactly this method:
private void performCrop() {
try {
//call the standard crop action intent (the user device may not support it)
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri
cropIntent.setDataAndType(**HERE**, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
//indicate output X and Y
cropIntent.putExtra("outputX", 256);
cropIntent.putExtra("outputY", 256);
//retrieve data on return
cropIntent.putExtra("return-data", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, 1234);
}
catch(ActivityNotFoundException anfe){
Log.d("debugging","EXCEPTION");/*
//display an error message
String errorMessage = "Whoops - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();*/
}
}
This line, asks for a Uri Data and String Type.
cropIntent.setDataAndType(**HERE**, "image/*");
But I just want to put this bitmap
Bitmap fotoCreada;
as Data, but I don't know how to do it.
Is there any way to achieve this?
Thanks.
EDIT
Okay, this is my code right now:
There's a button. When you click it:
public void onClick(View v) {
Boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if(isSDPresent) {
//Creem carpeta
File folder = new File(Environment.getExternalStorageDirectory().toString()+"/pic/");
folder.mkdirs();
//Recuperem data actual
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
String currentDateandTime = sdf.format(new Date());
//Cridem a la camara.
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
resultingFile=new File(folder.toString() + "/"+currentDateandTime+".jpg");
Uri uriSavedImage=Uri.fromFile(resultingFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
//Començem activity
startActivityForResult(cameraIntent, 1888);
} else {
Toast toast = Toast.makeText(getActivity(), "Issues while accessing sdcard.", Toast.LENGTH_SHORT);
toast.show();
}
}
As you can see, it's calling startActivityForResult. Basically takes a picture, and I retrieve it on activityResult:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("debugging",""+resultCode);
if( requestCode == 1888 && resultCode == -1) { //-1 = TOT HA ANAT BE.
Bitmap photo = BitmapFactory.decodeFile(resultingFile.getPath());
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap photoRotated = Bitmap.createBitmap(photo, 0, 0, photo.getWidth(), photo.getHeight(), matrix, true);
this.fotoCreada=photoRotated;
((ImageView) myFragmentView.findViewById(R.id.fotoCapturada)).setImageBitmap(this.fotoCreada);
try {
FileOutputStream out = new FileOutputStream(this.resultingFile.getPath());
this.fotoCreada.compress(Bitmap.CompressFormat.PNG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
performCrop();
}
if (requestCode == 1234 && resultCode == -1){
Bitmap bitmap = (Bitmap) data.getParcelableExtra("BitmapImage");
Log.d("debugging",""+bitmap.getHeight());
}
}
And as you can see from previous code, as I retrieve the bitmap, I call method performCrop. It's code, now, is:
private void performCrop() {
try {
//call the standard crop action intent (the user device may not support it)
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri
//cropIntent.setDataAndType(this.picUri, "image/*");
cropIntent.putExtra("BitmapImage", this.fotoCreada);
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
//indicate output X and Y
cropIntent.putExtra("outputX", 256);
cropIntent.putExtra("outputY", 256);
//retrieve data on return
cropIntent.putExtra("return-data", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, 1234);
Log.d("debugging","he acabat performCrop");
}
catch(ActivityNotFoundException anfe){
Log.d("debugging","EXCEPTION");
//display an error message
String errorMessage = "Whoops - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
But startActivityForResult from performCrop never ends up calling onActivityResult. Log cat says it just entered once, and should enter Twice. First one from the camera Activity and second from Crop activity.
-1
he acabat performCrop
Hope it's clear enough.
Thanks.
Bitmap implements Parcelable, so you could always pass it in the intent:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
and retrieve it on the other end:
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
However, if the bitmap exists as a file or a resource, its is always better to pass the URI or ResourceID of the bitmap and not the bitmap itself. Passing the entire bitmap requires a lot of memory. Passing the URL requires very little memory and allows each activity to load and scale the bitmap as they need it.
Use Intent.putExtra. A bitmap is a parceable, so it will work. setDataAndType is used for URIs, but you aren't referencing a resource on the web or on disk.