Merge pull request #1146 from jgfidelis/implement-local-cache

Create local cache directory and save image there when photo is taken.
This commit is contained in:
João Guilherme Fidelis 2018-01-23 11:23:48 -02:00 committed by GitHub
commit 683b3ee0c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 132 additions and 17 deletions

View File

@ -65,6 +65,8 @@ public class MutableImage {
return currentRepresentation.getHeight();
}
public Bitmap getBitmap() { return currentRepresentation; }
public void fixOrientation() throws ImageMutationFailedException {
try {
Metadata metadata = originalImageMetaData();

View File

@ -2,6 +2,7 @@ package org.reactnative.camera;
import android.content.Context;
import org.reactnative.camera.utils.ScopedContext;
import org.reactnative.facedetector.RNFaceDetector;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
@ -25,7 +26,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext mReactContext;
// private static ScopedContext mScopedContext;
private static ScopedContext mScopedContext;
static final int VIDEO_2160P = 0;
static final int VIDEO_1080P = 1;
static final int VIDEO_720P = 2;
@ -58,14 +59,15 @@ public class CameraModule extends ReactContextBaseJavaModule {
public CameraModule(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
mScopedContext = new ScopedContext(mReactContext);
}
public static ReactApplicationContext getReactContextSingleton() {
return mReactContext;
}
public static Context getScopedContextSingleton() {
return mReactContext;
public static ScopedContext getScopedContext() {
return mScopedContext;
}
@Override

View File

@ -6,6 +6,8 @@ import android.os.Build;
import android.support.annotation.Nullable;
import org.reactnative.camera.tasks.ResolveTakenPictureAsyncTask;
import org.reactnative.camera.utils.ScopedContext;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;

View File

@ -16,6 +16,8 @@ import org.reactnative.camera.tasks.FaceDetectorAsyncTask;
import org.reactnative.camera.tasks.FaceDetectorAsyncTaskDelegate;
import org.reactnative.camera.tasks.ResolveTakenPictureAsyncTask;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.camera.utils.RNFileUtils;
import org.reactnative.camera.utils.ScopedContext;
import org.reactnative.facedetector.RNFaceDetector;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
@ -81,7 +83,8 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
public void onPictureTaken(CameraView cameraView, final byte[] data) {
Promise promise = mPictureTakenPromises.poll();
ReadableMap options = mPictureTakenOptions.remove(promise);
new ResolveTakenPictureAsyncTask(data, promise, options).execute();
File cacheDirectory = CameraModule.getScopedContext().getCacheDirectory();
new ResolveTakenPictureAsyncTask(data, promise, options, cacheDirectory).execute();
}
@Override
@ -89,8 +92,7 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
if (mVideoRecordedPromise != null) {
if (path != null) {
WritableMap result = Arguments.createMap();
// TODO - fix this
//result.putString("uri", ExpFileUtils.uriFromFile(new File(path)).toString());
result.putString("uri", RNFileUtils.uriFromFile(new File(path)).toString());
mVideoRecordedPromise.resolve(result);
} else {
mVideoRecordedPromise.reject("E_RECORDING", "Couldn't stop recording - there is none in progress");
@ -156,10 +158,9 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
public void record(ReadableMap options, final Promise promise) {
// try {
// TODO - fix this
String path = "";
//String path = ExpFileUtils.generateOutputPath(CameraModule.getScopedContextSingleton().getCacheDir(), "Camera", ".mp4");
try {
File cacheDirectory = CameraModule.getScopedContext().getCacheDirectory();
String path = RNFileUtils.getOutputFilePath(cacheDirectory, ".mp4");
int maxDuration = options.hasKey("maxDuration") ? options.getInt("maxDuration") : -1;
int maxFileSize = options.hasKey("maxFileSize") ? options.getInt("maxFileSize") : -1;
@ -175,9 +176,9 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
} else {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.");
}
// } catch (IOException e) {
// promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
// }
} catch (IOException e) {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
}
}
/**

View File

@ -1,12 +1,14 @@
package org.reactnative.camera.tasks;
import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.media.ExifInterface;
import org.reactnative.MutableImage;
import org.reactnative.camera.RNCameraViewHelper;
import org.reactnative.camera.utils.RNFileUtils;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
@ -14,6 +16,9 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, WritableMap> {
@ -21,6 +26,7 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
private Promise mPromise;
private byte[] mImageData;
private ReadableMap mOptions;
private File mCacheDirectory;
public ResolveTakenPictureAsyncTask(byte[] imageData, Promise promise, ReadableMap options) {
mPromise = promise;
@ -28,6 +34,13 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
mImageData = imageData;
}
public ResolveTakenPictureAsyncTask(byte[] imageData, Promise promise, ReadableMap options, File cacheDirectory) {
mPromise = promise;
mOptions = options;
mImageData = imageData;
mCacheDirectory = cacheDirectory;
}
private int getQuality() {
return (int) (mOptions.getDouble("quality") * 100);
}
@ -52,9 +65,14 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
response.putMap("exif", exifData);
}
//TODO: create local cache directory, save image to file and insert into response "uri" key
// with the path to the file
//response.putString("uri", outputPath);
ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
mutableImage.getBitmap().compress(Bitmap.CompressFormat.JPEG, getQuality(), imageStream);
// Write compressed image to file in cache directory
String filePath = writeStreamToFile(imageStream);
File imageFile = new File(filePath);
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
return response;
} catch (Resources.NotFoundException e) {
@ -78,6 +96,35 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
return null;
}
private String writeStreamToFile(ByteArrayOutputStream inputStream) throws IOException {
String outputPath = null;
IOException exception = null;
FileOutputStream outputStream = null;
try {
outputPath = RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg");
outputStream = new FileOutputStream(outputPath);
inputStream.writeTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
exception = e;
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (exception != null) {
throw exception;
}
return outputPath;
}
@Override
protected void onPostExecute(WritableMap response) {
super.onPostExecute(response);

View File

@ -0,0 +1,34 @@
package org.reactnative.camera.utils;
import android.content.Context;
import android.net.Uri;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* Created by jgfidelis on 23/01/18.
*/
public class RNFileUtils {
public static File ensureDirExists(File dir) throws IOException {
if (!(dir.isDirectory() || dir.mkdirs())) {
throw new IOException("Couldn't create directory '" + dir + "'");
}
return dir;
}
public static String getOutputFilePath(File directory, String extension) throws IOException {
ensureDirExists(directory);
String filename = UUID.randomUUID().toString();
return directory + File.separator + filename + extension;
}
public static Uri uriFromFile(File file) {
return Uri.fromFile(file);
}
}

View File

@ -0,0 +1,27 @@
package org.reactnative.camera.utils;
import android.content.Context;
import java.io.File;
/**
* Created by jgfidelis on 23/01/18.
*/
public class ScopedContext {
private File cacheDirectory = null;
public ScopedContext(Context context) {
createCacheDirectory(context);
}
public void createCacheDirectory(Context context) {
cacheDirectory = new File(context.getCacheDir() + "/Camera/");
}
public File getCacheDirectory() {
return cacheDirectory;
}
}