Crop a fixed size image in Android - android

I am trying to crop an image but I want to be able to set the cropped area to exactly 640px x 640px. I want to prevent a user from cropping down to a really small area. So basically I would prefer to have a fixed height and width for the cropping area. I have looked into several third party libraries but don't see solving this problem. How can I do this?

I'd use one of these solutions:
https://github.com/jdamcd/android-crop
https://github.com/edmodo/cropper
Both seems to be appropriate to solve your problem and for sure cover more edge cases, devices and other Android stuff just to be more stable and reliable.
EDIT:
I have introduced a few changes to android-crop and now you can use withFixedSize(int width, int height) to set fixed cropping area in pixels.
Looks like this:
private void beginCrop(Uri source) {
Uri outputUri = Uri.fromFile(new File(getCacheDir(), "cropped"));
new Crop(source).output(outputUri).withFixedSize(640, 640).start(this);
}
Here it's a pull request.
Check full code at my github https://github.com/mklimek/android-crop/tree/newfeature_fied_size_crop.
You can clone build and add it to your project afterwards.
Hope it will help you.

There is a method you can useÆ
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(selectedImage, "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", 640);
cropIntent.putExtra("outputY", 640);
//retrieve data on return
cropIntent.putExtra("return-data", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, PIC_CROP);
}
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();
}
}
This part of code is what youøre interested in:
cropIntent.putExtra("outputX", 640);
cropIntent.putExtra("outputY", 640);
You should call crop method like this:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA && resultCode == RESULT_OK) {
selectedImage = data.getData();
performCrop();
}
if (requestCode == UPLOAD && resultCode == RESULT_OK) {
selectedImage = data.getData();
performCrop();
}
if (requestCode == PIC_CROP && resultCode == RESULT_OK){
Bundle extras = data.getExtras();
//get the cropped bitmap
Bitmap thePic = extras.getParcelable("data");
// Do what you want to do with the pic here
}
}

Related

low quality when capture picture and send it image view

low quality when capture picture and send it image view
when imgCamera button pressed
case R.id.imgCamera:
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
break;
**the activity result :**
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case CAMERA_REQUEST:
mPhotoEditor.clearAllViews();
Bitmap photo = (Bitmap) data.getExtras().get("data");
mPhotoEditorView.getSource().setImageBitmap(photo);
break;
case PICK_REQUEST:
try {
mPhotoEditor.clearAllViews();
Uri uri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
mPhotoEditorView.getSource().setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
please help me I want to get the best quality for the picture captured
To save the full-size image you need to do much more stuff.
data.getData();
This would return image thumbnail which is a low-quality image for the original one.
I can't find an accurate guide than the official documentation. check this link from Android Developer documentation. Following it, you would save the high-quality image easily instead of a low-quality one. Not to mention, You would learn about FileProivder and storage (Maybe you like to save it internal storage or external storage).
Be patient .. happy coding
my comment tells you want is wrong. Here's the solution:
first, modify your camera intent:
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
_photoUri = createImageUri();
// Continue only if the File was successfully created
if (_photoUri != null) {
//setflags is required to clear flag_activity_new_task that is automatically set on
//direct calls. If not cleared, you get instant returns from the app.
takePictureIntent.setFlags(0);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, _photoUri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
private Uri createImageUri() {
return FileProvider.getUriForFile(this
, this.getApplicationContext().getPackageName()
, new File(Environment.getExternalStorageDirectory()
, "orderphoto.jpg"));
}
this tells the camera where to put the photo.
check in your activity result for RESULT_OK to ensure they didn't cancel.
You'll need to then be able to read from the file system. Here's how our app does it: Note i can't be positive i'm not referencing a custom function in this. YMMV.
private Bitmap DecodeFile(Uri fileUri) {
/* There isn't enough memory to open up more than a couple camera photos */
/* So pre-scale the target _bitmap into which the file is decoded */
/* Get the size of the ImageView */
int targetW = _imageView.getWidth();
int targetH = _imageView.getHeight();
/* Get the size of the image */
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileUri.getPath(), bmOptions);
// TODO: 2/25/2019 Update to BitmapFactory.decodeStream()
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
if (photoW == 0 || photoH == 0) {
AppUtility.ShowToast("BitmapFactory.Decode: File Decoding Failed!");
}
/* Figure out which way needs to be reduced less */
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
/* Set _bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
/* compress/shrink the bitmap */
// TODO: 2/25/2019 Update to BitmapFactory.decodeStream()
return BitmapFactory.decodeFile(fileUri.getPath(), bmOptions);
}
When you use this, it does all the hard work for you and sizes it to the screen. Note that some samsung devices lie about the orientation so you may have problems about that.

how to crop image to square - android?

so i have a profile activity with a profile image. Now the image that was taken vertically. And I have horizontal image views. When i grab images onActivityResult() how do i "square" the image. By square the image, I mean, I want each image's width to be the width of the screen (and since its a square, height = image width = screen width).
In onActivityResult() i get the image from my gallery and camera back as a string path (which i can convert to a bitmap). Additionally, when i get images i get them from my backend using the Glide library and a url.
Glide.with(context).load("www.mybackendToImagePath").centerCrop().into(newImageView);
So, I need to convert that image path into a bitmap and then somehow square that bitmap with my screen's width. I'm not sure what code allows me to:
get the dimensions of the device.
transform's the image's width and height, to the width of the device.
Hope you guys can help!
Heres what my profile activity looks like.
You can use this https://github.com/Yalantis/uCrop library to crop image you get from camera or gallery. Include the library as local library project
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
Add Dependencies
compile 'com.github.yalantis:ucrop:2.2.1'
or
compile 'com.github.yalantis:ucrop:2.2.1-native'
Add UCropActivity into your AndroidManifest.xml
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="#style/Theme.AppCompat.Light.NoActionBar"/>
Now pass the URI of your image as sourceUri in following code and destinationUri will be where you want to place your cropped image
UCrop.of(sourceUri, destinationUri)
.withAspectRatio(1, 1)//1, 1 is the ratio b/w width and height of image i.e. square you can pass any ratio here
.withMaxResultSize(maxWidth, maxHeight)
.start(context);
Override onActivityResult method and handle uCrop result.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == UCrop.REQUEST_CROP) {
final Uri resultUri = UCrop.getOutput(data);
} else if (resultCode == UCrop.RESULT_ERROR) {
final Throwable cropError = UCrop.getError(data);
}
}

