1

I am using GalleryIntent to pick an image from the gallery and after that, I am encoding that image to Base64, but in this process after encoding an image to Base64, I saw that image is rotated to 90 degree.

Here is my code:-

public class ImagePickerModule extends ReactContextBaseJavaModule {

    private static final int IMAGE_PICKER_REQUEST = 121;
    private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
    private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
    private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
    private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";

    private Promise mPickerPromise;

    private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {

        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
            if (requestCode == IMAGE_PICKER_REQUEST) {
                if (mPickerPromise != null) {
                    if (resultCode == Activity.RESULT_CANCELED) {
                        mPickerPromise.reject(E_PICKER_CANCELLED, "Cancelled");
                    } else if (resultCode == Activity.RESULT_OK) {
                        Uri uri = intent.getData();
                        if (uri == null) {
                            mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Cancelled");
                        } else {
                            mPickerPromise.resolve(uri.toString());
                        }
                    }

                    mPickerPromise = null;
                }
            }
        }
    };

    @ReactMethod
    public String encodeImage(String url, final Promise promise) {
        Uri uri = Uri.parse(url);
        byte[] b;
        InputStream imageStream;
        try {
            imageStream = getReactApplicationContext().getContentResolver().openInputStream(uri);
            final Bitmap image = BitmapFactory.decodeStream(imageStream);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG, 40, baos);
            b = baos.toByteArray();
            try {
                promise.resolve(Base64.encodeToString(b, Base64.DEFAULT));
                image.recycle();
            } catch (OutOfMemoryError e) {
                Log.e("OutOfMemoryError", "encodeImage: e");
            } catch (RuntimeException err) {
                Log.e("RuntimeException", "encodeImage: e");
            }
        } catch (Exception e) {
            promise.reject("File Not Found Exception", "File not Found");
            e.printStackTrace();
        }
        return url;
    }

    ImagePickerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        reactContext.addActivityEventListener(mActivityEventListener);
    }

    @NonNull
    @Override
    public String getName() {
        return "ImagePicker";
    }

    @ReactMethod
    public void pickImage(final Promise promise) {

        Activity currentActivity = getCurrentActivity();

        if (currentActivity == null) {
            promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
            return;
        }

        if (ContextCompat.checkSelfPermission(currentActivity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(currentActivity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
        }

        // Store the promise to resolve/reject when picker returns data
        mPickerPromise = promise;

        try {
            final Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            currentActivity.startActivityForResult(galleryIntent, IMAGE_PICKER_REQUEST);
        } catch (Exception e) {
            mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
            mPickerPromise = null;
        }
    }
}

I am using this as a native module in my react native project. I tried this way Android getting an image from gallery comes rotated

but it doesn't help me.

If anyone knows the solution then help me. Thanks in Advance :)

Taslim Oseni
  • 6,086
  • 10
  • 44
  • 69
Akash Mishra
  • 623
  • 1
  • 6
  • 22
  • You reduce the quality of the picture to 40. Is this intentionally? If you wanna keep the full quality of the picture then your approch is completely wrong and you should not use an intermediate bitmap at all. – blackapps Dec 11 '19 at 09:49
  • yes, it's intentionally. – Akash Mishra Dec 11 '19 at 10:19

1 Answers1

3

I had the same problem and solved it like this:

Step 1: Add the gradle dependency for Exif Features:

implementation 'androidx.exifinterface:exifinterface:1.0.0'

Step 2: Read the Exif information of that file, containing additional infos about a file, e.g. it's rotation or geo position. With this, you're able to get it's initial rotation and rotate it to show the image correctly:

try
{
     InputStream inputStream = activity.getContentResolver().openInputStream(intent.getData()); // intent is parameter from onActivityResult()
     ExifInterface exif = new ExifInterface(inputStream);
     int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
     inputStream.close();

    if (orientation == 6)
    {
        // Rotation 90°
    }
    else if (orientation == 3)
    {
        // Rotation 180°
    }
    else if (orientation == 8)
    {
        // Rotation 270°
    }
} catch (IOException e)
{
    e.printStackTrace();
}

Step 3: Rotate the image to show it correctly:

Matrix matrix = new Matrix();
matrix.postRotate(degrees); // Degrees calculated in Step 2

Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Roman
  • 470
  • 2
  • 5
  • 17
  • Roman, where I need to place this code? In my encodeimage function? – Akash Mishra Dec 11 '19 at 08:14
  • I edited the answer, was posting the solution for the Camera intent. You need to read the orientation from the intent.getData() URI by implementing Step 2. You can add this code to your encodeImage() function, but then you need to pass the URI directly instead of it's String representation. Or you get the orientation in onActivityResult() and pass it to encodeImage() to rotate it there – Roman Dec 11 '19 at 08:50
  • before posting the steps, a good approach is to write an explanation – Daniel Dec 11 '19 at 08:56
  • @Daniel: What kind of explanation? – Roman Dec 11 '19 at 08:59
  • an explanation to what is exif information, how it is stored(at least a link would be helpful) and possible steps to fix this (there are at least 2 possible ways to solve this problem) – Daniel Dec 11 '19 at 09:03
  • Added a bit more information. This is the only way I know so far to solve this problem. If there are better ones, would be nice to have them here too – Roman Dec 11 '19 at 09:28