custom gallery cropping window in android - android

After struggling with Camera intents for too long, I have now finally created a custom camera experience for my app by using SurfaceView and the Camera api. It’s pretty awesome as I now have complete control over the picture taking experience. I would like to take control over the gallery experience as well. It’s not clear how I might do that? Any advice? Basically I am hoping for the following user experience
click on gallery button to view photos in your gallery
select a photo from the gallery
the selected photo shows up in a customized preview in which the user can move the photo around to select which portion to use. Notice that this is a sort of cropping that happens within a fixed area (in my case a square the size of the phone's width): no resizing allowed; the area of the picture within the window is the area used. Pretty much most of the social media apps out there do it that way. I just don’t have a clue how they manage that preview/edit-window.
What I know so far:
I can still use the gallery intent to let the user select the image
The part where I am stuck is on how to create the custom edit experience that lets the user choose an area of the image to show (fixed size square). Again, this is not resize-cropping; but rather the user can move the image around to choose which sub-area fits the window.
Thanks for any advice

Ok Here We Go!
Activity To Select The Image From Gallery.
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
public class GalleryUtil extends Activity{
private final static int RESULT_SELECT_IMAGE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private static final String TAG = "GalleryUtil";
String mCurrentPhotoPath;
File photoFile = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
//Pick Image From Gallery
Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_SELECT_IMAGE);
}catch(Exception e){
e.printStackTrace();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode){
case RESULT_SELECT_IMAGE:
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
try{
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
//return Image Path to the Main Activity
Intent returnFromGalleryIntent = new Intent();
returnFromGalleryIntent.putExtra("picturePath",picturePath);
setResult(RESULT_OK,returnFromGalleryIntent);
finish();
}catch(Exception e){
e.printStackTrace();
Intent returnFromGalleryIntent = new Intent();
setResult(RESULT_CANCELED, returnFromGalleryIntent);
finish();
}
}else{
Log.i(TAG,"RESULT_CANCELED");
Intent returnFromGalleryIntent = new Intent();
setResult(RESULT_CANCELED, returnFromGalleryIntent);
finish();
}
break;
}
}
}
Activity To Crop The Selected Image:
public class ImageSelecter extends Activity{
private final int GALLERY_ACTIVITY_CODE=200;
private final int RESULT_CROP = 400;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btn_choose.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Start Activity To Select Image From Gallery
Intent gallery_Intent = new Intent(getApplicationContext(), GalleryUtil.class);
startActivityForResult(gallery_Intent, GALLERY_ACTIVITY_CODE);
break;
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_ACTIVITY_CODE) {
if(resultCode == Activity.RESULT_OK){
picturePath = data.getStringExtra("picturePath");
//perform Crop on the Image Selected from Gallery
performCrop(picturePath);
}
}
if (requestCode == RESULT_CROP ) {
if(resultCode == Activity.RESULT_OK){
Bundle extras = data.getExtras();
Bitmap selectedBitmap = extras.getParcelable("data");
// Set The Bitmap Data To ImageView
image_capture1.setImageBitmap(selectedBitmap);
image_capture1.setScaleType(ScaleType.FIT_XY);
}
}
}
private void performCrop(String picUri) {
try {
//Start Crop Activity
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
File f = new File(picUri);
Uri contentUri = Uri.fromFile(f);
cropIntent.setDataAndType(contentUri, "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", 280);
cropIntent.putExtra("outputY", 280);
// retrieve data on return
cropIntent.putExtra("return-data", true);
// start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, RESULT_CROP);
}
// respond to users whose devices do not support the crop action
catch (ActivityNotFoundException anfe) {
// display an error message
String errorMessage = "your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
This all hope this will give you a head up:)

Related

android app exit when select image

I am blocked my app exit without any notification when I select images but when I select forum photo or gallery did not crashed.
I use creativesdk for photo edited.
screnshoot
package com.lamba.selfie;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.widget.ImageView;
import com.aviary.android.feather.sdk.AviaryIntent;
public class MainActivity extends AppCompatActivity {
private ImageView mResultImageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mResultImageView = (ImageView) findViewById(R.id.resultImageView);
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case 0:
Uri selectedImageUri = data.getData();
Uri imageUri = Uri.parse(getPath(selectedImageUri));
Intent imageEditorIntent = new AviaryIntent.Builder(this)
.setData(imageUri)
.build();
startActivity(imageEditorIntent);
/*case 1:
startActivityForResult(imageEditorIntent, 1);
Uri mImageUri = data.getData();
mResultImageView.setImageURI(mImageUri);
break;*/
}
}
}
public String getPath(Uri uri) {
// just some safety built in
if (uri == null) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
// this is our fallback here
return uri.getPath();
}
}
How could I fix it?
Source of the issue
You can simplify your switch statement's case 0 a bit and pass selectedImageUri directly to the AviaryIntent's setData() method.
As a result, you won't need your getPath() helper method.
Example code
Below is working code, based on your code above, that will:
Open the image source chooser immediately
Open the selected image in the Creative SDK Image Editor
Attach the edited image to the ImageView
See the comments in the example code to find where these things happen.
public class MainActivity extends AppCompatActivity {
private ImageView mSelectedImageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSelectedImageView = (ImageView) findViewById(R.id.selectedImageView);
// Open the image source chooser immediately
Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(galleryIntent, "Select an image"), 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
// Open the Creative SDK Image Editor with the chosen image
case 0:
Uri selectedImageUri = data.getData();
Intent imageEditorIntent = new AviaryIntent.Builder(this)
.setData(selectedImageUri)
.build();
startActivityForResult(imageEditorIntent, 1);
break;
// Attach the edited image to the ImageView
case 1:
Uri editedImageUri = data.getData();
mSelectedImageView.setImageURI(editedImageUri);
break;
}
}
}
// ...
}
try to change true to false on your Activity in the manifest file.
android:noHistory="true" to android:noHistory="false"
your code : galleryIntent.setAction(Intent.ACTION_GET_CONTENT)
Use this : Intent GalleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);

