* add TouchEvent on android * add GestureHandler to detect touches on android * add property to enable touchDetector on android * add onTouch event to ios * add GestureRecognizer to ios * add onTouch property and js setup * add missing semicolons * fix literal notation * add missing ":" * fix copy-paste error (wrong var-name) * pass the native event to the onTouch callback * replace : with ; * add onTouch type defs * add documentation for onTouch property * scale postion before emitting since the event coordinates are raw pixels * migrate advanced example to native pinch zoom and onTouch * split onTouch property into onTap and onDoubleTap
476 lines
20 KiB
Java
476 lines
20 KiB
Java
package org.reactnative.camera;
|
|
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.media.CamcorderProfile;
|
|
import android.os.Build;
|
|
import androidx.exifinterface.media.ExifInterface;
|
|
import android.view.ViewGroup;
|
|
import com.facebook.react.bridge.Arguments;
|
|
import com.facebook.react.bridge.ReactContext;
|
|
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
import com.facebook.react.bridge.ReadableMap;
|
|
import com.facebook.react.bridge.WritableMap;
|
|
import com.facebook.react.bridge.WritableArray;
|
|
import com.facebook.react.uimanager.UIManagerModule;
|
|
import com.google.android.cameraview.CameraView;
|
|
import com.google.zxing.Result;
|
|
import org.reactnative.camera.events.*;
|
|
import org.reactnative.barcodedetector.RNBarcodeDetector;
|
|
import org.reactnative.facedetector.RNFaceDetector;
|
|
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Calendar;
|
|
|
|
public class RNCameraViewHelper {
|
|
|
|
public static final String[][] exifTags = new String[][]{
|
|
{"string", ExifInterface.TAG_ARTIST},
|
|
{"int", ExifInterface.TAG_BITS_PER_SAMPLE},
|
|
{"int", ExifInterface.TAG_COMPRESSION},
|
|
{"string", ExifInterface.TAG_COPYRIGHT},
|
|
{"string", ExifInterface.TAG_DATETIME},
|
|
{"string", ExifInterface.TAG_IMAGE_DESCRIPTION},
|
|
{"int", ExifInterface.TAG_IMAGE_LENGTH},
|
|
{"int", ExifInterface.TAG_IMAGE_WIDTH},
|
|
{"int", ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT},
|
|
{"int", ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH},
|
|
{"string", ExifInterface.TAG_MAKE},
|
|
{"string", ExifInterface.TAG_MODEL},
|
|
{"int", ExifInterface.TAG_ORIENTATION},
|
|
{"int", ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION},
|
|
{"int", ExifInterface.TAG_PLANAR_CONFIGURATION},
|
|
{"double", ExifInterface.TAG_PRIMARY_CHROMATICITIES},
|
|
{"double", ExifInterface.TAG_REFERENCE_BLACK_WHITE},
|
|
{"int", ExifInterface.TAG_RESOLUTION_UNIT},
|
|
{"int", ExifInterface.TAG_ROWS_PER_STRIP},
|
|
{"int", ExifInterface.TAG_SAMPLES_PER_PIXEL},
|
|
{"string", ExifInterface.TAG_SOFTWARE},
|
|
{"int", ExifInterface.TAG_STRIP_BYTE_COUNTS},
|
|
{"int", ExifInterface.TAG_STRIP_OFFSETS},
|
|
{"int", ExifInterface.TAG_TRANSFER_FUNCTION},
|
|
{"double", ExifInterface.TAG_WHITE_POINT},
|
|
{"double", ExifInterface.TAG_X_RESOLUTION},
|
|
{"double", ExifInterface.TAG_Y_CB_CR_COEFFICIENTS},
|
|
{"int", ExifInterface.TAG_Y_CB_CR_POSITIONING},
|
|
{"int", ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING},
|
|
{"double", ExifInterface.TAG_Y_RESOLUTION},
|
|
{"double", ExifInterface.TAG_APERTURE_VALUE},
|
|
{"double", ExifInterface.TAG_BRIGHTNESS_VALUE},
|
|
{"string", ExifInterface.TAG_CFA_PATTERN},
|
|
{"int", ExifInterface.TAG_COLOR_SPACE},
|
|
{"string", ExifInterface.TAG_COMPONENTS_CONFIGURATION},
|
|
{"double", ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL},
|
|
{"int", ExifInterface.TAG_CONTRAST},
|
|
{"int", ExifInterface.TAG_CUSTOM_RENDERED},
|
|
{"string", ExifInterface.TAG_DATETIME_DIGITIZED},
|
|
{"string", ExifInterface.TAG_DATETIME_ORIGINAL},
|
|
{"string", ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION},
|
|
{"double", ExifInterface.TAG_DIGITAL_ZOOM_RATIO},
|
|
{"string", ExifInterface.TAG_EXIF_VERSION},
|
|
{"double", ExifInterface.TAG_EXPOSURE_BIAS_VALUE},
|
|
{"double", ExifInterface.TAG_EXPOSURE_INDEX},
|
|
{"int", ExifInterface.TAG_EXPOSURE_MODE},
|
|
{"int", ExifInterface.TAG_EXPOSURE_PROGRAM},
|
|
{"double", ExifInterface.TAG_EXPOSURE_TIME},
|
|
{"double", ExifInterface.TAG_F_NUMBER},
|
|
{"string", ExifInterface.TAG_FILE_SOURCE},
|
|
{"int", ExifInterface.TAG_FLASH},
|
|
{"double", ExifInterface.TAG_FLASH_ENERGY},
|
|
{"string", ExifInterface.TAG_FLASHPIX_VERSION},
|
|
{"double", ExifInterface.TAG_FOCAL_LENGTH},
|
|
{"int", ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM},
|
|
{"int", ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT},
|
|
{"double", ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION},
|
|
{"double", ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION},
|
|
{"int", ExifInterface.TAG_GAIN_CONTROL},
|
|
{"int", ExifInterface.TAG_ISO_SPEED_RATINGS},
|
|
{"string", ExifInterface.TAG_IMAGE_UNIQUE_ID},
|
|
{"int", ExifInterface.TAG_LIGHT_SOURCE},
|
|
{"string", ExifInterface.TAG_MAKER_NOTE},
|
|
{"double", ExifInterface.TAG_MAX_APERTURE_VALUE},
|
|
{"int", ExifInterface.TAG_METERING_MODE},
|
|
{"int", ExifInterface.TAG_NEW_SUBFILE_TYPE},
|
|
{"string", ExifInterface.TAG_OECF},
|
|
{"int", ExifInterface.TAG_PIXEL_X_DIMENSION},
|
|
{"int", ExifInterface.TAG_PIXEL_Y_DIMENSION},
|
|
{"string", ExifInterface.TAG_RELATED_SOUND_FILE},
|
|
{"int", ExifInterface.TAG_SATURATION},
|
|
{"int", ExifInterface.TAG_SCENE_CAPTURE_TYPE},
|
|
{"string", ExifInterface.TAG_SCENE_TYPE},
|
|
{"int", ExifInterface.TAG_SENSING_METHOD},
|
|
{"int", ExifInterface.TAG_SHARPNESS},
|
|
{"double", ExifInterface.TAG_SHUTTER_SPEED_VALUE},
|
|
{"string", ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE},
|
|
{"string", ExifInterface.TAG_SPECTRAL_SENSITIVITY},
|
|
{"int", ExifInterface.TAG_SUBFILE_TYPE},
|
|
{"string", ExifInterface.TAG_SUBSEC_TIME},
|
|
{"string", ExifInterface.TAG_SUBSEC_TIME_DIGITIZED},
|
|
{"string", ExifInterface.TAG_SUBSEC_TIME_ORIGINAL},
|
|
{"int", ExifInterface.TAG_SUBJECT_AREA},
|
|
{"double", ExifInterface.TAG_SUBJECT_DISTANCE},
|
|
{"int", ExifInterface.TAG_SUBJECT_DISTANCE_RANGE},
|
|
{"int", ExifInterface.TAG_SUBJECT_LOCATION},
|
|
{"string", ExifInterface.TAG_USER_COMMENT},
|
|
{"int", ExifInterface.TAG_WHITE_BALANCE},
|
|
{"int", ExifInterface.TAG_GPS_ALTITUDE_REF},
|
|
{"string", ExifInterface.TAG_GPS_AREA_INFORMATION},
|
|
{"double", ExifInterface.TAG_GPS_DOP},
|
|
{"string", ExifInterface.TAG_GPS_DATESTAMP},
|
|
{"double", ExifInterface.TAG_GPS_DEST_BEARING},
|
|
{"string", ExifInterface.TAG_GPS_DEST_BEARING_REF},
|
|
{"double", ExifInterface.TAG_GPS_DEST_DISTANCE},
|
|
{"string", ExifInterface.TAG_GPS_DEST_DISTANCE_REF},
|
|
{"double", ExifInterface.TAG_GPS_DEST_LATITUDE},
|
|
{"string", ExifInterface.TAG_GPS_DEST_LATITUDE_REF},
|
|
{"double", ExifInterface.TAG_GPS_DEST_LONGITUDE},
|
|
{"string", ExifInterface.TAG_GPS_DEST_LONGITUDE_REF},
|
|
{"int", ExifInterface.TAG_GPS_DIFFERENTIAL},
|
|
{"double", ExifInterface.TAG_GPS_IMG_DIRECTION},
|
|
{"string", ExifInterface.TAG_GPS_IMG_DIRECTION_REF},
|
|
{"string", ExifInterface.TAG_GPS_LATITUDE_REF},
|
|
{"string", ExifInterface.TAG_GPS_LONGITUDE_REF},
|
|
{"string", ExifInterface.TAG_GPS_MAP_DATUM},
|
|
{"string", ExifInterface.TAG_GPS_MEASURE_MODE},
|
|
{"string", ExifInterface.TAG_GPS_PROCESSING_METHOD},
|
|
{"string", ExifInterface.TAG_GPS_SATELLITES},
|
|
{"double", ExifInterface.TAG_GPS_SPEED},
|
|
{"string", ExifInterface.TAG_GPS_SPEED_REF},
|
|
{"string", ExifInterface.TAG_GPS_STATUS},
|
|
{"string", ExifInterface.TAG_GPS_TIMESTAMP},
|
|
{"double", ExifInterface.TAG_GPS_TRACK},
|
|
{"string", ExifInterface.TAG_GPS_TRACK_REF},
|
|
{"string", ExifInterface.TAG_GPS_VERSION_ID},
|
|
{"string", ExifInterface.TAG_INTEROPERABILITY_INDEX},
|
|
{"int", ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH},
|
|
{"int", ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH},
|
|
{"int", ExifInterface.TAG_DNG_VERSION},
|
|
{"int", ExifInterface.TAG_DEFAULT_CROP_SIZE},
|
|
{"int", ExifInterface.TAG_ORF_PREVIEW_IMAGE_START},
|
|
{"int", ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH},
|
|
{"int", ExifInterface.TAG_ORF_ASPECT_FRAME},
|
|
{"int", ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER},
|
|
{"int", ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER},
|
|
{"int", ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER},
|
|
{"int", ExifInterface.TAG_RW2_SENSOR_TOP_BORDER},
|
|
{"int", ExifInterface.TAG_RW2_ISO},
|
|
};
|
|
|
|
// Run all events on native modules queue thread since they might be fired
|
|
// from other non RN threads.
|
|
|
|
|
|
// Mount error event
|
|
|
|
public static void emitMountErrorEvent(final ViewGroup view, final String error) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
CameraMountErrorEvent event = CameraMountErrorEvent.obtain(view.getId(), error);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Camera ready event
|
|
|
|
public static void emitCameraReadyEvent(final ViewGroup view) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
CameraReadyEvent event = CameraReadyEvent.obtain(view.getId());
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Picture saved event
|
|
|
|
public static void emitPictureSavedEvent(final ViewGroup view, final WritableMap response) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
PictureSavedEvent event = PictureSavedEvent.obtain(view.getId(), response);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
// Picture taken event
|
|
|
|
public static void emitPictureTakenEvent(final ViewGroup view) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
PictureTakenEvent event = PictureTakenEvent.obtain(view.getId());
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// video recording start/end events
|
|
|
|
public static void emitRecordingStartEvent(final ViewGroup view, final WritableMap response) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
RecordingStartEvent event = RecordingStartEvent.obtain(view.getId(), response);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void emitRecordingEndEvent(final ViewGroup view) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
RecordingEndEvent event = RecordingEndEvent.obtain(view.getId());
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
// Touch event
|
|
public static void emitTouchEvent(final ViewGroup view, final boolean isDoubleTap, final int x, final int y) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
TouchEvent event = TouchEvent.obtain(view.getId(), isDoubleTap, x, y);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
|
|
}
|
|
// Face detection events
|
|
|
|
public static void emitFacesDetectedEvent(final ViewGroup view, final WritableArray data) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
FacesDetectedEvent event = FacesDetectedEvent.obtain(view.getId(), data);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void emitFaceDetectionErrorEvent(final ViewGroup view, final RNFaceDetector faceDetector) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
FaceDetectionErrorEvent event = FaceDetectionErrorEvent.obtain(view.getId(), faceDetector);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Barcode detection events
|
|
|
|
public static void emitBarcodesDetectedEvent(final ViewGroup view, final WritableArray barcodes) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
BarcodesDetectedEvent event = BarcodesDetectedEvent.obtain(view.getId(), barcodes);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void emitBarcodeDetectionErrorEvent(final ViewGroup view, final RNBarcodeDetector barcodeDetector) {
|
|
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
BarcodeDetectionErrorEvent event = BarcodeDetectionErrorEvent.obtain(view.getId(), barcodeDetector);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Bar code read event
|
|
|
|
public static void emitBarCodeReadEvent(final ViewGroup view, final Result barCode, final int width, final int height) {
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
BarCodeReadEvent event = BarCodeReadEvent.obtain(view.getId(), barCode, width, height);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Text recognition event
|
|
|
|
public static void emitTextRecognizedEvent(final ViewGroup view, final WritableArray data) {
|
|
final ReactContext reactContext = (ReactContext) view.getContext();
|
|
reactContext.runOnNativeModulesQueueThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
TextRecognizedEvent event = TextRecognizedEvent.obtain(view.getId(), data);
|
|
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Utilities
|
|
|
|
public static int getCorrectCameraRotation(int rotation, int facing, int cameraOrientation) {
|
|
if (facing == CameraView.FACING_FRONT) {
|
|
// Tested the below line and there's no need to do the mirror calculation
|
|
return (cameraOrientation + rotation) % 360;
|
|
} else {
|
|
final int landscapeFlip = rotationIsLandscape(rotation) ? 180 : 0;
|
|
return (cameraOrientation - rotation + landscapeFlip) % 360;
|
|
}
|
|
}
|
|
|
|
private static boolean rotationIsLandscape(int rotation) {
|
|
return (rotation == Constants.LANDSCAPE_90 ||
|
|
rotation == Constants.LANDSCAPE_270);
|
|
}
|
|
|
|
private static int getCamcorderProfileQualityFromCameraModuleConstant(int quality) {
|
|
switch (quality) {
|
|
case CameraModule.VIDEO_2160P:
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
return CamcorderProfile.QUALITY_2160P;
|
|
}
|
|
case CameraModule.VIDEO_1080P:
|
|
return CamcorderProfile.QUALITY_1080P;
|
|
case CameraModule.VIDEO_720P:
|
|
return CamcorderProfile.QUALITY_720P;
|
|
case CameraModule.VIDEO_480P:
|
|
return CamcorderProfile.QUALITY_480P;
|
|
case CameraModule.VIDEO_4x3:
|
|
return CamcorderProfile.QUALITY_480P;
|
|
}
|
|
return CamcorderProfile.QUALITY_HIGH;
|
|
}
|
|
|
|
public static CamcorderProfile getCamcorderProfile(int quality) {
|
|
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
|
|
int camcorderQuality = getCamcorderProfileQualityFromCameraModuleConstant(quality);
|
|
if (CamcorderProfile.hasProfile(camcorderQuality)) {
|
|
profile = CamcorderProfile.get(camcorderQuality);
|
|
if (quality == CameraModule.VIDEO_4x3) {
|
|
profile.videoFrameWidth = 640;
|
|
}
|
|
}
|
|
return profile;
|
|
}
|
|
|
|
public static WritableMap getExifData(ExifInterface exifInterface) {
|
|
WritableMap exifMap = Arguments.createMap();
|
|
for (String[] tagInfo : exifTags) {
|
|
String name = tagInfo[1];
|
|
if (exifInterface.getAttribute(name) != null) {
|
|
String type = tagInfo[0];
|
|
switch (type) {
|
|
case "string":
|
|
exifMap.putString(name, exifInterface.getAttribute(name));
|
|
break;
|
|
case "int":
|
|
exifMap.putInt(name, exifInterface.getAttributeInt(name, 0));
|
|
break;
|
|
case "double":
|
|
exifMap.putDouble(name, exifInterface.getAttributeDouble(name, 0));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
double[] latLong = exifInterface.getLatLong();
|
|
if (latLong != null) {
|
|
exifMap.putDouble(ExifInterface.TAG_GPS_LATITUDE, latLong[0]);
|
|
exifMap.putDouble(ExifInterface.TAG_GPS_LONGITUDE, latLong[1]);
|
|
exifMap.putDouble(ExifInterface.TAG_GPS_ALTITUDE, exifInterface.getAltitude(0));
|
|
}
|
|
|
|
return exifMap;
|
|
}
|
|
|
|
public static void setExifData(ExifInterface exifInterface, ReadableMap exifMap) {
|
|
for (String[] tagInfo : exifTags) {
|
|
String name = tagInfo[1];
|
|
if (exifMap.hasKey(name)) {
|
|
String type = tagInfo[0];
|
|
switch (type) {
|
|
case "string":
|
|
exifInterface.setAttribute(name, exifMap.getString(name));
|
|
break;
|
|
case "int":
|
|
exifInterface.setAttribute(name, Integer.toString(exifMap.getInt(name)));
|
|
exifMap.getInt(name);
|
|
break;
|
|
case "double":
|
|
exifInterface.setAttribute(name, Double.toString(exifMap.getDouble(name)));
|
|
exifMap.getDouble(name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (exifMap.hasKey(ExifInterface.TAG_GPS_LATITUDE) && exifMap.hasKey(ExifInterface.TAG_GPS_LONGITUDE)) {
|
|
exifInterface.setLatLong(exifMap.getDouble(ExifInterface.TAG_GPS_LATITUDE),
|
|
exifMap.getDouble(ExifInterface.TAG_GPS_LONGITUDE));
|
|
}
|
|
if(exifMap.hasKey(ExifInterface.TAG_GPS_ALTITUDE)){
|
|
exifInterface.setAltitude(exifMap.getDouble(ExifInterface.TAG_GPS_ALTITUDE));
|
|
}
|
|
}
|
|
|
|
// clears exif values in place
|
|
public static void clearExifData(ExifInterface exifInterface) {
|
|
for (String[] tagInfo : exifTags) {
|
|
exifInterface.setAttribute(tagInfo[1], null);
|
|
}
|
|
|
|
// these are not part of our tag list, remove by hand
|
|
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, null);
|
|
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, null);
|
|
exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, null);
|
|
}
|
|
|
|
public static Bitmap generateSimulatorPhoto(int width, int height) {
|
|
Bitmap fakePhoto = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
Canvas canvas = new Canvas(fakePhoto);
|
|
Paint background = new Paint();
|
|
background.setColor(Color.BLACK);
|
|
canvas.drawRect(0, 0, width, height, background);
|
|
Paint textPaint = new Paint();
|
|
textPaint.setColor(Color.YELLOW);
|
|
textPaint.setTextSize(35);
|
|
Calendar calendar = Calendar.getInstance();
|
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd G '->' HH:mm:ss z");
|
|
canvas.drawText(simpleDateFormat.format(calendar.getTime()), width * 0.1f, height * 0.2f, textPaint);
|
|
canvas.drawText(simpleDateFormat.format(calendar.getTime()), width * 0.2f, height * 0.4f, textPaint);
|
|
canvas.drawText(simpleDateFormat.format(calendar.getTime()), width * 0.3f, height * 0.6f, textPaint);
|
|
canvas.drawText(simpleDateFormat.format(calendar.getTime()), width * 0.4f, height * 0.8f, textPaint);
|
|
|
|
return fakePhoto;
|
|
}
|
|
}
|