Skip to content

Commit a1db2c9

Browse files
author
Marco Celotti
committed
CB-13683: (android) cordova-plugin-media-capture rotates pictures with some devices
1 parent f3fa6e8 commit a1db2c9

File tree

2 files changed

+91
-27
lines changed

2 files changed

+91
-27
lines changed

plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ xmlns:rim="http://www.blackberry.com/ns/widgets"
9191
<js-module src="www/android/init.js" name="init">
9292
<runs />
9393
</js-module>
94+
95+
<framework src="com.android.support:exifinterface:27.+" />
9496
</platform>
9597

9698
<!-- ios -->

src/android/Capture.java

Lines changed: 89 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,47 @@ Licensed to the Apache Software Foundation (ASF) under one
1818
*/
1919
package org.apache.cordova.mediacapture;
2020

21-
import java.io.File;
22-
import java.io.FileInputStream;
23-
import java.io.IOException;
24-
import java.io.OutputStream;
25-
import java.lang.reflect.InvocationTargetException;
26-
import java.lang.reflect.Field;
27-
import java.lang.reflect.Method;
28-
import java.util.Arrays;
29-
30-
import android.os.Build;
31-
import android.os.Bundle;
32-
33-
import org.apache.cordova.file.FileUtils;
34-
import org.apache.cordova.file.LocalFilesystemURL;
35-
36-
import org.apache.cordova.CallbackContext;
37-
import org.apache.cordova.CordovaPlugin;
38-
import org.apache.cordova.LOG;
39-
import org.apache.cordova.PermissionHelper;
40-
import org.apache.cordova.PluginManager;
41-
import org.apache.cordova.mediacapture.PendingRequests.Request;
42-
import org.json.JSONArray;
43-
import org.json.JSONException;
44-
import org.json.JSONObject;
45-
4621
import android.Manifest;
4722
import android.app.Activity;
4823
import android.content.ContentResolver;
4924
import android.content.ContentValues;
25+
import android.content.Context;
5026
import android.content.Intent;
5127
import android.content.pm.PackageManager;
5228
import android.content.pm.PackageManager.NameNotFoundException;
5329
import android.database.Cursor;
30+
import android.graphics.Bitmap;
5431
import android.graphics.BitmapFactory;
32+
import android.graphics.Matrix;
5533
import android.media.MediaPlayer;
5634
import android.net.Uri;
35+
import android.os.Build;
36+
import android.os.Bundle;
5737
import android.os.Environment;
5838
import android.provider.MediaStore;
39+
import android.support.annotation.Nullable;
40+
import android.support.media.ExifInterface;
41+
42+
import org.apache.cordova.CallbackContext;
43+
import org.apache.cordova.CordovaPlugin;
44+
import org.apache.cordova.LOG;
45+
import org.apache.cordova.PermissionHelper;
46+
import org.apache.cordova.PluginManager;
47+
import org.apache.cordova.file.FileUtils;
48+
import org.apache.cordova.file.LocalFilesystemURL;
49+
import org.apache.cordova.mediacapture.PendingRequests.Request;
50+
import org.json.JSONArray;
51+
import org.json.JSONException;
52+
import org.json.JSONObject;
53+
54+
import java.io.ByteArrayOutputStream;
55+
import java.io.File;
56+
import java.io.IOException;
57+
import java.io.InputStream;
58+
import java.lang.reflect.Field;
59+
import java.lang.reflect.InvocationTargetException;
60+
import java.lang.reflect.Method;
61+
import java.util.Arrays;
5962

6063
public class Capture extends CordovaPlugin {
6164

@@ -183,7 +186,7 @@ else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
183186
/**
184187
* Get the Image specific attributes
185188
*
186-
* @param filePath path to the file
189+
* @param fileUrl path to the file
187190
* @param obj represents the Media File Data
188191
* @return a JSONObject that represents the Media File Data
189192
* @throws JSONException
@@ -287,6 +290,12 @@ private static void createWritableFile(File file) throws IOException {
287290
file.setWritable(true, false);
288291
}
289292

293+
private static Bitmap rotateImage(Bitmap source, float angle) {
294+
Matrix matrix = new Matrix();
295+
matrix.postRotate(angle);
296+
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
297+
}
298+
290299
/**
291300
* Sets up an intent to capture video. Result handled by onActivityResult()
292301
*/
@@ -378,8 +387,16 @@ public void onAudioActivityResult(Request req, Intent intent) {
378387
}
379388

380389
public void onImageActivityResult(Request req) {
390+
Uri uri = imageUri;
391+
392+
// Check image rotation
393+
Bitmap rotatedBitmap = rotateAccordingToExifOrientation(uri);
394+
if (rotatedBitmap != null) {
395+
uri = fromBitmapToUri(this.cordova.getContext(), rotatedBitmap);
396+
}
397+
381398
// Add image to results
382-
req.results.put(createMediaFile(imageUri));
399+
req.results.put(createMediaFile(uri));
383400

384401
checkForDuplicateImage();
385402

@@ -537,6 +554,51 @@ private Uri whichContentStore() {
537554
}
538555
}
539556

557+
@Nullable
558+
private Bitmap rotateAccordingToExifOrientation(Uri uri) {
559+
Context context = this.cordova.getContext();
560+
int orientation;
561+
Bitmap bitmap;
562+
try {
563+
InputStream inputStream = context.getContentResolver().openInputStream(uri);
564+
if (inputStream == null)
565+
throw new IOException("input stream from ContentResolver is null");
566+
ExifInterface ei = new ExifInterface(inputStream);
567+
orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
568+
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
569+
} catch (IOException e) {
570+
LOG.e(LOG_TAG, "Failed reading bitmap", e);
571+
return null;
572+
}
573+
574+
Bitmap rotatedBitmap;
575+
switch (orientation) {
576+
case ExifInterface.ORIENTATION_ROTATE_90:
577+
rotatedBitmap = rotateImage(bitmap, 90);
578+
break;
579+
580+
case ExifInterface.ORIENTATION_ROTATE_180:
581+
rotatedBitmap = rotateImage(bitmap, 180);
582+
break;
583+
584+
case ExifInterface.ORIENTATION_ROTATE_270:
585+
rotatedBitmap = rotateImage(bitmap, 270);
586+
break;
587+
588+
case ExifInterface.ORIENTATION_NORMAL:
589+
default:
590+
rotatedBitmap = bitmap;
591+
}
592+
return rotatedBitmap;
593+
}
594+
595+
private Uri fromBitmapToUri(Context context, Bitmap inImage) {
596+
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
597+
inImage.compress(Bitmap.CompressFormat.JPEG, 85, bytes);
598+
String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "title", null);
599+
return Uri.parse(path);
600+
}
601+
540602
private void executeRequest(Request req) {
541603
switch (req.action) {
542604
case CAPTURE_AUDIO:

0 commit comments

Comments
 (0)