Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 92 additions & 27 deletions android/src/main/java/com/imagepicker/ImageMetadata.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,98 @@
package com.imagepicker;

import android.content.Context;
import android.net.Uri;
import android.util.Log;
import androidx.exifinterface.media.ExifInterface;
import java.io.InputStream;

public class ImageMetadata extends Metadata {
public ImageMetadata(Uri uri, Context context) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
ExifInterface exif = new ExifInterface(inputStream);
String datetimeTag = exif.getAttribute(ExifInterface.TAG_DATETIME);

// Extract anymore metadata here...
if(datetimeTag != null) this.datetime = getDateTimeInUTC(datetimeTag, "yyyy:MM:dd HH:mm:ss");
} catch (Exception e) {
// This error does not bubble up to RN as we don't want failed datetime retrieval to prevent selection
Log.e("RNIP", "Could not load image metadata: " + e.getMessage());
import static android.media.ExifInterface.TAG_APERTURE;
import static android.media.ExifInterface.TAG_DATETIME;
import static android.media.ExifInterface.TAG_DATETIME_DIGITIZED;
import static android.media.ExifInterface.TAG_EXPOSURE_TIME;
import static android.media.ExifInterface.TAG_FLASH;
import static android.media.ExifInterface.TAG_FOCAL_LENGTH;
import static android.media.ExifInterface.TAG_GPS_ALTITUDE;
import static android.media.ExifInterface.TAG_GPS_ALTITUDE_REF;
import static android.media.ExifInterface.TAG_GPS_DATESTAMP;
import static android.media.ExifInterface.TAG_GPS_LATITUDE;
import static android.media.ExifInterface.TAG_GPS_LATITUDE_REF;
import static android.media.ExifInterface.TAG_GPS_LONGITUDE;
import static android.media.ExifInterface.TAG_GPS_LONGITUDE_REF;
import static android.media.ExifInterface.TAG_GPS_PROCESSING_METHOD;
import static android.media.ExifInterface.TAG_GPS_TIMESTAMP;
import static android.media.ExifInterface.TAG_IMAGE_LENGTH;
import static android.media.ExifInterface.TAG_IMAGE_WIDTH;
import static android.media.ExifInterface.TAG_ISO;
import static android.media.ExifInterface.TAG_MAKE;
import static android.media.ExifInterface.TAG_MODEL;
import static android.media.ExifInterface.TAG_ORIENTATION;
import static android.media.ExifInterface.TAG_SUBSEC_TIME;
import static android.media.ExifInterface.TAG_SUBSEC_TIME_DIG;
import static android.media.ExifInterface.TAG_SUBSEC_TIME_ORIG;
import static android.media.ExifInterface.TAG_WHITE_BALANCE;

import android.media.ExifInterface;
import android.os.Build;

import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class ImageMetadata {

static WritableMap extract(String path) throws IOException {
WritableMap exifData = new WritableNativeMap();

List<String> attributes = getBasicAttributes();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
attributes.addAll(getLevel23Attributes());
}

ExifInterface exif = new ExifInterface(path);

for (String attribute : attributes) {
String value = exif.getAttribute(attribute);
exifData.putString(attribute, value);
}

return exifData;
}

private static List<String> getBasicAttributes() {
return new ArrayList<>(Arrays.asList(
TAG_APERTURE,
TAG_DATETIME,
TAG_EXPOSURE_TIME,
TAG_FLASH,
TAG_FOCAL_LENGTH,
TAG_GPS_ALTITUDE,
TAG_GPS_ALTITUDE_REF,
TAG_GPS_DATESTAMP,
TAG_GPS_LATITUDE,
TAG_GPS_LATITUDE_REF,
TAG_GPS_LONGITUDE,
TAG_GPS_LONGITUDE_REF,
TAG_GPS_PROCESSING_METHOD,
TAG_GPS_TIMESTAMP,
TAG_IMAGE_LENGTH,
TAG_IMAGE_WIDTH,
TAG_ISO,
TAG_MAKE,
TAG_MODEL,
TAG_ORIENTATION,
TAG_WHITE_BALANCE
));
}

@Override
public String getDateTime() { return datetime; }

// At the moment we are not using the ImageMetadata class to get width/height
// TODO: to use this class for extracting image width and height in the future
@Override
public int getWidth() { return 0; }
@Override
public int getHeight() { return 0; }
private static List<String> getLevel23Attributes() {
return new ArrayList<>(Arrays.asList(
TAG_DATETIME_DIGITIZED,
TAG_SUBSEC_TIME,
TAG_SUBSEC_TIME_DIG,
TAG_SUBSEC_TIME_ORIG
));


}

}
56 changes: 29 additions & 27 deletions android/src/main/java/com/imagepicker/ImagePickerModuleImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
package com.imagepicker;

