I need to crop a photo from the android phone gallery and then edit it.
The original size of the photo is 3264 *2448 which is displayed in my screen of size 1280 * 720 as a scaled down image.
When I crop it, i am getting a image of size 185 * 139.
The code I am using for cropping is
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(picUri, "image/*");
cropIntent.putExtra("crop", "true");
cropIntent.putExtra("return-data", true);
startActivityForResult(cropIntent, PIC_CROP);
When I display the cropped image in an imageView it is displayed as a much smaller image.
I should be cropping the original sized image and not the scaled down version. Could any of you please guide me as to how to do this?
Please try this, i know its too late, but may help someone.
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(mImageCaptureUri, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 4);
cropIntent.putExtra("aspectY", 3);
//indicate output X and Y
cropIntent.putExtra("outputX", 800);
cropIntent.putExtra("outputY", 800);
File f = new File(Environment.getExternalStorageDirectory(),
"/temporary_holder.jpg");
try {
f.createNewFile();
} catch (IOException ex) {
Log.e("io", ex.getMessage());
}
uri = Uri.fromFile(f);
cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
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 doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Make your onActivityResult like this :-
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PIC_CROP) {
String filePath = Environment.getExternalStorageDirectory()
+ "/temporary_holder.jpg";
thumbnail = BitmapFactory.decodeFile(filePath);
//thumbnail = BitmapFactory.decodeFile(filePath);
// Log.i("",String.valueOf(thumbnail.getHeight()));
ImageView image = (ImageView) findViewById(R.id.pestImage);
image.setImageBitmap(thumbnail);
}
}
Add:
intent.putExtra(MediaStore.EXTRA_OUTPUT, tempUri);
Then you can get an image file which is not reduced. And use this saved file instead of:
Intent.getExtras().getParcelable("data")
Just ignore returned bitmap.
First off you should be aware that the crop intent cannot be relied upon for cross-device compatibility. (Any OEM can replace the stock camera/gallery app with their own version). This aside, I think you are missing a few extras that should go in the intent and give you your desired effect.
// width & height are your desired width/height for the cropped result
cropIntent.putExtra("outputX", width);
cropIntent.putExtra("outputY", height);
cropIntent.putExtra("aspectX", width);
cropIntent.putExtra("aspectY", height);
cropIntent.putExtra("scaleUpIfNeeded", true);
Try adding those to your intent and see how it turns out.
Related
I do not know , is the problem the cut function or the Decoding Code ? :
I use the code for for uploading:
public void Upload(View view) {
Bitmap Bimg = ((BitmapDrawable) image1.getDrawable()).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Bimg.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
// Bimg.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); // bad too
encodimg = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT);
and i use this code to cut the image :
private void performCrop(){
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(picUri, "image/*");
cropIntent.putExtra("crop", "true");
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
cropIntent.putExtra("outputX", 512);
cropIntent.putExtra("outputY", 512);
cropIntent.putExtra("return-data", true);
startActivityForResult(cropIntent, PIC_CROP);
Toast toast = Toast.makeText(this, "Done", Toast.LENGTH_SHORT);
}
catch(ActivityNotFoundException anfe){
String errorMessage = "Soory - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
remark : I use a small image in xml as small preview :
<ImageView
android:onClick="Load_Picture"
android:id="#+id/imageview1"
android:background="#drawable/default_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
but i do not thing, the image size in xml is the problem
Iget the Bitmap from Camera or From Galerie like that :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ( requestCode==111 && resultCode==RESULT_OK ){
// Uri uri = data.getData();
// imageView.setImageURI(uri);
imageView.setImageBitmap((Bitmap)data.getExtras().get("data"));
}
}
the Problem is the cut methode , because if i upload the bitmap before cutting, i get very good quality. so the Problem is :
performCrop(){
You are not trying to send your cropped image to a server.
Instead you display the cropped image in an imageview. Then after that you take an screendump from that imageview and upload that to the server. Of course hat screendump has bad quality.
Instead you should upload the image you get from the crop function.
Please compare the resolution in pixels of all involved images.
Is there a way of looping through the default image gallery on an android device?
In my app I have managed to pass a selected picture from the default gallery to an imageView by this code:
public void onImageGalleryClicked(View v){
//Invoke image gallery using implicit intent
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
//Where is the image gallery stored
File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//Get path of the image gallery as string
CurrentPicturePath = pictureDirectory.getPath();
//Get the URI-representation of the image directory path
Uri data = Uri.parse(CurrentPicturePath);
//Set the data and type to get all the images
photoPickerIntent.setDataAndType(data, "image/*");
//Invoke activity and wait for result
startActivityForResult(photoPickerIntent, IMAGE_GALLERY_REQUEST);
}
And showing the picture in in a viewcontroller by:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK){
if(requestCode == IMAGE_GALLERY_REQUEST){
//Address of the image on SD-card
Uri imageUri = data.getData();
//Declare a stream to read the image from SD-card
InputStream inputStream;
try {
inputStream = getContentResolver().openInputStream(imageUri);
//Get a bitmap
Bitmap image = BitmapFactory.decodeStream(inputStream);
imgPicture.setImageBitmap(image);
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to open image!", Toast.LENGTH_LONG).show();
}
}
}
}
Now I want to have a button in my app that finds the next picture in the default gallery.
I'd like a way to loop through the gallery to find my current picture (by path/name!?) to be able to select the next one (or previous)
There are billions of Android devices, spread across thousands of device models. These will have hundreds of different "default image gallery" apps, as those are usually written by device manufacturers. The user does not have to use any of those apps to satisfy your ACTION_PICK request.
There is no requirement of ACTION_PICK implementations to supply you with "next" or "forward" information.
I am going to try and explain this in much detail as possible (if i miss anything please let me know)
So in my app on the map the user can longclick at any point on the map, which then adds a default marker and it starts the camera intent, whereby the user can take a photo of the castle and return to the map. so when the user then taps on the map the full image is displayed in the getInfoContents(Marker marker) and when the user taps on the infoWindow they can either select "delete marker" or "cancel" All of this is fine and working. However the problem i am facing is when the user takes a photo of castle 1 and places the marker, and then take another photo of castle 2 and places the marker, what seem to happen is that when tapping on castle 1 marker, castle 2 image is displayed (the same then for castle 2)
So what i would like to do is "save" that image to that specific marker.
So this is my code up until this point:
I created the HashMap:
private HashMap<Bitmap, Marker> myMarkersHash;
Then in onCreate method this:
myMarkersHash = new HashMap<Bitmap, Marker>();
Then in onMapLongClick this:
Marker marker = googleMap.addMarker(new MarkerOptions()
.position(thePoint));
myMarkersHash.put(bitmap, marker);
Then in my getInfoContents(Marker marker) this:
View v = getLayoutInflater().inflate(R.layout.infowindow_layout, null);
final ImageView markerIcon = (ImageView) v.findViewById(R.id.marker_icon);
myMarkersHash.get(bitmap);
markerIcon.setImageBitmap(bitmap);
But this doesn't seem to work, so am missing something here I think.
This is my camera intent (Might help with my question)
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "My Castle");
imagesFolder.mkdirs();
image = new File(imagesFolder, "Mycastle_" + timeStamp + ".jpg");
fileUri = Uri.fromFile(image);
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(imageIntent, TAKE_PICTURE);
Then in onActivityResult this:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK) {
try {
GetImageThumbnail getImageThumbnail = new GetImageThumbnail();
bitmap = getImageThumbnail.getThumbnail(fileUri, this);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
(Just to add the onActivityResult gets the scaled down image from the GetImageThumbnail.class
Hope i have made sense and really hoping some one could assist me with this problem.
Thank you in advance!
EDIT 1
So what i have tried now is to implement this:
private Map<String, Uri> myMarkersHash;
the in onCreate Method:
myMarkersHash = new HashMap<String, Uri>();
Then in onMapLongClick this:
myMarkersHash.put(marker.getId(), fileUri );
And finally getInfoContents this:
myMarkersHash.get(marker.getId() + fileUri);
markerIcon.setImageBitmap(bitmap);
But unfortunately it still doesn't seem to work. I have also tried image.getAbsolutePath(); but that just crashes the app with a nullPointerException
EDIT 2
As suggested i have tried this:
private Map<String, Bitmap> myMarkersHash;
the in onCreate Method:
myMarkersHash = new HashMap<String, Bitmap>();
Then in onMapLongClick this:
myMarkersHash.put(marker.getId(), bitmap);
And finally getInfoContents this:
myMarkersHash.get(marker.getId());
markerIcon.setImageBitmap(bitmap);
But still doesn't seem to work, still displaying the same image for every marker. I think that it doesn't see that image taken at that point (although the images are saved to a folder on the sdCard if that makes sense?)
EDIT 3
Okay so there is light at the end of the tunnel! However not quite there yet. As suggested i have implemented this code:
Bitmap bitmap = myMarkersHash.get(marker.getId());
markerIcon.setImageBitmap(bitmap);
Now what seems to happen is this:
a. 1st marker placed = no image
b. 2nd marker placed = image of the first marker
c. 3rd marker placed = image of the 2nd marker
d. 4th marker placed = image of the 3rd marker
e. 5th marker placed = image of the 4th marker
and so forth.
Any ideas why this would happen? Will try something now and let you know.
EDIT 4
Full OnMapLongClick code:
#Override
public void onMapLongClick(LatLng point) {
thePoint=point;
Marker marker = googleMap.addMarker(new MarkerOptions()
.position(thePoint));
myMarkersHash.put(marker.getId(), bitmap );
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "My Castle");
imagesFolder.mkdirs();
image = new File(imagesFolder.getPath(), "Mycastle_" + timeStamp + ".jpg");
fileUri = Uri.fromFile(image);
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(imageIntent, TAKE_PICTURE);
}
Hope this helps.
EDIT 5
GREAT!! it works!! Whoop, but the problem is it is turning an image taken in portrait to landscape, which is why i had to implement this code:
ExifInterface exif = null;
try {
exif = new ExifInterface(image.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation != 1) {
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
default:
rotate = 0;
break;
}
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
}
But since adding the code as suggested, its gone back to displaying the photo taken in portrait to landscape.
LAST EDIT
Okay so all is working now a 100%!! Thanks for all the help, much appreciated!!!
I am not sure from your edit of what you are exactly doing, but it seems you're not using HashMap as you would need to. You might try something like this:
Bitmap bitmap = myMarkersHash.get(marker.getId());
markerIcon.setBitmap(bitmap);
You should also create a local bitmap before adding it to the HashMap:
#Override
public void onMapLongClick(LatLng point) {
thePoint=point;
Marker marker = googleMap.addMarker(new MarkerOptions()
.position(thePoint));
markerId = marker.getId();
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "My Castle");
imagesFolder.mkdirs();
image = new File(imagesFolder.getPath(), "Mycastle_" + timeStamp + ".jpg");
fileUri = Uri.fromFile(image);
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(imageIntent, TAKE_PICTURE);
}
Then when you set your bitmap:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK) {
try {
GetImageThumbnail getImageThumbnail = new GetImageThumbnail();
Bitmap bitmap = getImageThumbnail.getThumbnail(fileUri, this);
myMarkersHash.put(markerId, bitmap );
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
Therefore, you need to store your markerId somewhere to be able to get it in onActivityResult
I think you are creating a new imagesFolder every time.
You can try to do something like:
File imagesFolder = new(File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "My Castle");
if (!imagesFolder.exists()) {
if (!imagesFolder.mkdirs()) {
Log.e(TAG, "Fail to create directory.");
return null;
}
}
And this:
file = new File(imageFolder.getPath() + File.seperator + "IMG_" + timestamp + ".jpg");
Also, you can output the list of Marker ID from your hashmap, see if the number of marker ids matched.
In Android, is there any built-in way for resizing an image through selecting it, and then dragging the corners/sides to the desired dimensions?
To illustrate what I wish to achieve:
I think what you are looking for is cropping image.
you can achieve that with default android Crop functionality:
private void performCrop(Uri picUri) {
try {
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);
// indicate output X and Y
cropIntent.putExtra("outputX", 128);
cropIntent.putExtra("outputY", 128);
// retrieve data on return
cropIntent.putExtra("return-data", 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 = "Whoops - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Constant declare:
final int PIC_CROP = 1;
override onActivity result method in your activity, writ following code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PIC_CROP) {
if (data != null) {
// get the returned data
Bundle extras = data.getExtras();
// get the cropped bitmap
Bitmap selectedBitmap = extras.getParcelable("data");
imgView.setImageBitmap(selectedBitmap);
}
}
}
I take a picture in Android via
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePicture, CAMERA_REQUEST);
and show / save it via
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
ImageView theImage = (ImageView) findViewById(R.id.preview);
theImage.setImageBitmap(photo);
// try to save its
try {
File testFile = new File(Environment.getExternalStorageDirectory(), "test.png");
testFile.createNewFile();
FileOutputStream out = new FileOutputStream(testFile);
photo.compress(Bitmap.CompressFormat.PNG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
This works fine, however the quality of the image is very bad. I do not know why, since I take the picture with 8 mega pixels.
Is there a way to do this without requiring the camera manually?
Take a closer look at this post: there are two ways to capture an image in Android. First one is designed for taking small and lightweight pictures - that's the approach you use, and the second one captures full-sized pictures and writes them to storage. The post describes both ways of accomplishing this task.