Auto Image Rotated from Portrait to Landscape - java

I am taking photo and storing it into SD Card , and later viewing it from SD Card into ImageView, but getting as rotated ...
I am capturing it in Portrait mode , but getting resultant image in Landscape mode...
Is there something which I am missing ?
ExifUtil.java class found here
/**
* Displaying captured image/video on the screen
* */
private void previewMedia(boolean isImage) {
// Checking whether captured media is image or video
if (isImage) {
imgPreview.setVisibility(View.VISIBLE);
final Bitmap bitmap = BitmapFactory.decodeFile(filePath);
Bitmap orientedBitmap = ExifUtil.rotateBitmap(filePath, bitmap);
imgPreview.setImageBitmap(orientedBitmap);
} else {
imgPreview.setVisibility(View.GONE);
}
}
but still showing rotated image in a ImageView ...

If the image(photo) were taken by a program made by you, you must set Parameters.setRotation with the correct rotation value.
This, depending of camera drive, rotates the image before save or save the rotation value to exif TAG_ORIENTATION.
Therefore, if TAG_ORIENTATION is null or zero, the image are in the correct orientation, otherwise you must rotate image according the value in TAG_ORIENTATION.
CODE
Get orientation from EXIF:
ExifInterface exif = null;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Get bitmap rotated:
Bitmap bmRotated = rotateBitmap(bitmap, orientation);
Method to rotate bitmap:
public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
return bitmap;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try {
Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return bmRotated;
}
catch (OutOfMemoryError e) {
e.printStackTrace();
return null;
}
}
Source - https://stackoverflow.com/a/20480741/3036759

You need to use EXIF with ORIENTATION_UNDEFINED to get right orientation.
ExifInterface exif = null;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
And rotate the Bitmap :
Bitmap bmRotated = rotateBitmap(bitmap, orientation);
Reference link

Related

How to fix uploaded image auto rotate problem in java