import static com.imagepicker.Utils.cameraPermissionDescription;
import static com.imagepicker.Utils.collectUrisFromData;
import static com.imagepicker.Utils.createFile;
import static com.imagepicker.Utils.createUri;
import static com.imagepicker.Utils.deleteFile;
import static com.imagepicker.Utils.errCameraUnavailable;
import static com.imagepicker.Utils.errOthers;
import static com.imagepicker.Utils.errPermission;
import static com.imagepicker.Utils.getCancelMap;
import static com.imagepicker.Utils.getErrorMap;
import static com.imagepicker.Utils.getResponseMap;
import static com.imagepicker.Utils.hasPermission;
import static com.imagepicker.Utils.isCameraAvailable;
import static com.imagepicker.Utils.isCameraPermissionFulfilled;
import static com.imagepicker.Utils.isValidRequestCode;
import static com.imagepicker.Utils.mediaTypePhoto;
import static com.imagepicker.Utils.mediaTypeVideo;
import static com.imagepicker.Utils.saveToPublicDirectory;
import static com.imagepicker.Utils.setFrontCamera;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
Expand All @@ -10,17 +30,12 @@
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Callback;
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.module.annotations.ReactModule;

import java.io.File;
import java.util.Collections;
import java.util.List;

import static com.imagepicker.Utils.*;

public class ImagePickerModuleImpl implements ActivityEventListener {
static final String NAME = "ImagePicker";

Expand Down Expand Up @@ -118,39 +133,26 @@ public void launchImageLibrary(final ReadableMap options, final Callback callbac
Intent libraryIntent;
requestCode = REQUEST_LAUNCH_LIBRARY;

int selectionLimit = this.options.selectionLimit;
boolean isSingleSelect = selectionLimit == 1;
boolean isSingleSelect = this.options.selectionLimit == 1;
boolean isPhoto = this.options.mediaType.equals(mediaTypePhoto);
boolean isVideo = this.options.mediaType.equals(mediaTypeVideo);
if(isSingleSelect && (isPhoto || isVideo)) {
libraryIntent = new Intent(Intent.ACTION_PICK);

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (isSingleSelect && (isPhoto || isVideo)) {
libraryIntent = new Intent(Intent.ACTION_PICK);
} else {
libraryIntent = new Intent(Intent.ACTION_GET_CONTENT);
libraryIntent.addCategory(Intent.CATEGORY_OPENABLE);
}
} else {
libraryIntent = new Intent(MediaStore.ACTION_PICK_IMAGES);
libraryIntent = new Intent(Intent.ACTION_GET_CONTENT);
libraryIntent.addCategory(Intent.CATEGORY_OPENABLE);
}

if (!isSingleSelect) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
libraryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
} else {
if (selectionLimit != 1) {
int maxNum = selectionLimit;
if (selectionLimit == 0) maxNum = MediaStore.getPickImagesMaxLimit();
libraryIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNum);
}
}
if(!isSingleSelect) {
libraryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}

if (isPhoto) {
if(isPhoto) {
libraryIntent.setType("image/*");
} else if (isVideo) {
libraryIntent.setType("video/*");
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
} else {
libraryIntent.setType("*/*");
libraryIntent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});
}
Expand Down
Loading