Out of Memory error while loading images. [Android]

I want to pick image from the gallery and use it in my App as Profile Picture. So far I've tried this.
Here's my InfoGet class. The loadImagefromGallery gets called on click.
public void loadImagefromGallery(View view) {
/* Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, RESULT_LOAD);*/
Intent gallery_Intent = new Intent(getApplicationContext(), GalleryUtil.class);
startActivityForResult(gallery_Intent, GALLERY_ACTIVITY_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_ACTIVITY_CODE) {
if(resultCode == Activity.RESULT_OK){
String picturePath = data.getStringExtra("picturePath");
//perform Crop on the Image Selected from Gallery
performCrop(picturePath);
}
}
if (requestCode == RESULT_CROP ) {
if(resultCode == Activity.RESULT_OK){
Bundle extras = data.getExtras();
Bitmap selectedBitmap = extras.getParcelable("data");
// Set The Bitmap Data To ImageView
pro.setImageBitmap(selectedBitmap);
pro.setScaleType(ImageView.ScaleType.FIT_XY);
}
}
}
private void performCrop(String picUri) {
try {
//Start Crop Activity
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
File f = new File(picUri);
Uri contentUri = Uri.fromFile(f);
cropIntent.setDataAndType(contentUri, "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", 280);
cropIntent.putExtra("outputY", 280);
// retrieve data on return
cropIntent.putExtra("return-data", true);
// start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, RESULT_CROP);
}
// respond to users whose devices do not support the crop action
catch (ActivityNotFoundException anfe) {
// display an error message
String errorMessage = "your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
And here's my GalleryUtil code
public class GalleryUtil extends Activity {
private final static int RESULT_SELECT_IMAGE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private static final String TAG = "GalleryUtil";
String mCurrentPhotoPath;
File photoFile = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
//Pick Image From Gallery
Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_SELECT_IMAGE);
}catch(Exception e){
e.printStackTrace();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode){
case RESULT_SELECT_IMAGE:
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
try{
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
//return Image Path to the Main Activity
Intent returnFromGalleryIntent = new Intent();
returnFromGalleryIntent.putExtra("picturePath",picturePath);
setResult(RESULT_OK,returnFromGalleryIntent);
finish();
}catch(Exception e){
e.printStackTrace();
Intent returnFromGalleryIntent = new Intent();
setResult(RESULT_CANCELED, returnFromGalleryIntent);
finish();
}
}else{
Log.i(TAG, "RESULT_CANCELED");
Intent returnFromGalleryIntent = new Intent();
setResult(RESULT_CANCELED, returnFromGalleryIntent);
finish();
}
break;
}
}
}
I need help can anyone just make some changes in the existing code. I do not want to rebuild anything from scratch. I want to optimise this image picker before I release the next update. The Existing code work okay for devices with decent amount of RAM like 1GB or so.
Please help me.
And also explain what you did and how it works. Thanks a LOT.
I did that method read images from path and solve this issue, maybe it help you:
public static Bitmap readBitmap(Uri selectedImage, int resizeFactor)
{
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = resizeFactor;
AssetFileDescriptor fileDescriptor = null;
try
{
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");
} catch (FileNotFoundException e)
{
e.printStackTrace();
} finally
{
try
{
bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
return bm;
}
The atributes are Uri selectedImage and int resizeFactor;
on selectedImage you need to put a Path from image and on resizeFactor put a int number, Normally I use number 10, try with that or try with another one (down/up)
Now if you want to put on ImageView you can use that.
ImageView.setImageBitmap(readBitmap(Path, 10));
Later you need clear Bitmap content to avoid OutOfMemory, use that method:
public static void clearBitmap(Bitmap bm)
{
bm.recycle();
}

handling result from activity to a fragment

I have a fragment which contains four images each image when clicked it opens a gallery for the user to select image from there in the activity result when retrieving the image name and path I'm passing this result to an activity through intent that handles the cropping of the image in the cropping activity after the cropping is done i don't know how to send back the result of the cropped image to the fragment and place it in the image view same process is done for the 4 images how can i achieve that. Here is my starting code.
enter code here
attach_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pickFromGallery();
}
});
private void pickFromGallery()
{
Intent galleryIntent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
// When an Image is picked
if (requestCode == RESULT_LOAD_IMG && resultCode == getActivity().RESULT_OK
&& null != data) {
// Get the Image from data
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
// Get the cursor
Cursor cursor = getContext().getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
// Move to first row
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imgDecodableString = cursor.getString(columnIndex);
cursor.close();
startCrop(imgDecodableString);
} else {
Toast.makeText(getActivity(), "You haven't picked Image",
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getActivity(), "Something went wrong", Toast.LENGTH_LONG)
.show();
}
}
private void startCrop(String imageUri)
{
Intent intent = new Intent(getActivity(),CropActivity.class);
intent.putExtra("Image",imageUri);
startActivity(intent);
}
}
in my cropping activity here is my code
enter code here
Intent i = getIntent();
image = i.getStringExtra("Image");
Log.d("Image",""+image);
DisplayMetrics metrics = getResources().getDisplayMetrics();
int imageWidth = (int) ( (float) metrics.widthPixels / 1.5 );
int imageHeight = (int) ( (float) metrics.heightPixels / 1.5 );
bitmap = BitmapLoadUtils.decode(image, imageWidth, imageHeight);
imageCropView.setImageBitmap(bitmap);
imageCropView.setAspectRatio(3, 2);
findViewById(R.id.crop_btn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if(!imageCropView.isChangingScale())
{
Bitmap b = imageCropView.getCroppedImage();
}
}
});
after cropping here the image i need to set this cropped image in the image view in the fragment same for the rest of the image with the same process how can this be achieved .
Any help would be appreciated.
You can start the activity using startActivityForResult(...) method, so you can send data back.
As for how to pass the bitmap using intent, check this stackoverflow question.
Then you can get the Bitmap on the onActivityResult(...) method of your fragment.
Passing bitmaps via intents is not a good practice and will not work if the bitmap is large and therefore should be avoided.
I would suggest u to save the bitmap on disk and pass the path of the saved image to the fragment. Check the edit of the accepted answer in this post
Also shouldn't call startActivity() from a fragment. It should be done from the another activity. Check this Communicating With Fragments Guide

