diff --git a/plugin.xml b/plugin.xml index 7b4bb87b..e035ad70 100644 --- a/plugin.xml +++ b/plugin.xml @@ -91,6 +91,8 @@ xmlns:rim="http://www.blackberry.com/ns/widgets" + + diff --git a/src/android/Capture.java b/src/android/Capture.java index 33c3413b..c12e5b32 100644 --- a/src/android/Capture.java +++ b/src/android/Capture.java @@ -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; @@ -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 { @@ -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 @@ -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) { @@ -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() */ @@ -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(); @@ -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); } /** @@ -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: