I've found a very interesting problem. After taking a camera picture (I hold the device in portrait mode, and not rotating), the given photo is sometimes rotated, but not always. I know, some device give always rotated photo, but it can be rotated with exif or mediastore information. But in this case, exif and mediastore says orientation is 0, but the image is rotated. The most frustrating thing this comes totally randomly. The code is very simple:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, currentFileUri);
startActivityForResult(intent, RequestCodeCollection.CAMERA_IMAGE_CAPTURE);
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
try {
oldImageExifInterface = new ExifInterface(currentFileUri.getPath());
}
}
Have anybody seen this problem? I experienced on Galaxy Nexus after OS update (4.1.1)
Try this.
try {
File f = new File(imagePath);
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f),
null, options);
bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), mat, true);
ByteArrayOutputStream outstudentstreamOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100,
outstudentstreamOutputStream);
imageView.setImageBitmap(correctBmp);
} catch (IOException e) {
Log.w("TAG", "-- Error in setting image");
} catch (OutOfMemoryError oom) {
Log.w("TAG", "-- OOM Error in setting image");
}
Related
I have created a custom camera. When I click on the capture button in the application, image has been taken. Moreover, I am getting the data in the form of byte array in the function named as onPictureTaken.
I am converting the byte array into the bitmap using the library known as Glide.
My problem is that in Samsung device the images rotates itself. I have been researching on it for quite a while. I found the library called as metadata extraction library to get the Exif information from byte[] and rotate the image on it but it is not working on the Samsung devices. The metadata extraction library every time returns a value of 1 for portrait image which shows that image does not need rotation however, the image taken in portrait mode is always 90 degree rotated.
Whenever, the photo is taken in portrait mode it is rotated at an angle of 90 degrees for both front and back camera and meta extraction library shows a value of 1.
Is there something other then metadata extraction extraction library which extract Exif information stream data?
Note: I cannot use ExifInterface because it requires the minimum Api level of 24 whereas, I am testing on API level 22
I have tried many solution but nothing is working. Is there any solution for this?
The code is given below:
public void onPictureTaken(byte[] data, Camera camera) {
mCamera.stopPreview();
Glide.with(this).load(data)
.asBitmap().centerCrop().animate(R.anim.abc_fade_in)
.into(new SimpleTarget<Bitmap>(width, height) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
camera_view.setVisibility(View.INVISIBLE);
int w = resource.getWidth();
int h = resource.getHeight();
// Setting post rotate to 90
Matrix mtx = new Matrix();
try {
InputStream is = new ByteArrayInputStream(data);
Metadata metadata = ImageMetadataReader.readMetadata(is);
final ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
final int exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
switch (exifOrientation) {
case 6:
mtx.postRotate(90);
break; // top left
case 3:
mtx.postRotate(180);;
break; // top right
case 8:
mtx.postRotate(270);
break; // bottom right
}
photo = Bitmap.createBitmap(resource, 0, 0, w, h, mtx, true);
/* Work on exifOrientation */
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am using Samsung J5 for the testing.
You don't need a library for this. Here is a couple methods that I wrote that should do the trick for you.
public static int getCapturedImageOrientation(Context context, Uri imageUri){
int rotate = 0;
try {
context.getContentResolver().notifyChange(imageUri, null);
File imageFile = new File(imageUri.getPath());
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
Log.i("RotateImage", "Exif orientation: " + orientation);
Log.i("RotateImage", "Rotate value: " + rotate);
} catch (Exception e) {
Log.e(TAG, "Error getting rotation of image");
}
return rotate;
}
public static int GetRotateAngle(Context context, Uri imageUri) {
String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION };
Cursor cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
if (cursor == null) {
//If null, it is not in the gallery, so may be temporary image
return getCapturedImageOrientation(context, imageUri);
}
cursor.moveToFirst();
int orientationColumnIndex = cursor.getColumnIndex(columns[1]);
int orientation = cursor.getInt(orientationColumnIndex);
cursor.close();
return orientation;
}
I wrap these in a class called ImageHelper. You can use it like this:
rotateImage(ImageHelper.GetRotateAngle(Context, mCropImageUri));
Then of course the rotateImage code would be:
private void rotateImage(int degrees) {
Matrix mat = new Matrix();
mat.postRotate(degrees);
mCropImage = Bitmap.createBitmap(mCropImage, 0, 0, mCropImage.getWidth(), mCropImage.getHeight(), mat, true);
setImageForCropping(mCropImage);
}
Of course i was doing all this for a photo editing, cropping and scaling app, so you can ignore some of the extras, but this should take care of ya. Goodluck.
Almost in all Samsung Devices the image rotation Issue is common ,in my case i am using Samsung Note 3 and this same issue occurs but i am using below code to solve this issue
public static Bitmap decodeFile(String path) { // this method is for avoiding the image rotation
int orientation;
try {
if (path == null) {
return null;
}
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 4;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("orientation", "" + orientation);
Matrix m = new Matrix();
if ((orientation == 3)) {
m.postRotate(180);
m.postScale((float) bm.getWidth(), (float) bm.getHeight());
// if(m.preRotate(90)){
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
} else if (orientation == 6) {
m.postRotate(90);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
} else if (orientation == 8) {
m.postRotate(270);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
}
return bitmap;
} catch (Exception e) {
}
return null;
}
This code is work for me so i hope this will helpful for you
This can be easily fixed by using ExifInterface provided by Google.
You can add it to your project as follows:
implementation "androidx.exifinterface:exifinterface:1.1.0"
After this, get the rotation from your image and apply it to your ImageView:
// uri of the image
val inputStream = contentResolver.openInputStream(Uri.parse(uri))
val exifInterface = ExifInterface(requireNotNull(inputStream))
var rotation = 0
when (exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
ExifInterface.ORIENTATION_ROTATE_90 -> rotation = 90
ExifInterface.ORIENTATION_ROTATE_180 -> rotation = 180
ExifInterface.ORIENTATION_ROTATE_270 -> rotation = 270
}
I am using android:hardware:camera API to make custom camera . i have done to make the camera but problem is that after taking picture from camera the pic save in rotated form.I am using Surface View for the Camera .
this is Camera setting function on surface-created
try {
File f = new File(imagePath);
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f),
null, options);
bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), mat, true);
ByteArrayOutputStream outstudentstreamOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100,
outstudentstreamOutputStream);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
Log.w("TAG", "-- Error in setting image");
} catch (OutOfMemoryError oom) {
Log.w("TAG", "-- OOM Error in setting image");
}
try this after capture image from camera to rotate.
You can use below method to show/save image in actual orientation.
public static Bitmap setImage(String filePath, Bitmap bitmap){
File curFile = new File(filePath);
Bitmap rotatedBitmap = null;
try {
ExifInterface exif = new ExifInterface(curFile.getPath());
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
Matrix matrix = new Matrix();
if (rotation != 0.0f) {matrix.preRotate(rotationInDegrees);}
rotatedBitmap = Bitmap.createBitmap(bitmap,0,0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}catch(IOException ex){
ex.printStackTrace();
}
return rotatedBitmap;
}
private static int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; }
return 0;
}
I have an app that the client has asked to add rotation support.
Below is the current code that takes the image from the camera.
camera.takePicture(null, null, new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
Matrix mtx = new Matrix();
mtx.postRotate(180);
float density = Resources.getSystem().getDisplayMetrics().density;
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
Bitmap scaled = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), mtx, true);
bm = Bitmap.createScaledBitmap(scaled, (int)(480*density), (int)(320*density), true); //height and width are backwards because its portrait
previewImage(bm);
}
}
});
What I am trying to work out is the quickest way to work out what orientation the captured bitmap should be in, i.e when the user takes a picture with the device in landscape we need to flip:
Bitmap.createScaledBitmap(scaled, (int)(480*density), (int)(320*density), true);
to:
Bitmap.createScaledBitmap(scaled, (int)(320*density), (int)(480*density), true);
and also change the mtx.postRotate
My issue is working out the best way to find out what rotation the image was taken in.
Try this
private Bitmap checkForRotation(String filename, Bitmap bitmap) {
Bitmap myBitmap = bitmap;
ExifInterface ei = null;
try {
ei = new ExifInterface(filename);
new ExifInterface(filename);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
//Here you get the orientation and do what ever you want to do with it as i am rotating the image
case ExifInterface.ORIENTATION_ROTATE_90:
myBitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
myBitmap = rotateImage(bitmap, 180);
break;
}
return myBitmap;
}
I want to set background image for a view using Intent.ACTION_GET_CONTENT and handled onActivityResult method as...
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
try {
InputStream inputStream =
getContentResolver().openInputStream(selectedImageUri);
Drawable drawable = Drawable.createFromStream(inputStream,
selectedImageUri.toString());
mView.setBackground(drawable);
} catch(FileNotFoundException e) {}
}
}
It works fine for some images from gallary but not for all images. Image orientation get changed after selecting some image.
Try below code:-
try {
File f = new File(imagePath);
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f),
null, options);
bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), mat, true);
ByteArrayOutputStream outstudentstreamOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100,
outstudentstreamOutputStream);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
Log.w("TAG", "-- Error in setting image");
} catch (OutOfMemoryError oom) {
Log.w("TAG", "-- OOM Error in setting image");
}
I'm trying to rotate the image taken from camera and save it without scaling down without showing in an view, but when I try to load it like this
Bitmap bmp = BitmapFactory.decodeFile(tmpImageFilePath);
I get OutOfMemoryError. There is no problem for me to rotate image but how to load it and save with original size? I've already googled some techniques in order to solve this problem but none of them fits me.
And when I try this variant:
File f = new File(tmpImageFilePath);
long filesize = f.length();
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bmp = BitmapFactory.decodeFile(tmpImageFilePath, options);
Bitmap correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);
bmp.recycle();
try {
FileOutputStream out = new FileOutputStream(f);
correctBmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
I get lesser image.