cropping image and saved ok but imageview has old image, why?

I do a crop on an image after it is captured by my camera - all working.
The image appears in my gallery all cropped and lovely - all working.
I assign the image after calling crop to a imageview using the uri - not working
Heres my code, i think my issue is that the uri is pointing to the old uncropped image in \storage\emulator\0... and the cropped goes straight to my gallery. How can i get cropped úí and the cropped image is in my gallery - How do i get the cropped image into my imageView
code:
private static final int PICK_IMAGE = 0;
private static final int PICK_IMAGE_FROM_GALLERY = 1;
private static final int CROP_IMAGE = 2;
private Uri uri;
.
.
.
btnPhotoCamera.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent camera=new Intent();
camera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
//camera.putExtra("crop", "true");
File f=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
uri = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"myFile.jpg"));
camera.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(camera, PICK_IMAGE);
}
});
private void performCrop(Uri picUri)
{
//NEXUS 5 OS 5 is example of this branch
// 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, "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
// retrieve data on return
cropIntent.putExtra("return-data", true);
// start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, CROP_IMAGE);
}
// respond to users whose devices do not support the crop action
catch (ActivityNotFoundException anfe)
{//NOT TESTED AS HW DOES NOT GO HERE
Toast toast = Toast.makeText(this,"This device doesn't support the crop action! Exception: " + anfe.toString(),Toast.LENGTH_SHORT);
toast.show();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
// TODO Auto-generated method stub
if (resultCode==RESULT_OK )
{
if(requestCode == PICK_IMAGE) //reply from camera
{
performCrop(uri); //crop the picture
}
if(requestCode == CROP_IMAGE) //reply from crop
{
Bitmap bmp = getBitmap(uri);
imgView.setImageBitmap(bmp);
}
}
}
private Bitmap getBitmap(Uri bitmap_uri) {
InputStream is=null;
try
{
is = this.getContentResolver().openInputStream(bitmap_uri);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return BitmapFactory.decodeStream(is);
}
}
Crop result will be in the date extra in onActivityResult as below:
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if(requestCode == CROP_IMAGE && resultCode == RESULT_OK) //reply from crop
{
Bundle extras = data.getExtras();
if(extras != null ) {
Bitmap photo = extras.getParcelable("data");
FileOutputStream fOut = new FileOutputStream(tmpFile);
photo.compress(Bitmap.CompressFormat.JPEG, 75, fOut);
//etc
}
}
}

