I have this code:
//choosed a picture
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == ImageHelper.SELECT_PICTURE) {
String picture = "";
Uri selectedImageUri = data.getData();
//OI FILE Manager
String filemanagerstring = selectedImageUri.getPath();
//MEDIA GALLERY
String selectedImagePath = ImageHelper.getPath(mycontext, selectedImageUri);
picture=(selectedImagePath!=null)?selectedImagePath:filemanagerstring;
...
This is only a picture chooser, from gallery. This is nice, but when I open this picture on an ImageView, the images when took on "PORTRAIT MODE" with the camera look nice, but the images that took "LANDSCAPE MODE" with the camera, opening in -90 degrees.
How can i rotate those pictures back?
Bitmap output = Bitmap.createBitmap(newwidth, newheight, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
I tried this:
Log.e("w h", bitmap.getWidth()+" "+bitmap.getHeight());
if (bitmap.getWidth()<bitmap.getHeight()) canvas.rotate(-90);
But this is not working, all image size is: *2560 1920 pixel (PORTRAIT, and LANDSCAPE mode all)
What can I do to rotate back the LANDSCAPE pictures?
If a photo is taken with a digital camera or smartphone, rotation is often stored in the photo's Exif data, as part of the image file. You can read an image's Exif meta-data using the Android ExifInterface.
First, create the ExifInterface:
ExifInterface exif = new ExifInterface(uri.getPath());
Next, find the current rotation:
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Convert exif rotation to degrees:
int rotationInDegrees = exifToDegrees(rotation);
where
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;
}
Then use the image's actual rotation as a reference point to rotate the image using a Matrix.
Matrix matrix = new Matrix();
if (rotation != 0) {matrix.preRotate(rotationInDegrees);}
You create the new rotated image with the Bitmap.createBitmap method that take a Matrix as a parameter:
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
where Matrix m holds the new rotation:
Bitmap adjustedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true);
See this tutorial for a useful source code example:
Read Exif information in a JPEG file.
if you are Using Jetpack CameraX, inside onImageCaptured method you can access rotation degree provided by EXIF data from the imageProxy like this:
image.imageInfo.rotationDegrees
then while setting your image you can rotate your image according to this degree
Last answer was technically perfect, but I tried hard to create a system to manage pictures, rotate, resize, cache and load into ImageViews and I can tell it is a hell. Even when all it was done it crashes sometimes cause OutOfMemory in some devices.
My point is do not reinvent the wheel, it has a perfect design. Google itself encourage you to use Glide. It works in one line, super easy to use, lightweight in size and functions number, it manage EXIF by default, and it use memory like a charm.. It is simply black magic coded ;)
I'm not sure if Picasso also manages EXIF, but there is a quick intro to both of them:
https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
My Advice: do not waste your time and use them. You can solve your problem in one line:
Glide.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Related
I'm loading the camera as an intent and saving to a local file:
Intent capturePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
capturePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriPhoto);
startActivityForResult(capturePhotoIntent, REQUEST_IMAGE_CAPTURE);
Some mobile phones are saving the image in the incorrect orientation. Where a photo is captured with the mobile phone held in portrait, the saved image is rotated 90 degrees to landscape.
Most phone cameras are landscape, therefore I understand this is why the rotation occurs. The camera application should populate the image file with the correct orientation within the EXIF data.
I understand that I could use Glide to display the captured image within the application and this will automatically handle the rotation for me.
Glide.with(myContext).load(photoFilePaths.get(iPosition)).into(myViewHolder.getPhotoImageView());
However, I believe that this rotates the image in the ImageView each time it is loaded - could Glide be used to rotate and save the image within the correct orientation onActivityResult?
I've seen the following could be an alternative, however this relies on the correct orientation being set within the EXIF data:
ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap rotatedBitmap = null;
switch(orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
...
}
public static Bitmap rotateImage(Bitmap source, float angle)
{
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
Glide appears to be more consistent at displaying an image in the correct orientation, so I'm guessing it follows a different approach that could provide better results when saving the image. The image needs to be uploaded to a web server in the correct orientation, rather than just displaying within the Android application.
This question already has answers here:
How to detect when the device switch from portrait to landscape mode? [duplicate]
(4 answers)
Closed 4 years ago.
I am making an application in which I have to take a picture every one second in a service without launching the camera preview.
I wrote the following code in service and able to take picture.
if (cameraId < 0) {
Log.d(TAG, "No camera found");
}
else
{
camera = Camera.open(cameraId);
camera.startPreview();
}
camera.takePicture(null, null, bitmapHandler);
In the bitmapHandler class I get the capture image data in
#Override
public void onPictureTaken(byte[] data, Camera camera) {
.
.
.
}
when I take the picture in portrait mode, the resultant image is rotated by 90 degree clockwise.
when I take the picture in landscape mode, the resultant image is proper.
when I take the picture in reverse-landscape mode, the resultant image is rotated by 180 degree
when I take the picture in reverse-portrait mode, the resultant image is rotated by 270 degree
What i did to get proper image so that I can feed that image to my neural network.
What I tried : I am rotating the bitmap by 90 when image was taken in portrait mode, but still not able to find in which mode the image was captured.
Does the Camera API have any way to know or control the rotation angle ?
I was using the function fixImageOrientation, parameters are image itself and path to the image file (as second parameter, I was passing the path where camera activity stores temporary image file)
public static Bitmap rotateImage(Bitmap bmp, float angle)
{
Matrix matrix = new Matrix();
matrix.postRotate(angle);
System.out.println("Rotating image " + Float.toString(angle) + " degrees, rotateImage()");
return Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
public static Bitmap fixImageOrientation(Bitmap bmp, String path)
{
ExifInterface ei;
boolean changed = true;
try {
ei = new ExifInterface(path);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
bmp = rotateImage(bmp, 90);
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
bmp = rotateImage(bmp, 180);
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
bmp = rotateImage(bmp, 270);
else
changed = false;
} catch (IOException e){
System.out.println("IOException, image probably has no exif data, fixImageOrientation()");
e.printStackTrace();
}
if (changed)
{
System.out.println("Image orientation fixed, fixImageOrientation()");
}
else
{
System.out.println("Image orientation did not change, fixImageOrientation()");
}
return bmp;
}
So i got this simple app, open the camera (either front or back), take a picture, post it.
I managed to get a straight preview, despite the display orientation.
The problem is when I get the picture. If for example I take a photo with different devices in portrait mode, the resulting pictures are rotated of different angles, depending which device was used.
All I'm asking is simple: do you know how I can get straight pictures (either portrait or landscape, according to the rotation) and make sure it works on every device?
Well' if any of you has a solution,please share it,I'll be eternally grateful!
Different devices use different orientations on their pictures by default. This can be annoying. What you need to do is find that orientation, and flip the image correspondingly.
Here's some code that I use in my application:
Note: I'm sure this isn't perfect. If anyone has suggestions on how to improve this, please feel free to comment/edit!
private int getOrientation(String pathToYourImage) throws IOException{
ExifInterface exif = new ExifInterface(path);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
if (rotation == ExifInterface.ORIENTATION_ROTATE_90){
return 90;
} else if (rotation == ExifInterface.ORIENTATION_ROTATE_180){
return 180;
} else if (rotation == ExifInterface.ORIENTATION_ROTATE_270){
return 270;
}
return 0;
}
then something like
if (orientation > 0){
originalImage = rotateBitmap(originalImage, orientation);
}
private Bitmap rotateBitmap(Bitmap srcBitmap, int angle){
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotatedBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true);
srcBitmap.recycle();
return rotatedBitmap;
}
This might not completely suit your needs, but it works well enough for me. Ask if you have any more questions!
I've written an app to capture an image. The problem is that the image is rotated 90 degrees after the capture. I've setted the
camera.setDisplayOrientation(NINTY_DEGREES);
But this only affects the previewing of the SurfaceView. The real problem is that the bytes I get from the camera is flipped. Why does this happend? Is there a setting I can set to flip it before capture?
I my activity subcribes to an event, when the image is captured. This is how I register when the byte[] is filled:
camera.takePicture(null, null, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
if (null != callback)
callback.onJpegPictureTaken(data, camera);
}
});
In my Activity
public class History extends BaseWindow implements OnClickListener, CaptureImageCallback
and the relevant method:
#Override
public void onJpegPictureTaken(byte[] data, Camera camera) {
Intent i = new Intent(this, ImageEditing.class);
i.putExtra("image", data);
startActivity(i);
}
You can see the parameter data which contains the image data, this byte array is rotated 90 degress. I could of course rotate the ImageView 90 degress, but since I will work with other systems, such as a homemade webservice, I would need to apply this hot fix to every external system. How can I correct this rotation?
Thanks!
You can get the "Angle" of your captured image and rotate as per angle.
ExifInterface exif = new ExifInterface(imagePath);
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;
}
Log.d("Tag", "Angle: " + angle);
Matrix mat = new Matrix();
mat.postRotate(angle);
if (angle != 0)
Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), mat, true);
As name indicates setDisplayOrientation() is for display only. Doc says:
This does not affect the order of byte array passed in
onPreviewFrame(byte[], Camera), JPEG pictures, or recorded videos
So if you want to save rotated image, you need to rotate it yourself prior saving.
This question already has answers here:
Why does an image captured using camera intent gets rotated on some devices on Android?
(23 answers)
Closed 4 years ago.
I have had a look around but there doesn't seem to be a solid answer/solution to the, very irritating, problem.
I take a picture in portrait orientation and when I hit save/discard the buttons are in the correct orientation also. The problem is when I then retrieve the image later on it is in landscape orientation (the picture has been rotated 90 degrees anti-clockwise)
I don' want to force the user to use the camera in a certain orientation.
Is there a way to maybe detect whether the photo was taken in portrait mode and then decode the bitmap and flip it the correct way up?
The picture is always taken in the orientation the camera is built into the device. To get your image rotated correctly you'll have to read the orientation information that is stored into the picture (EXIF meta data). There it is stored how the device was oriented, when the image was taken.
Here is some code that reads the EXIF data and rotates the image accordingly:
file is the name of the image file.
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(file, opts);
ExifInterface exif = new ExifInterface(file);
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);
UPDATE 2017-01-16
With the release of the 25.1.0 Support Library, an ExifInterface Support Library was introduced, which should perhaps make the access to the Exif attributes easier. See the Android Developer's Blog for an article about it.
The selected answer uses the most common method answered to this and similar questions. However, it did not work for me with both front and back cameras on Samsung. For those needing another solution which works across both front and back cameras for Samsung and other major manufacturers, this answer by nvhausid is awesome:
https://stackoverflow.com/a/18915443/6080472
For those who don't want to click through, the relevant magic is to use the CameraInfo rather then relying on EXIF or a Cursor over the media files.
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);
Full code in the link.