From e3fe66acfc4e0fde20404ef7807f161d6e168ed3 Mon Sep 17 00:00:00 2001 From: Fada Chen Date: Mon, 21 Mar 2016 19:31:20 -0700 Subject: [PATCH] Backed out D3073724, revert changes in master only Reviewed By: zjj010104 Differential Revision: D3076377 fb-gh-sync-id: da9ca730904c2d520c5c0619b68f3ebee2c74f02 shipit-source-id: da9ca730904c2d520c5c0619b68f3ebee2c74f02 --- .../modules/camera/ImageEditingManager.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java index cbcfbb596e003c..be9ef2f892ea52 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java @@ -24,13 +24,19 @@ import java.util.List; import java.util.Map; +import android.annotation.SuppressLint; import android.content.Context; +import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; +import android.media.ExifInterface; import android.net.Uri; import android.os.AsyncTask; +import android.provider.MediaStore; +import android.text.TextUtils; +import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.GuardedAsyncTask; import com.facebook.react.bridge.ReactApplicationContext; @@ -40,6 +46,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableMap; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.common.ReactConstants; /** * Native module that provides image cropping functionality. @@ -54,6 +61,35 @@ public class ImageEditingManager extends ReactContextBaseJavaModule { /** Compress quality of the output file. */ private static final int COMPRESS_QUALITY = 90; + @SuppressLint("InlinedApi") private static final String[] EXIF_ATTRIBUTES = new String[] { + ExifInterface.TAG_APERTURE, + ExifInterface.TAG_DATETIME, + ExifInterface.TAG_DATETIME_DIGITIZED, + ExifInterface.TAG_EXPOSURE_TIME, + ExifInterface.TAG_FLASH, + ExifInterface.TAG_FOCAL_LENGTH, + ExifInterface.TAG_GPS_ALTITUDE, + ExifInterface.TAG_GPS_ALTITUDE_REF, + ExifInterface.TAG_GPS_DATESTAMP, + ExifInterface.TAG_GPS_LATITUDE, + ExifInterface.TAG_GPS_LATITUDE_REF, + ExifInterface.TAG_GPS_LONGITUDE, + ExifInterface.TAG_GPS_LONGITUDE_REF, + ExifInterface.TAG_GPS_PROCESSING_METHOD, + ExifInterface.TAG_GPS_TIMESTAMP, + ExifInterface.TAG_IMAGE_LENGTH, + ExifInterface.TAG_IMAGE_WIDTH, + ExifInterface.TAG_ISO, + ExifInterface.TAG_MAKE, + ExifInterface.TAG_MODEL, + ExifInterface.TAG_ORIENTATION, + ExifInterface.TAG_SUBSEC_TIME, + ExifInterface.TAG_SUBSEC_TIME_DIG, + ExifInterface.TAG_SUBSEC_TIME_ORIG, + ExifInterface.TAG_WHITE_BALANCE + }; + + public ImageEditingManager(ReactApplicationContext reactContext) { super(reactContext); new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -241,6 +277,10 @@ protected void doInBackgroundGuarded(Void... params) { File tempFile = createTempFile(mContext, mimeType); writeCompressedBitmapToFile(cropped, mimeType, tempFile); + if (mimeType.equals("image/jpeg")) { + copyExif(mContext, Uri.parse(mUri), tempFile); + } + mSuccess.invoke(Uri.fromFile(tempFile).toString()); } catch (Exception e) { @@ -352,6 +392,47 @@ private Bitmap cropAndResize( // Utils + private static void copyExif(Context context, Uri oldImage, File newFile) throws IOException { + File oldFile = getFileFromUri(context, oldImage); + if (oldFile == null) { + FLog.w(ReactConstants.TAG, "Couldn't get real path for uri: " + oldImage); + return; + } + + ExifInterface oldExif = new ExifInterface(oldFile.getAbsolutePath()); + ExifInterface newExif = new ExifInterface(newFile.getAbsolutePath()); + for (String attribute : EXIF_ATTRIBUTES) { + String value = oldExif.getAttribute(attribute); + if (value != null) { + newExif.setAttribute(attribute, value); + } + } + newExif.saveAttributes(); + } + + private static @Nullable File getFileFromUri(Context context, Uri uri) { + if (uri.getScheme().equals("file")) { + return new File(uri.getPath()); + } else if (uri.getScheme().equals("content")) { + Cursor cursor = context.getContentResolver() + .query(uri, new String[] { MediaStore.MediaColumns.DATA }, null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + String path = cursor.getString(0); + if (!TextUtils.isEmpty(path)) { + return new File(path); + } + } + } finally { + cursor.close(); + } + } + } + + return null; + } + private static boolean isLocalUri(String uri) { for (String localPrefix : LOCAL_URI_PREFIXES) { if (uri.startsWith(localPrefix)) {