I am using java and vaadin 14 as a web framework.
In vaadin i am using Vaadin Uploader component to upload an image from camera or image gallery on android phone .
When i choose an image from gallery then it's uploaded and shows normally. But when i am trying to upload an image from phone camera in particular device(samsung) then uploaded image rotated automatically That means, uploaded image shows in portrait if captured in landscape and if captured in portrait it shows landscape. how to solve it?
Note: It does not happen in all android devices. Only in samsung android devices like samsung s7.
here is my code-
import com.vaadin.flow.component.upload.SucceededEvent;
import com.vaadin.flow.component.upload.Upload;
private void fileUploaderInit() {
uploader = new Upload(buffer);
uploader.setMaxFiles(1);
uploader.setDropAllowed(false);
uploader.setAcceptedFileTypes("image/*");
uploader.getElement().removeProperty("capture");
uploader.setUploadButton(image);
uploader.addSucceededListener(event -> {
succeedEvent = event;
saveUploadedImage();
setUserImage();
});
uploader.getElement().addEventListener("file-abort", remove -> {
succeedEvent = null;
});
uploadLayout.add(uploader);
}
private void saveUploadedImage() {
if (succeedEvent != null && userEntity != null) {
addData();
succeedEvent = null;
Notification.show("Image saved successfully.",2000, Position.MIDDLE);
userEvent.fire(new UserEvent(userEntity,false));
}
uploader.getElement().setPropertyJson("files", Json.createArray());
}
I usually use Retrofit for uploading image and files but it is not related uploading service.
It just is related to camera image processing.
Let me show you my code to fix rotation issue.
public Bitmap getImageFromPath(String photoPath) {
Bitmap bitmap = BitmapFactory.decodeFile(photoPath);
Bitmap rotatedBitmap = bitmap;
ExifInterface ei = null;
try {
ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch(orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotatedBitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotatedBitmap = rotateImage(bitmap, 270);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
rotatedBitmap = bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return rotatedBitmap;
}
After taking image from Camera, you save it to android directory and you should detect its orientation and rotate like this code.
Good luck.

Android - Activity orientation stuck after Camera Activity

In our application, the user presses a button which opens the Android default camera activity.
Snippet on how we start the camera activity:
Uri uri = FileProvider.getUriForFile(this, FILE_PROVIDER, image);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, 1);
The problem is if the Activity is in portrait mode, everything works fine, camera is in portrait mode, image gets saved in the correct orientation, etc.
In landscape mode though, the camera starts and after returning the activity is stuck in portrait mode and does not change by tilting the phone anymore.
Does anyone know a solution for this problem?
EDIT: code of onActivityResult(...)
EDIT2: resolved custom methods
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CAMERA_ACTIVITY_CODE && resultCode == Activity.RESULT_OK) {
//returns Filehandler to image
File objektImage = getImageForObjekt(loadedObjekt);
correctImageRotation(objektImage);
//ImageView
this.imgObjekt.setImageDrawable(Drawable.createFromPath(objektImage.getAbsolutePath()));
}
}
This method corrects the image rotation - cameras on Samsung phones stored them in the wrong orientation which is corrected here:
public boolean correctImageRotation(File img) {
ExifInterface ei;
try {
ei = new ExifInterface(img.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
return false;
}
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Log.d(this._LOGKEY, getLogPraefix()+" Store the new Objekt image to: " + img.getName());
Bitmap bm = BitmapFactory.decodeFile(img.getAbsolutePath());
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
bm = rotateImage(bm, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
bm = rotateImage(bm, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
bm = rotateImage(bm, 270);
break;
}
bm = ImageHelper.squarify(bm);
bm = ImageHelper.compress(bm, ImageHelper.Size.large);
try {
FileOutputStream stream = new FileOutputStream(img);
bm.compress(Bitmap.CompressFormat.JPEG, 90, stream);
stream.flush();
stream.close();
return true;
} catch (FileNotFoundException e) {
Log.e(_LOGKEY, getLogPraefix()+": file not found.");
return false;
} catch (IOException e) {
Log.e(_LOGKEY, getLogPraefix()+": IO problem.");
return false;
}
}
This method cuts the image s.t. it is square-shaped afterwards:
public static Bitmap squarify(Bitmap srcBmp) {
Bitmap dstBmp;
if (srcBmp.getWidth() >= srcBmp.getHeight()){
dstBmp = Bitmap.createBitmap(
srcBmp,
srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
0,
srcBmp.getHeight(),
srcBmp.getHeight()
);
}else{
dstBmp = Bitmap.createBitmap(
srcBmp,
0,
srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
srcBmp.getWidth(),
srcBmp.getWidth()
);
}
return dstBmp;
}
And finally this method compresses the image in one of three possible sizes:
public static Bitmap compress(Bitmap srcBmp, Size size) {
int side;
switch (size) {
default:
case small:
side = 200;
break;
case medium:
side = 400;
break;
case large:
side = 800;
break;
}
return Bitmap.createScaledBitmap(srcBmp, side, side, true);
}

FileNotFoundException when Using ExifInterface

I have been uploading images to FirebaseStorage, but often they are the wrong way around when displaying them. I have discovered the ExifInterface that can determined the orientation of the image and rotate and flip it if necessary.
When selecting the image from the gallery area on my phone I get this error.
I can select the image on my phone from the gallery and It can be displayed on the page.
The differences between the URI address and the data is one /
Data.getData() address : content://media/external/images/media/53331
uri.toString() address: content:/media/external/images/media/53331
I'm using the uri address as the images absolute path of the image to be able to rotate it if necessary. I pass this value into another method called modifyOrientation which then rotates it. Once it is passed into the method it reaches the line
ExifInterface ei = new ExifInterface(image_absolute_path);
and then returns to the catch as the file was not found.
Below is the entire error I'm getting as well as all my code. How can I fix this issue that I'm having. So when I pass the URI across into the next method it actually has the correct address.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
final FirebaseUser user = auth.getCurrentUser();
if (requestCode == GALLERY_INTENT && resultCode == RESULT_OK)
{
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Displaying Image...");
progressDialog.show();
//imageUri = data.getData();
//Picasso.get().load(imageUri).into(profileImage);
final Uri uri = data.getData();
File file = new File(uri.toString());
file.getAbsolutePath();
progressDialog.dismiss();
try
{
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);
modifyOrientation(bitmap,file.getAbsolutePath());
profileImage.setImageBitmap(bitmap);
}
catch(IOException e)
{
e.getStackTrace();
}
}
}
public static Bitmap modifyOrientation(Bitmap bitmap, String image_absolute_path) throws IOException {
ExifInterface ei = new ExifInterface(image_absolute_path);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotate(bitmap, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotate(bitmap, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotate(bitmap, 270);
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
return flip(bitmap, true, false);
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
return flip(bitmap, false, true);
default:
return bitmap;
}
}
public static Bitmap rotate(Bitmap bitmap, float degrees) {
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
public static Bitmap flip(Bitmap bitmap, boolean horizontal, boolean vertical) {
Matrix matrix = new Matrix();
matrix.preScale(horizontal ? -1 : 1, vertical ? -1 : 1);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
A Uri is not a File.
Step #1: Delete File file = new File(uri.toString());
Step #2: Make sure that you are using the Support Library edition of ExifInterface
Step #3: Call getContentResolver() on your Activity to get a ContentResolver
Step #4: Call openInputStream() on the ContentResolver, passing in the Uri, to get an InputStream on the content pointed to by that Uri
Step #5: Pass that InputStream to the ExifInterface constructor
Step #6: Use that ExifInterface as you are presently, to determine the image orientation
Step #7: Once you get things working, move all of this I/O to a background thread

Grayscaling doesn't affect my image

I am using tessaract to scan text and convert it into a string , so far so good , but i have a problem with grayscaling an image. I have images captured with my camera and I want to grayscale them and to rescale them in order to save some memory , i did this by using the BitmapFactory.Options and the method inSimpleSize(put it in 4).
After that i've tried to get the image from the folder that it is and grayscale it. But didn't work - the text can't be extracted from the photo. However when i removed grayscaling worked.
Here is my code :
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath() , options);
// bitmap = toGrayscale(bitmap);
result = extractText(bitmap);
textView.setText(result);
The extractText method simply calls Tessaract and scan the image and it's working fine without the grayscaling.
My toGrayscale code which i found online ( it is working , i have tried it as a filter and i was happy with it) :
public Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Here is my code for capturing photos with the camera :
if (captureImg != null) {
captureImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCameraActivity();
}
});
private void startCameraActivity() {
try {
String IMGS_PATH = Environment.getExternalStorageDirectory().toString() + "/Noetic/imgs";
prepareDirectory(IMGS_PATH);
String img_path = IMGS_PATH + "/ocr.jpg";
outputFileUri = Uri.fromFile(new File(img_path));
final Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, PHOTO_REQUEST_CODE);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I was looking for a solution but didn't find anything. I have some theories why this doesn't work - one of them is because my grayscaling method creates the same image but new (so BitmapFactory.Options.getSampleSize becomes useless). Any help will be much appriciated.
Thanks in advance!
Try to use Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); instead of Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);