Android cropped image quality issue

I am trying to save an image as cropped from android and then show it in my app. I am using the code below, but when I try to view the image in my app the image quality is not good as in the attached image. Am doing anything wrong? Any help would be great.
My code is:
dipToPixel = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == getActivity().RESULT_OK && data != null) {
picUri = data.getData();
performCrop();
}
if (requestCode == 111 && resultCode == getActivity().RESULT_OK && data != null) {
Bundle extras = data.getExtras();
Bitmap bitmapImage = extras.getParcelable("data");
tweetImage.setImageBitmap(bitmapImage);
tweetImage.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
tweetImage.getViewTreeObserver().removeOnPreDrawListener(this);
widthPixel = tweetImage.getMeasuredWidth();
heightPixel = tweetImage.getMeasuredHeight();
return true;
}
});
System.out.println("photo added");
addPhotoVar = 1;
addPhotoBtn.setText("remove");
}
callbackManager.onActivityResult(requestCode, resultCode, data);
}
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(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", Math.round(screenWidth / dipToPixel)-10);
cropIntent.putExtra("outputY", Math.round(screenWidth / dipToPixel)-10);
//retrieve data on return
cropIntent.putExtra("return-data", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, 111);
}
// 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(getActivity(), errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
Below is the code that I use the image and save to database:
tweetImage.buildDrawingCache();
bm = tweetImage.getDrawingCache();
if (widthPixel < heightPixel) {
basePixel = widthPixel;
}
else {
basePixel = heightPixel;
}
if (basePixel > 768) {
widthRatio = (float) 768/basePixel;
heightRatio = (float) 768/basePixel;
}
else {
widthRatio = 1;
heightRatio = 1;
}
Bitmap bmResized = Bitmap.createScaledBitmap(bm,(int)(widthPixel*widthRatio), (int)(heightPixel*heightRatio), true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmResized.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byteArray1 = stream.toByteArray();
image1 = new ParseFile("profilePhoto.jpg", byteArray1, "image/jpg");
Use this library, this library manage cropped image quality as well it keeps both image Crop Library
Change :
bmResized.compress(Bitmap.CompressFormat.JPEG, 100, stream);
to :
bmResized.compress(Bitmap.CompressFormat.PNG, 100, stream);
Since JPEG format uses a lossy compression, you should use PNG to save the bitmap, if you don't want quality loss.
Also, you should avoid using com.android.camera.action.CROP intent as it doesn't exist on all the devices as explained here.
There are some alternatives listed on the above link, you may use one of them.
Please refer this link :
https://commonsware.com/blog/2013/01/23/no-android-does-not-have-crop-intent.html
Here are some libraries to consider for image crop:
https://github.com/lvillani/android-cropimage
https://github.com/biokys/cropimage
https://github.com/MMP-forTour/cropimage (forked from the above one)
https://github.com/dtitov/pickncrop

keep imageview after orient change

I get an image from the camera or gallery and set it to my imageview. Unfortunately when the screen gets rotated the imageview shows nothing.
How can I keep the image visible ?
This is the code where I get the image :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case REQUEST_IMAGE_CAPTURE:
// if taking
if (resultCode == RESULT_OK && null != data && TAKE_OR_PICK == 1) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
int width = imageBitmap.getWidth();
int height = imageBitmap.getHeight();
if(height>width) {
int crop = (height - width) / 2;
Bitmap cropImg = Bitmap.createBitmap(imageBitmap, crop, 0, width, width);
image.setImageBitmap(cropImg);
}
else if (width>height){int crop = (width - height) / 2;
Bitmap cropImg = Bitmap.createBitmap(imageBitmap, crop, 0, height, height);
image.setImageBitmap(cropImg);}
else {image.setImageBitmap(imageBitmap);}
}
break;
case RESULT_LOAD_IMAGE:
// if choosing
if (resultCode == RESULT_OK && null != data && TAKE_OR_PICK == 2) {
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();
Bitmap imageBitmap = BitmapFactory.decodeFile(picturePath);
int width = imageBitmap.getWidth();
int height = imageBitmap.getHeight();
if(height>width) {
int crop = (height - width) / 2;
Bitmap cropImg = Bitmap.createBitmap(imageBitmap, crop, 0, width, width);
image.setImageBitmap(cropImg);
}
else if (width>height){int crop = (width - height) / 2;
Bitmap cropImg = Bitmap.createBitmap(imageBitmap, crop, 0, height, height);
image.setImageBitmap(cropImg);
}
else {image.setImageBitmap(imageBitmap);}
}
I've tried to use onSaveInstanceState() but can't get it to work for a bitmap. Is there another way to achieve this ?
There are generally three ways to do this:
As some of the answers suggested, you could distinguish the cases of
your activity being created for the first time and being restored
from savedInstanceState. This is done by overriding
onSaveInstanceState and checking the parameter of onCreate.
2.You could lock the activity in one orientation by adding android:screenOrientation="portrait" (or "landscape") to
in your manifest.
3.You could tell the system that you meant to handle screen changes for yourself by specifying
android:configChanges="orientation" in the tag. This way
the activity will not be recreated, but will receive a callback
instead (which you can ignore as it's not useful for you)
as Gazi said if the user is not allowed to rotate the screen that "close" the option via the Manifest.
if it's not relevant you shall have a function that
fillAllData()
that is called within "onResume" and inside the function if you have the bitmap add it into the image (you can keep it with onSaveInstance)
private ImageView mMyImageView;
private String tempFileName;
onCreate(){
setContentView(R.layout.myLayout);
mMyImageView = (ImageView)findViewById(R.id.myImageView);
}
onActivityResult(){
//do all your code plus this:
tempFileName = random string;
save bitmap after process in tempFileName
update in application some flag that a temp file image is available;
}
onResume(){
if temp file name is available load bitmap into your image view.
}
What happening in your case is, if you rotate your device the activity is recreated.Try adding the below inside activity tag of your AndroidManifest.xml file. Hope this helps.
android:configChanges="orientation | screenSize"

Memory/Allocation errors when setting ImageButton from Camera Photo

I am trying to take a photo from the phones camera and place in it in a ImageButton as part of a Profile activity including all users details, and then save the image as shared pref.
If I use the following code the ImageButton simply does not update:
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
// method checks data returned form camera via startActivityForResult
super.onActivityResult(requestCode, resultCode, data);
Runnable runnable = new Runnable(){#Override
public void run() {
handler.post(new Runnable(){
#Override
public void run() {
Bundle extras = data.getExtras();
photo = (Bitmap) extras.get("data");
takeAndSetPhoto.setImageBitmap(photo);
Toast.makeText(getBaseContext(), "Image set to profile!",
Toast.LENGTH_SHORT).show();
}//edn inner run
});//end new runnab;e
}
};
new Thread(runnable).start();
}//end if result OK
}// end onActivity
Alternatively the image DOES load if I use this method but I get erros:
Allocation fail for scaled Bitmap
Out Of Memory 01-03 10:13:06.645: E/AndroidRuntime(30163):
android.view.InflateException: Binary XML file line #18: Error
inflating class
The code is using Uro for phot taken:
public void run() {
Bundle extras = data.getExtras();
Uri photoShot = data.getData(); view
takeAndSetPhoto.setImageURI(photoShot);
Toast.makeText(getBaseContext(), "Image set to profile!",
Toast.LENGTH_SHORT).show();
}//edn inner run
All suggestions appreciated.
Cheers
Ciaran
Resizing Image:
When resizing the image:
Bitmap photoBitmap = Bitmap.createScaledBitmap(photo, 100, 100, false);
It works fine on the emulator with SD card activated, but crashes on a real device (a tablet 8inch)
Problem was I was not resizing image when taken form device phone, passed image to this method before setting to the image view:
public Bitmap reSizeImage(Bitmap bitmapImage) {
// resize bitmap image passed and rerun new one
Bitmap resizedImage = null;
float factorH = h / (float) bitmapImage.getHeight();
float factorW = w / (float) bitmapImage.getWidth();
float factorToUse = (factorH > factorW) ? factorW : factorH;
try {
resizedImage = Bitmap.createScaledBitmap(bitmapImage,
(int) (bitmapImage.getWidth() * factorToUse),
(int) (bitmapImage.getHeight() * factorToUse), false);
} catch (IllegalArgumentException e) {
Log.d(TAG, "Problem resizing Image #Line 510+");
e.printStackTrace();
}
Log.d(TAG,
"in resixed, value of resized image: "
+ resizedImage.toString());
return resizedImage;
}// end reSize

Categories

Resources