Runtime Cropping an Image in android

I have already selected an image from SD card in my activity's ImageView using Intent.and now I want to show a fixed size moving Rectangle i.e. we have to use gesture and whatever portion of the image we want,then we are able to crop that.How can we do that?Its really tough for me to do?
Please help me in doing that?
Update-->I have been able to bring the rectangle and I m getting problem in cropping and saving that selected part.How to do this?
ok geetanjali. try this code this will open gallery and you can pick a photo to crop, it will store with name starts from apple, you can see cropped image in your activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop","true");
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempFile());
photoPickerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, 1);
}
private Uri getTempFile() {
if (isSDCARDMounted()) {
String f;
muri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
"apple_" + String.valueOf(System.currentTimeMillis()) + ".jpg"));
//File f = new File(Environment.getExternalStorageDirectory(),"titus1.jpg");
try {
f=muri.getPath();
} catch (Exception e) {
}
return muri;
} else {
return null;
}
}
private boolean isSDCARDMounted(){
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
}
protected void onActivityResult(int requestCode, int resultCode,
Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String filePath= muri.getPath();
Log.e("path", "filePath");
Toast.makeText(this, filePath, Toast.LENGTH_LONG).show();
Bitmap selectedImage = BitmapFactory.decodeFile(filePath);
image = (ImageView)findViewById(R.id.image);
image.setImageBitmap(selectedImage);
}
}
}

Categories

Resources