Skip to content

Commit

Permalink
Merge pull request #1 from mcelotti/CB-13683
Browse files Browse the repository at this point in the history
Fix Android Photo Rotation

apache#100
  • Loading branch information
rogervanwile authored Jan 20, 2020
2 parents e1fb581 + 56979a6 commit ab6cdf3
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 10 deletions.
2 changes: 2 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ xmlns:android="http://schemas.android.com/apk/res/android"
<js-module src="www/android/init.js" name="init">
<runs />
</js-module>

<framework src="com.android.support:exifinterface:27.+" />
</platform>

<!-- ios -->
Expand Down
85 changes: 75 additions & 10 deletions src/android/Capture.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ Licensed to the Apache Software Foundation (ASF) under one
*/
package org.apache.cordova.mediacapture;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;

Expand All @@ -53,10 +55,13 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.media.ExifInterface;

public class Capture extends CordovaPlugin {

Expand Down Expand Up @@ -185,7 +190,7 @@ else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
/**
* Get the Image specific attributes
*
* @param filePath path to the file
* @param fileUrl path to the file
* @param obj represents the Media File Data
* @return a JSONObject that represents the Media File Data
* @throws JSONException
Expand Down Expand Up @@ -260,7 +265,7 @@ private void captureImage(Request req) {
!PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

boolean needCameraPermission = cameraPermissionInManifest &&
!PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);
!PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);

if (needExternalStoragePermission || needCameraPermission) {
if (needExternalStoragePermission && needCameraPermission) {
Expand Down Expand Up @@ -293,6 +298,12 @@ private static void createWritableFile(File file) throws IOException {
file.setWritable(true, false);
}

private 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);
}

/**
* Sets up an intent to capture video. Result handled by onActivityResult()
*/
Expand Down Expand Up @@ -384,8 +395,16 @@ public void onAudioActivityResult(Request req, Intent intent) {
}

public void onImageActivityResult(Request req) {
Uri uri = imageUri;

// Check image rotation
Bitmap rotatedBitmap = rotateAccordingToExifOrientation(uri);
if (rotatedBitmap != null) {
uri = fromBitmapToUri(this.cordova.getContext(), rotatedBitmap);
}

// Add image to results
req.results.put(createMediaFile(imageUri));
req.results.put(createMediaFile(uri));

checkForDuplicateImage();

Expand Down Expand Up @@ -506,11 +525,11 @@ private JSONObject createErrorObject(int code, String message) {
*/
private Cursor queryImgDB(Uri contentStore) {
return this.cordova.getActivity().getContentResolver().query(
contentStore,
new String[] { MediaStore.Images.Media._ID },
null,
null,
null);
contentStore,
new String[] { MediaStore.Images.Media._ID },
null,
null,
null);
}

/**
Expand Down Expand Up @@ -543,6 +562,52 @@ private Uri whichContentStore() {
}
}

@Nullable
private Bitmap rotateAccordingToExifOrientation(Uri uri) {
Context context = this.cordova.getContext();
int orientation;
Bitmap bitmap;
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
if (inputStream == null)
throw new IOException("input stream from ContentResolver is null");
ExifInterface ei = new ExifInterface(inputStream);
orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
} catch (IOException e) {
LOG.e(LOG_TAG, "Failed reading bitmap", e);
return null;
}

Bitmap rotatedBitmap;
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:
// use original bitmap
rotatedBitmap = null;
}
return rotatedBitmap;
}

private Uri fromBitmapToUri(Context context, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "title", null);
return Uri.parse(path);
}

private void executeRequest(Request req) {
switch (req.action) {
case CAPTURE_AUDIO:
Expand Down

0 comments on commit ab6cdf3

Please sign in to comment.