Images selected with gallery are MUCH bigger then when taken with camera

in my app a user either picks an image from their image gallery or captures an image with their camera.
When you capture it is added to the gallery of the user.
I have found that the images, besides being the same image have massive changes in size.
Captured: 33kb
CODE:
if (requestCode == TAKEIMAGE) {
System.out.println("TAKE IMAGE");
int photoLength = 0;
Bitmap photo = (Bitmap) data.getExtras().get("data");
photoLength = GetBitmapLength(photo);
SetSubmissionImage(photo, photoLength);
}
Taken from gallery: 1600kb
CODE:
else if (requestCode == CHOOSEIMAGE) {
System.out.println("CHOOSE IMAGE");
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
try {
FileInputStream fileis=new FileInputStream(selectedImagePath);
BufferedInputStream bufferedstream=new BufferedInputStream(fileis);
byte[] bMapArray= new byte[bufferedstream.available()];
bufferedstream.read(bMapArray);
int photoLength = 0;
Bitmap photo = BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
bMapArray = null;
fileis.close();
bufferedstream.close();
//rotate to be portrait properly
try {
ExifInterface exif = new ExifInterface(selectedImagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
}
else if (orientation == 3) {
matrix.postRotate(180);
}
else if (orientation == 8) {
matrix.postRotate(270);
}
photo = Bitmap.createBitmap(photo, 0, 0, photo.getWidth(), photo.getHeight(), matrix, true); // rotating bitmap
}
catch (Exception e) {
}
//photo = GetCompressedBitmap(photo);
photoLength = GetBitmapLength(photo);
SetSubmissionImage(photo, photoLength);
}
Like other said in comments you need to start the camera activity with an intent that contains an uri where image will be saved:
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
Then in your onActivityResult() method you can retrive the uri and load the image the from the URI in the intent.

Categories