0

I've never been struggling this much with images as I am today and I'd appreciate some help :D
So, thing is, I'm using the built-in camera to capture a picture and then send it to the back end to save it but the orientation is messed up for Kit kat and specially Samsung devices. I tried to use the exif interface everyone suggests, but I just can't get the photo orientation.
A few minutes ago I found an answer somewhat related to this, saying that maybe a good solution is to save the device orientation when the picture is taken, which sounds pretty nice, however, I don't know how to do that with the built in camera, since I don't have full control when opening the camera with an Intent, like this:

mPathToTakenImage = ImageProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider",
            newFile);

    openCamera.putExtra(MediaStore.EXTRA_OUTPUT, mPathToTakenImage);
    openCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

    startActivityForResult(openCamera, AlgebraNationConstants.TAKE_PHOTO_REQUEST_CODE);

So, how can I get the device orientation while the image was being taken in order to rotate the image correctly?
This is the code to rotate the image, however, I'm getting always zero:

        final Bitmap finalImg;
        final StringBuilder base64Image = new StringBuilder("data:image/jpeg;base64,");

        final ExifInterface exifInterface;

        try {
            final String imagePath = params[0].getPath();

            exifInterface = new ExifInterface(imagePath);

            final int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);

            final Bitmap takenPhoto = MediaStore.Images.Media.getBitmap(mRelatedContext.getContentResolver(),
                    params[0]);

            if (null == takenPhoto) {
                base64Image.setLength(0);
            } else {
                finalImg = rotateBitmap(takenPhoto, orientation);

                if (null == finalImg) {
                    base64Image.setLength(0);
                } else {
                    final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    finalImg.compress(Bitmap.CompressFormat.JPEG, 75, byteArrayOutputStream);
                    final byte[] byteArray = byteArrayOutputStream.toByteArray();
                    base64Image.append(Base64.encodeToString(byteArray, Base64.DEFAULT));
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return base64Image.length() == 0 ? null : base64Image.toString();

I'm going crazy with this, any help will be deeply appreciated.

EDIT:
<code>exiftool</code> data from the picture I'm using, which is in landscape mode

pamobo0609
  • 812
  • 10
  • 21
  • `final String imagePath = params[0].getPath();` -- what is this, exactly? It should be `newFile` (or, since it is a `String`, `newFile.getAbsolutePath()`. – CommonsWare Oct 12 '17 at 22:20
  • Thanks for the response. The code is called in an `Asynctask` class where `params[0]` is a `Uri`. – pamobo0609 Oct 12 '17 at 22:22
  • Where did the `Uri` come from? You already know where the image should be (`newFile`), and that is not a `Uri`. Unless that `Uri` is one that you created with `Uri.fromFile()`, `getPath()` is pointless. – CommonsWare Oct 12 '17 at 22:24
  • When the image is coming from the camera, the `Uri` is the one I'm passing as extra in the `Intent`, otherwise is using the `data.getData()` in `onActivityResult` – pamobo0609 Oct 12 '17 at 22:26

2 Answers2

0

A Uri is not a file. Unless the scheme of the Uri is file, getPath() is meaningless. In your case, the scheme is mostly going to be content, not file. As it stands, you are not getting EXIF headers, because ExifInterface cannot find that file.

Use a ContentResolver and openInputStream() to open an InputStream on the content identified by the Uri. Pass that InputStream to the android.support.media.ExifInterface constructor.

Also, bear in mind that you will crash much of the time with an OutOfMemoryError, as you will not have heap space to hold a base64-encoded photo.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I know an `Uri` is not a file. Unfortunately, my app minSdk is 16, and the constructor you're mentioning is for <= api 24. – pamobo0609 Oct 12 '17 at 22:38
  • @pamobo0609: The constructor that I mentioning is from the support library edition of `ExifInterface` -- that is [the one that I linked to in my answer](https://developer.android.com/reference/android/support/media/ExifInterface.html#ExifInterface(java.io.InputStream)). It works back to API Level 14, and it does not suffer from [the security flaws that the `ExifInterface` that you are presently using have on older Android devices](https://commonsware.com/blog/2016/09/08/dealing-exifinterface-security-flaw.html). – CommonsWare Oct 12 '17 at 22:40
  • I changed it and I'm still getting zero, using the `InputStream` as you suggested:`exifInterface = new ExifInterface(new FileInputStream(params[1])); final int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);` – pamobo0609 Oct 12 '17 at 22:48
  • Download the image off the device and check it with other tools (e.g., `exiftool`) to see if it has that header. Ideally, a camera app will set the header, but there's no requirement that it does. – CommonsWare Oct 12 '17 at 22:50
  • @pamobo0609: You will need to sift through that output and see if the orientation header is there. I do not see it in the screenshot, but there is more to the output. – CommonsWare Oct 12 '17 at 23:09
  • That's the full output mate :( – pamobo0609 Oct 12 '17 at 23:11
  • @pamobo0609: I was going by the "press RETURN" part at the bottom, which I assumed meant that there was more output. Regardless, if the orientation header is not there, there is nothing that you can do about it, other than suggest that the user use a better camera app, or take the pictures yourself. – CommonsWare Oct 12 '17 at 23:13
0

So, I finally resolved my problem making use of these two answers:

https://stackoverflow.com/a/17426328

https://stackoverflow.com/a/40865982

In general, the issue was due to the image allocation in disk since I don't know why Android didn't like the fact that I was giving my own path to save the taken image. At the end, the Intent to open the camera is looking like this:
final Intent openCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(openCamera, AlgebraNationConstants.TAKE_PHOTO_REQUEST_CODE);

And Android itself is resolving where to put the image. Nevertheless, @CommonsWare thanks for the enlightenment and answers.

pamobo0609
  • 812
  • 10
  • 21