Mirror image for Android (#399)

* Add mirrorImage support for Android

* Release resources after mirroring

* Mirror image only for TYPE_FRONT

* Remove unnecessary annotation

* Document mirrorImage for Android

* Improved compression and error handling

* Add support for mirroring on Android back camera too
This commit is contained in:
Gonzalo Aguirre 2016-09-13 13:48:48 -03:00 committed by Zack Story
parent 2bbdf8ce91
commit b01c64e773
5 changed files with 83 additions and 7 deletions

View File

@ -189,6 +189,7 @@ export default class Example extends React.Component {
type={this.state.camera.type}
flashMode={this.state.camera.flashMode}
defaultTouchToFocus
mirrorImage={false}
/>
<View style={[styles.overlay, styles.topOverlay]}>
<TouchableOpacity

View File

@ -2,4 +2,4 @@ rootProject.name = 'Example'
include ':app'
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../../android')

View File

@ -243,9 +243,9 @@ By default, `onZoomChanged` is not defined and pinch-to-zoom is disabled.
If set to `true`, the device will not sleep while the camera preview is visible. This mimics the behavior of the default camera app, which keeps the device awake while open.
#### `iOS` `mirrorImage`
#### `mirrorImage`
If set to `true`, the image returned will be mirrored..
If set to `true`, the image returned will be mirrored.
## Component instance methods

View File

@ -5,28 +5,48 @@
package com.lwansbrough.RCTCamera;
import android.annotation.TargetApi;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaActionSound;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.Surface;
import com.facebook.react.bridge.*;
import javax.annotation.Nullable;
import java.io.*;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
public class RCTCameraModule extends ReactContextBaseJavaModule
implements MediaRecorder.OnInfoListener, LifecycleEventListener {
@ -393,6 +413,50 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
return byteArray;
}
private byte[] mirrorImage(byte[] data) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
Bitmap photo = BitmapFactory.decodeStream(inputStream);
Matrix m = new Matrix();
m.preScale(-1, 1);
Bitmap mirroredImage = Bitmap.createBitmap(photo, 0, 0, photo.getWidth(), photo.getHeight(), m, false);
byte[] result = null;
try {
result = compress(mirroredImage, 85);
} catch (OutOfMemoryError e) {
try {
result = compress(mirroredImage, 70);
} catch (OutOfMemoryError e2) {
e.printStackTrace();
}
}
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private byte[] compress(Bitmap bitmap, int quality) throws OutOfMemoryError {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
try {
return outputStream.toByteArray();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@ReactMethod
public void capture(final ReadableMap options, final Promise promise) {
int orientation = options.hasKey("orientation") ? options.getInt("orientation") : RCTCamera.getInstance().getOrientation();
@ -435,10 +499,20 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
RCTCamera.getInstance().setCaptureQuality(options.getInt("type"), options.getString("quality"));
}
final Boolean shouldMirror = options.hasKey("mirrorImage") && options.getBoolean("mirrorImage");
RCTCamera.getInstance().adjustCameraRotationToDeviceOrientation(options.getInt("type"), deviceOrientation);
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (shouldMirror) {
data = mirrorImage(data);
if (data == null) {
promise.reject("Error mirroring image");
}
}
camera.stopPreview();
camera.startPreview();
WritableMap response = new WritableNativeMap();

View File

@ -184,6 +184,7 @@ export default class Camera extends Component {
type: props.type,
title: '',
description: '',
mirrorImage: props.mirrorImage,
...options
};