mirror of
https://github.com/status-im/react-native-image-crop-picker.git
synced 2025-02-23 02:48:12 +00:00
[FEATURE] Video support
This commit is contained in:
parent
3b7f2c4c21
commit
457c0efbd5
@ -1,5 +1,5 @@
|
||||
# react-native-image-crop-picker
|
||||
iOS/Android image picker with support for camera, multiple images and cropping
|
||||
iOS/Android image picker with support for camera, video compression, multiple images and cropping
|
||||
|
||||
## Result
|
||||
|
||||
@ -68,6 +68,7 @@ ImagePicker.clean().then(() => {
|
||||
| multiple | bool (default false) | Enable or disable multiple image selection |
|
||||
| includeBase64 | bool (default false) | Enable or disable returning base64 data with image |
|
||||
| maxFiles (ios only) | number (default 5) | Max number of files to select when using `multiple` option |
|
||||
| compressVideo (ios only) | number (default true) | When video is selected, compress it and convert it to mp4 |
|
||||
|
||||
#### Response Object
|
||||
|
||||
@ -95,7 +96,7 @@ react-native link react-native-image-crop-picker
|
||||
|
||||
- Add `platform :ios, '8.0'` to Podfile (!important)
|
||||
- Add `pod 'RSKImageCropper'` and `pod 'QBImagePickerController'` to Podfile
|
||||
|
||||
|
||||
###### non-cocoapods users
|
||||
|
||||
- Drag and drop the ios/ImageCropPickerSDK folder to your xcode project. (Make sure Copy items if needed IS ticked)
|
||||
@ -141,4 +142,3 @@ It is basically wrapper around few libraries
|
||||
|
||||
## License
|
||||
*MIT*
|
||||
|
||||
|
@ -16,5 +16,5 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile 'com.facebook.react:react-native:+'
|
||||
compile 'com.yalantis:ucrop:2.1.2'
|
||||
compile 'com.yalantis:ucrop:2.2.0-native'
|
||||
}
|
@ -7,6 +7,7 @@ import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
@ -28,6 +29,7 @@ import com.facebook.react.bridge.WritableNativeMap;
|
||||
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import com.yalantis.ucrop.UCrop;
|
||||
|
||||
@ -58,6 +60,7 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
private static final String E_CAMERA_IS_NOT_AVAILABLE = "E_CAMERA_IS_NOT_AVAILABLE";
|
||||
private static final String E_CANNOT_LAUNCH_CAMERA = "E_CANNOT_LAUNCH_CAMERA";
|
||||
private static final String E_PERMISSIONS_MISSING = "E_PERMISSIONS_MISSING";
|
||||
private static final String E_ERROR_WHILE_CLEANING_FILES = "E_ERROR_WHILE_CLEANING_FILES";
|
||||
|
||||
private Promise mPickerPromise;
|
||||
private Activity activity;
|
||||
@ -77,6 +80,15 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
mReactContext = reactContext;
|
||||
}
|
||||
|
||||
public String getTmpDir() {
|
||||
String tmpDir = mReactContext.getCacheDir() + "/react-native-image-crop-picker";
|
||||
Boolean created = new File(tmpDir).mkdir();
|
||||
|
||||
System.out.println(tmpDir);
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ImageCropPicker";
|
||||
@ -90,14 +102,52 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
cropping = options.hasKey("cropping") ? options.getBoolean("cropping") : cropping;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void clean(final Promise promise) {
|
||||
promise.resolve(null);
|
||||
private void deleteRecursive(File fileOrDirectory) {
|
||||
if (fileOrDirectory.isDirectory()) {
|
||||
for (File child : fileOrDirectory.listFiles()) {
|
||||
deleteRecursive(child);
|
||||
}
|
||||
}
|
||||
|
||||
fileOrDirectory.delete();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void cleanSingle(final String path, final Promise promise) {
|
||||
promise.resolve(null);
|
||||
public void clean(final Promise promise) {
|
||||
try {
|
||||
File file = new File(this.getTmpDir());
|
||||
if (!file.exists()) throw new Exception("File does not exist");
|
||||
|
||||
this.deleteRecursive(file);
|
||||
promise.resolve(null);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
promise.reject(E_ERROR_WHILE_CLEANING_FILES, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void cleanSingle(String path, final Promise promise) {
|
||||
if (path == null) {
|
||||
promise.reject(E_ERROR_WHILE_CLEANING_FILES, "Cannot cleanup empty path");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final String filePrefix = "file://";
|
||||
if (path.startsWith(filePrefix)) {
|
||||
path = path.substring(filePrefix.length());
|
||||
}
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.exists()) throw new Exception("File does not exist. Path: " + path);
|
||||
|
||||
this.deleteRecursive(file);
|
||||
promise.resolve(null);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
promise.reject(E_ERROR_WHILE_CLEANING_FILES, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@ -159,7 +209,13 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
|
||||
try {
|
||||
final Intent galleryIntent = new Intent(Intent.ACTION_PICK);
|
||||
galleryIntent.setType("image/*");
|
||||
|
||||
if (cropping) {
|
||||
galleryIntent.setType("image/*");
|
||||
} else {
|
||||
galleryIntent.setType("image/*,video/*");
|
||||
}
|
||||
|
||||
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple);
|
||||
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
galleryIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
@ -198,7 +254,50 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
return Base64.encodeToString(bytes, Base64.NO_WRAP);
|
||||
}
|
||||
|
||||
private WritableMap getImage(Uri uri, boolean resolvePath) {
|
||||
public static String getMimeType(String url) {
|
||||
String type = null;
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension != null) {
|
||||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public WritableMap getSelection(Uri uri) throws Exception {
|
||||
String path = RealPathUtil.getRealPathFromURI(activity, uri);
|
||||
if (path == null || path.isEmpty()) {
|
||||
throw new Exception("Cannot resolve image path.");
|
||||
}
|
||||
|
||||
String mime = getMimeType(path);
|
||||
if (mime != null && mime.startsWith("video/")) {
|
||||
return getVideo(path, mime);
|
||||
}
|
||||
|
||||
return getImage(uri, true);
|
||||
}
|
||||
|
||||
public WritableMap getVideo(String path, String mime) {
|
||||
WritableMap image = new WritableNativeMap();
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(path);
|
||||
Bitmap bmp = retriever.getFrameAtTime();
|
||||
|
||||
if (bmp != null) {
|
||||
image.putInt("width", bmp.getWidth());
|
||||
image.putInt("height", bmp.getHeight());
|
||||
}
|
||||
|
||||
image.putString("path", "file://" + path);
|
||||
image.putString("mime", mime);
|
||||
image.putInt("size", (int) new File(path).length());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private WritableMap getImage(Uri uri, boolean resolvePath) throws Exception {
|
||||
WritableMap image = new WritableNativeMap();
|
||||
String path = uri.getPath();
|
||||
|
||||
@ -206,20 +305,19 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
path = RealPathUtil.getRealPathFromURI(activity, uri);
|
||||
}
|
||||
|
||||
if (path == null || path.isEmpty()) {
|
||||
throw new Exception("Cannot resolve image path.");
|
||||
}
|
||||
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
||||
long fileLen = 0;
|
||||
if (path != null) {
|
||||
fileLen = new File(path).length();
|
||||
}
|
||||
|
||||
BitmapFactory.decodeFile(path, options);
|
||||
image.putString("path", "file://" + path);
|
||||
image.putInt("width", options.outWidth);
|
||||
image.putInt("height", options.outHeight);
|
||||
image.putString("mime", options.outMimeType);
|
||||
image.putInt("size", (int) fileLen);
|
||||
image.putInt("size", (int) new File(path).length());
|
||||
|
||||
if (includeBase64) {
|
||||
image.putString("data", getBase64StringFromFile(path));
|
||||
@ -232,7 +330,7 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
UCrop.Options options = new UCrop.Options();
|
||||
options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
|
||||
|
||||
UCrop.of(uri, Uri.fromFile(new File(activity.getCacheDir(), UUID.randomUUID().toString() + ".jpg")))
|
||||
UCrop.of(uri, Uri.fromFile(new File(this.getTmpDir(), UUID.randomUUID().toString() + ".jpg")))
|
||||
.withMaxResultSize(width, height)
|
||||
.withAspectRatio(width, height)
|
||||
.withOptions(options)
|
||||
@ -251,23 +349,36 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
ClipData clipData = data.getClipData();
|
||||
WritableArray result = new WritableNativeArray();
|
||||
|
||||
// only one image selected
|
||||
if (clipData == null) {
|
||||
result.pushMap(getImage(data.getData(), true));
|
||||
} else {
|
||||
for (int i = 0; i < clipData.getItemCount(); i++) {
|
||||
result.pushMap(getImage(clipData.getItemAt(i).getUri(), true));
|
||||
try {
|
||||
// only one image selected
|
||||
if (clipData == null) {
|
||||
result.pushMap(getSelection(data.getData()));
|
||||
} else {
|
||||
for (int i = 0; i < clipData.getItemCount(); i++) {
|
||||
result.pushMap(getSelection(clipData.getItemAt(i).getUri()));
|
||||
}
|
||||
}
|
||||
|
||||
mPickerPromise.resolve(result);
|
||||
} catch (Exception ex) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
|
||||
}
|
||||
|
||||
mPickerPromise.resolve(result);
|
||||
} else {
|
||||
Uri uri = data.getData();
|
||||
|
||||
if (cropping && uri != null) {
|
||||
if (uri == null) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Cannot resolve image url");
|
||||
}
|
||||
|
||||
if (cropping) {
|
||||
startCropping(uri);
|
||||
} else {
|
||||
mPickerPromise.resolve(getImage(uri, true));
|
||||
try {
|
||||
mPickerPromise.resolve(getSelection(uri));
|
||||
} catch (Exception ex) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -280,15 +391,24 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
|
||||
if (resultCode == Activity.RESULT_CANCELED) {
|
||||
mPickerPromise.reject(E_PICKER_CANCELLED_KEY, E_PICKER_CANCELLED_MSG);
|
||||
} else if (resultCode == Activity.RESULT_OK && mCameraCaptureURI != null) {
|
||||
} else if (resultCode == Activity.RESULT_OK) {
|
||||
Uri uri = mCameraCaptureURI;
|
||||
|
||||
if (uri == null) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Cannot resolve image url");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cropping) {
|
||||
UCrop.Options options = new UCrop.Options();
|
||||
options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
|
||||
startCropping(uri);
|
||||
} else {
|
||||
mPickerPromise.resolve(getImage(uri, true));
|
||||
try {
|
||||
mPickerPromise.resolve(getImage(uri, true));
|
||||
} catch (Exception ex) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,7 +417,11 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
if (data != null) {
|
||||
final Uri resultUri = UCrop.getOutput(data);
|
||||
if (resultUri != null) {
|
||||
mPickerPromise.resolve(getImage(resultUri, false));
|
||||
try {
|
||||
mPickerPromise.resolve(getImage(resultUri, false));
|
||||
} catch (Exception ex) {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Cannot find image data");
|
||||
}
|
||||
@ -344,7 +468,7 @@ public class PickerModule extends ReactContextBaseJavaModule implements Activity
|
||||
private File createNewFile(final boolean forcePictureDirectory) {
|
||||
String filename = "image-" + UUID.randomUUID().toString() + ".jpg";
|
||||
if (tmpImage && (!forcePictureDirectory)) {
|
||||
return new File(mReactContext.getCacheDir(), filename);
|
||||
return new File(this.getTmpDir(), filename);
|
||||
} else {
|
||||
File path = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PICTURES);
|
||||
|
@ -88,7 +88,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example"
|
||||
minSdkVersion 16
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 22
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@ -126,6 +126,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-video')
|
||||
compile project(':react-native-image-crop-picker')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.android.support:appcompat-v7:23.1.1"
|
||||
|
@ -3,6 +3,7 @@ package com.example;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.brentvatne.react.ReactVideoPackage;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
@ -23,6 +24,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new ReactVideoPackage(),
|
||||
new PickerPackage()
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
<resources>
|
||||
|
||||
<string name="app_name">example</string>
|
||||
</resources>
|
||||
|
@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
classpath 'com.android.tools.build:gradle:2.1.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -1,6 +1,6 @@
|
||||
#Fri Aug 26 00:38:15 CEST 2016
|
||||
#Sat Sep 10 03:05:34 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
@ -1,6 +1,8 @@
|
||||
rootProject.name = 'example'
|
||||
|
||||
include ':app'
|
||||
include ':react-native-video'
|
||||
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
|
||||
|
||||
include ':react-native-image-crop-picker'
|
||||
project(':react-native-image-crop-picker').projectDir = new File(settingsDir, '../../android')
|
@ -1,7 +1,11 @@
|
||||
import React, {Component} from 'react';
|
||||
import {View, Text, StyleSheet, ScrollView, Image, TouchableOpacity} from 'react-native';
|
||||
import {
|
||||
View, Text, StyleSheet, ScrollView,
|
||||
Image, TouchableOpacity, NativeModules, Dimensions
|
||||
} from 'react-native';
|
||||
|
||||
import Video from 'react-native-video';
|
||||
|
||||
import {NativeModules, Dimensions} from 'react-native';
|
||||
var ImagePicker = NativeModules.ImageCropPicker;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@ -57,7 +61,7 @@ export default class App extends Component {
|
||||
image: {uri: `data:${image.mime};base64,`+ image.data, width: image.width, height: image.height},
|
||||
images: null
|
||||
});
|
||||
}).catch(e => {});
|
||||
}).catch(e => alert(e));
|
||||
}
|
||||
|
||||
cleanupImages() {
|
||||
@ -83,14 +87,15 @@ export default class App extends Component {
|
||||
ImagePicker.openPicker({
|
||||
width: 300,
|
||||
height: 300,
|
||||
cropping: cropit
|
||||
cropping: cropit,
|
||||
compressVideo: true
|
||||
}).then(image => {
|
||||
console.log('received image', image);
|
||||
this.setState({
|
||||
image: {uri: image.path, width: image.width, height: image.height},
|
||||
image: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
|
||||
images: null
|
||||
});
|
||||
}).catch(e => {});
|
||||
}).catch(e => alert(e));
|
||||
}
|
||||
|
||||
pickMultiple() {
|
||||
@ -101,21 +106,54 @@ export default class App extends Component {
|
||||
image: null,
|
||||
images: images.map(i => {
|
||||
console.log('received image', i);
|
||||
return {uri: i.path, width: i.width, height: i.height};
|
||||
return {uri: i.path, width: i.width, height: i.height, mime: i.mime};
|
||||
})
|
||||
});
|
||||
}).catch(e => {});
|
||||
}).catch(e => alert(e));
|
||||
}
|
||||
|
||||
scaledHeight(oldW, oldH, newW) {
|
||||
return (oldH / oldW) * newW;
|
||||
}
|
||||
|
||||
renderVideo(uri) {
|
||||
return <View style={{height: 300, width: 300}}>
|
||||
<Video source={{uri}}
|
||||
style={{position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0
|
||||
}}
|
||||
rate={1}
|
||||
paused={false}
|
||||
volume={1}
|
||||
muted={false}
|
||||
resizeMode={'cover'}
|
||||
onLoad={load => console.log(load)}
|
||||
onProgress={() => {}}
|
||||
onEnd={() => { console.log('Done!'); }}
|
||||
repeat={true} />
|
||||
</View>;
|
||||
}
|
||||
|
||||
renderImage(image) {
|
||||
return <Image style={{width: 300, height: 300, resizeMode: 'contain'}} source={image} />
|
||||
}
|
||||
|
||||
renderAsset(image) {
|
||||
if (image.mime && image.mime.toLowerCase().indexOf('video/') !== -1) {
|
||||
return this.renderVideo(image.uri);
|
||||
}
|
||||
|
||||
return this.renderImage(image);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <View style={styles.container}>
|
||||
<ScrollView>
|
||||
{this.state.image ? <Image style={{width: 300, height: 300, resizeMode: 'contain'}} source={this.state.image} /> : null}
|
||||
{this.state.images ? this.state.images.map(i => <Image key={i.uri} style={{width: 300, height: this.scaledHeight(i.width, i.height, 300)}} source={i} />) : null}
|
||||
{this.state.image ? this.renderAsset(this.state.image) : null}
|
||||
{this.state.images ? this.state.images.map(i => <View key={i.uri}>{this.renderAsset(i)}</View>) : null}
|
||||
</ScrollView>
|
||||
|
||||
<TouchableOpacity onPress={() => this.pickSingleWithCamera(false)} style={styles.button}>
|
||||
|
@ -27,6 +27,7 @@
|
||||
34A9DDBD1D7F43320012B1F5 /* QBImagePicker.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34A9DDB81D7F43220012B1F5 /* QBImagePicker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
34A9DDBE1D7F43320012B1F5 /* RSKImageCropper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A9DDB91D7F43220012B1F5 /* RSKImageCropper.framework */; };
|
||||
34A9DDBF1D7F43320012B1F5 /* RSKImageCropper.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34A9DDB91D7F43220012B1F5 /* RSKImageCropper.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
7165791E23AC464E8943EEF6 /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FE03BA1664084F9C9C188799 /* libRCTVideo.a */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -94,6 +95,13 @@
|
||||
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
|
||||
remoteInfo = React;
|
||||
};
|
||||
34534DEB1D8374A6005D9519 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 69779CA3792A4BD79EBAC2CD /* RCTVideo.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTVideo;
|
||||
};
|
||||
3460B9DF1D6BA58300CCEC39 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 3460B9D91D6BA58300CCEC39 /* imageCropPicker.xcodeproj */;
|
||||
@ -155,8 +163,10 @@
|
||||
3460B9D91D6BA58300CCEC39 /* imageCropPicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = imageCropPicker.xcodeproj; path = ../../ios/imageCropPicker.xcodeproj; sourceTree = "<group>"; };
|
||||
34A9DDB81D7F43220012B1F5 /* QBImagePicker.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = QBImagePicker.framework; sourceTree = "<group>"; };
|
||||
34A9DDB91D7F43220012B1F5 /* RSKImageCropper.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RSKImageCropper.framework; sourceTree = "<group>"; };
|
||||
69779CA3792A4BD79EBAC2CD /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/RCTVideo.xcodeproj"; sourceTree = "<group>"; };
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
FE03BA1664084F9C9C188799 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -185,6 +195,7 @@
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
|
||||
34A9DDBC1D7F43320012B1F5 /* QBImagePicker.framework in Frameworks */,
|
||||
7165791E23AC464E8943EEF6 /* libRCTVideo.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -286,6 +297,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
34534DDF1D8374A6005D9519 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34534DEC1D8374A6005D9519 /* libRCTVideo.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3460B9DA1D6BA58300CCEC39 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -325,6 +344,7 @@
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
|
||||
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
|
||||
69779CA3792A4BD79EBAC2CD /* RCTVideo.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@ -405,7 +425,7 @@
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
LastUpgradeCheck = 730;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
00E356ED1AD99517003FC87E = {
|
||||
@ -465,6 +485,10 @@
|
||||
ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 34534DDF1D8374A6005D9519 /* Products */;
|
||||
ProjectRef = 69779CA3792A4BD79EBAC2CD /* RCTVideo.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
|
||||
ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
|
||||
@ -539,6 +563,13 @@
|
||||
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
34534DEC1D8374A6005D9519 /* libRCTVideo.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTVideo.a;
|
||||
remoteRef = 34534DEB1D8374A6005D9519 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
3460B9E01D6BA58300CCEC39 /* libimageCropPicker.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@ -650,6 +681,10 @@
|
||||
INFOPLIST_FILE = exampleTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
|
||||
@ -664,6 +699,10 @@
|
||||
INFOPLIST_FILE = exampleTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
|
||||
@ -685,6 +724,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-video",
|
||||
);
|
||||
INFOPLIST_FILE = example/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@ -713,6 +753,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-video",
|
||||
);
|
||||
INFOPLIST_FILE = example/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@ -766,6 +807,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-video",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
@ -806,6 +848,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-video",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
|
@ -22,6 +22,9 @@
|
||||
#define ERROR_CANNOT_SAVE_IMAGE_KEY @"cannot_save_image"
|
||||
#define ERROR_CANNOT_SAVE_IMAGE_MSG @"Cannot save image. Unable to write to tmp location."
|
||||
|
||||
#define ERROR_CANNOT_PROCESS_VIDEO_KEY @"cannot_process_video"
|
||||
#define ERROR_CANNOT_PROCESS_VIDEO_MSG @"Cannot process video data"
|
||||
|
||||
@implementation ImageCropPicker
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
@ -33,6 +36,7 @@ RCT_EXPORT_MODULE();
|
||||
@"multiple": @NO,
|
||||
@"cropping": @NO,
|
||||
@"includeBase64": @NO,
|
||||
@"compressVideo": @YES,
|
||||
@"maxFiles": @5,
|
||||
@"width": @200,
|
||||
@"height": @200
|
||||
@ -117,8 +121,17 @@ RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
|
||||
}
|
||||
|
||||
- (NSString*) getTmpDirectory {
|
||||
NSString* TMP_DIRECTORY = @"/react-native-image-crop-picker/";
|
||||
return [NSTemporaryDirectory() stringByAppendingString:TMP_DIRECTORY];
|
||||
NSString *TMP_DIRECTORY = @"react-native-image-crop-picker/";
|
||||
NSString *tmpFullPath = [NSTemporaryDirectory() stringByAppendingString:TMP_DIRECTORY];
|
||||
|
||||
BOOL isDir;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:tmpFullPath isDirectory:&isDir];
|
||||
if (!exists) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath: tmpFullPath
|
||||
withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
return tmpFullPath;
|
||||
}
|
||||
|
||||
- (BOOL)cleanTmpDirectory {
|
||||
@ -172,7 +185,12 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
imagePickerController.allowsMultipleSelection = [[self.options objectForKey:@"multiple"] boolValue];
|
||||
imagePickerController.maximumNumberOfSelection = [[self.options objectForKey:@"maxFiles"] intValue];
|
||||
imagePickerController.showsNumberOfSelectedAssets = YES;
|
||||
imagePickerController.mediaType = QBImagePickerMediaTypeImage;
|
||||
|
||||
if ([[self.options objectForKey:@"cropping"] boolValue]) {
|
||||
imagePickerController.mediaType = QBImagePickerMediaTypeImage;
|
||||
} else {
|
||||
imagePickerController.mediaType = QBImagePickerMediaTypeAny;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[self getRootVC] presentViewController:imagePickerController animated:YES completion:nil];
|
||||
@ -181,6 +199,121 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL
|
||||
outputURL:(NSURL*)outputURL
|
||||
handler:(void (^)(AVAssetExportSession*))handler {
|
||||
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
|
||||
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
|
||||
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
|
||||
exportSession.outputURL = outputURL;
|
||||
exportSession.outputFileType = AVFileTypeMPEG4;
|
||||
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
|
||||
{
|
||||
handler(exportSession);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)showActivityIndicator:(void (^)(UIActivityIndicatorView*, UIView*))handler {
|
||||
UIView *mainView = [[self getRootVC] view];
|
||||
|
||||
// create overlay
|
||||
UIView *loadingView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
|
||||
loadingView.clipsToBounds = YES;
|
||||
|
||||
// create loading spinner
|
||||
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
activityView.frame = CGRectMake(65, 40, activityView.bounds.size.width, activityView.bounds.size.height);
|
||||
activityView.center = loadingView.center;
|
||||
[loadingView addSubview:activityView];
|
||||
|
||||
// create message
|
||||
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 115, 130, 22)];
|
||||
loadingLabel.backgroundColor = [UIColor clearColor];
|
||||
loadingLabel.textColor = [UIColor whiteColor];
|
||||
loadingLabel.adjustsFontSizeToFitWidth = YES;
|
||||
CGPoint loadingLabelLocation = loadingView.center;
|
||||
loadingLabelLocation.y += [activityView bounds].size.height;
|
||||
loadingLabel.center = loadingLabelLocation;
|
||||
loadingLabel.textAlignment = UITextAlignmentCenter;
|
||||
loadingLabel.text = @"Processing assets...";
|
||||
[loadingLabel setFont:[UIFont boldSystemFontOfSize:18]];
|
||||
[loadingView addSubview:loadingLabel];
|
||||
|
||||
// show all
|
||||
[mainView addSubview:loadingView];
|
||||
[activityView startAnimating];
|
||||
|
||||
handler(activityView, loadingView);
|
||||
}
|
||||
|
||||
|
||||
- (void) getVideoAsset:(PHAsset*)forAsset completion:(void (^)(NSDictionary* image))completion {
|
||||
PHImageManager *manager = [PHImageManager defaultManager];
|
||||
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
|
||||
options.version = PHVideoRequestOptionsVersionOriginal;
|
||||
|
||||
[manager
|
||||
requestAVAssetForVideo:forAsset
|
||||
options:options
|
||||
resultHandler:^(AVAsset * asset, AVAudioMix * audioMix,
|
||||
NSDictionary *info) {
|
||||
NSURL *sourceURL = [(AVURLAsset *)asset URL];
|
||||
AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||
CGSize dimensions = CGSizeApplyAffineTransform(track.naturalSize, track.preferredTransform);
|
||||
|
||||
if (![[self.options objectForKey:@"compressVideo"] boolValue]) {
|
||||
NSNumber *fileSizeValue = nil;
|
||||
[sourceURL getResourceValue:&fileSizeValue
|
||||
forKey:NSURLFileSizeKey
|
||||
error:nil];
|
||||
|
||||
completion([self createAttachmentResponse:[sourceURL absoluteString]
|
||||
withWidth:[NSNumber numberWithFloat:dimensions.width]
|
||||
withHeight:[NSNumber numberWithFloat:dimensions.height]
|
||||
withMime:[@"video/" stringByAppendingString:[[sourceURL pathExtension] lowercaseString]]
|
||||
withSize:fileSizeValue
|
||||
withData:[NSNull null]]);
|
||||
return;
|
||||
}
|
||||
|
||||
// create temp file
|
||||
NSString *tmpDirFullPath = [self getTmpDirectory];
|
||||
NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]];
|
||||
filePath = [filePath stringByAppendingString:@".mp4"];
|
||||
NSURL *outputURL = [NSURL fileURLWithPath:filePath];
|
||||
|
||||
[self convertVideoToLowQuailtyWithInputURL:sourceURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession) {
|
||||
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
|
||||
NSNumber *fileSizeValue = nil;
|
||||
[outputURL getResourceValue:&fileSizeValue
|
||||
forKey:NSURLFileSizeKey
|
||||
error:nil];
|
||||
|
||||
completion([self createAttachmentResponse:[outputURL absoluteString]
|
||||
withWidth:[NSNumber numberWithFloat:dimensions.width]
|
||||
withHeight:[NSNumber numberWithFloat:dimensions.height]
|
||||
withMime:@"video/mp4"
|
||||
withSize:fileSizeValue
|
||||
withData:[NSNull null]]);
|
||||
} else {
|
||||
completion(nil);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSDictionary*) createAttachmentResponse:(NSString*)filePath withWidth:(NSNumber*)width withHeight:(NSNumber*)height withMime:(NSString*)mime withSize:(NSNumber*)size withData:(NSString*)data {
|
||||
return @{
|
||||
@"path": filePath,
|
||||
@"width": width,
|
||||
@"height": height,
|
||||
@"mime": mime,
|
||||
@"size": size,
|
||||
@"data": data,
|
||||
};
|
||||
}
|
||||
|
||||
- (void)qb_imagePickerController:
|
||||
(QBImagePickerController *)imagePickerController
|
||||
didFinishPickingAssets:(NSArray *)assets {
|
||||
@ -188,47 +321,101 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
PHImageManager *manager = [PHImageManager defaultManager];
|
||||
|
||||
if ([[[self options] objectForKey:@"multiple"] boolValue]) {
|
||||
NSMutableArray *images = [[NSMutableArray alloc] init];
|
||||
NSMutableArray *selections = [[NSMutableArray alloc] init];
|
||||
PHImageRequestOptions* options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = YES;
|
||||
|
||||
for (PHAsset *asset in assets) {
|
||||
[self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) {
|
||||
NSLock *lock = [[NSLock alloc] init];
|
||||
__block int processed = 0;
|
||||
|
||||
for (PHAsset *phAsset in assets) {
|
||||
|
||||
if (phAsset.mediaType == PHAssetMediaTypeVideo) {
|
||||
[self getVideoAsset:phAsset completion:^(NSDictionary* video) {
|
||||
[lock lock];
|
||||
|
||||
if (video != nil) {
|
||||
[selections addObject:video];
|
||||
}
|
||||
|
||||
processed++;
|
||||
[lock unlock];
|
||||
|
||||
if (processed == [assets count]) {
|
||||
self.resolve(selections);
|
||||
[indicatorView stopAnimating];
|
||||
[overlayView removeFromSuperview];
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[manager
|
||||
requestImageDataForAsset:phAsset
|
||||
options:options
|
||||
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
NSData *data = UIImageJPEGRepresentation(image, 1);
|
||||
|
||||
NSString *filePath = [self persistFile:data];
|
||||
if (filePath == nil) {
|
||||
self.reject(ERROR_CANNOT_SAVE_IMAGE_KEY, ERROR_CANNOT_SAVE_IMAGE_MSG, nil);
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
[lock lock];
|
||||
[selections addObject:[self createAttachmentResponse:filePath
|
||||
withWidth:@(phAsset.pixelWidth)
|
||||
withHeight:@(phAsset.pixelHeight)
|
||||
withMime:@"image/jpeg"
|
||||
withSize:[NSNumber numberWithUnsignedInteger:data.length]
|
||||
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null]
|
||||
]];
|
||||
processed++;
|
||||
[lock unlock];
|
||||
|
||||
if (processed == [assets count]) {
|
||||
self.resolve(selections);
|
||||
[indicatorView stopAnimating];
|
||||
[overlayView removeFromSuperview];
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
PHAsset *phAsset = [assets objectAtIndex:0];
|
||||
|
||||
if (phAsset.mediaType == PHAssetMediaTypeVideo) {
|
||||
|
||||
[self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) {
|
||||
[self getVideoAsset:phAsset completion:^(NSDictionary* video) {
|
||||
if (video != nil) {
|
||||
self.resolve(video);
|
||||
} else {
|
||||
self.reject(ERROR_CANNOT_PROCESS_VIDEO_KEY, ERROR_CANNOT_PROCESS_VIDEO_MSG, nil);
|
||||
}
|
||||
|
||||
|
||||
[indicatorView stopAnimating];
|
||||
[overlayView removeFromSuperview];
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
}];
|
||||
} else {
|
||||
[manager
|
||||
requestImageDataForAsset:asset
|
||||
options:options
|
||||
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
NSData *data = UIImageJPEGRepresentation(image, 1);
|
||||
|
||||
NSString *filePath = [self persistFile:data];
|
||||
if (filePath == nil) {
|
||||
self.reject(ERROR_CANNOT_SAVE_IMAGE_KEY, ERROR_CANNOT_SAVE_IMAGE_MSG, nil);
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
[images addObject:@{
|
||||
@"path": filePath,
|
||||
@"width": @(asset.pixelWidth),
|
||||
@"height": @(asset.pixelHeight),
|
||||
@"mime": @"image/jpeg",
|
||||
@"size": [NSNumber numberWithUnsignedInteger:data.length],
|
||||
@"data": [[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null],
|
||||
}];
|
||||
requestImageDataForAsset:phAsset
|
||||
options:nil
|
||||
resultHandler:^(NSData *imageData, NSString *dataUTI,
|
||||
UIImageOrientation orientation,
|
||||
NSDictionary *info) {
|
||||
[self processSingleImagePick:[UIImage imageWithData:imageData] withViewController:imagePickerController];
|
||||
}];
|
||||
}
|
||||
|
||||
self.resolve(images);
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
} else {
|
||||
[manager
|
||||
requestImageDataForAsset:[assets objectAtIndex:0]
|
||||
options:nil
|
||||
resultHandler:^(NSData *imageData, NSString *dataUTI,
|
||||
UIImageOrientation orientation,
|
||||
NSDictionary *info) {
|
||||
[self processSingleImagePick:[UIImage imageWithData:imageData] withViewController:imagePickerController];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,14 +449,13 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
return;
|
||||
}
|
||||
|
||||
self.resolve(@{
|
||||
@"path": filePath,
|
||||
@"width": @(image.size.width),
|
||||
@"height": @(image.size.height),
|
||||
@"mime": @"image/jpeg",
|
||||
@"size": [NSNumber numberWithUnsignedInteger:data.length],
|
||||
@"data": [[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null],
|
||||
});
|
||||
self.resolve([self createAttachmentResponse:filePath
|
||||
withWidth:@(image.size.width)
|
||||
withHeight:@(image.size.height)
|
||||
withMime:@"image/jpeg"
|
||||
withSize:[NSNumber numberWithUnsignedInteger:data.length]
|
||||
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null]]);
|
||||
|
||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
@ -352,14 +538,12 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
return;
|
||||
}
|
||||
|
||||
self.resolve(@{
|
||||
@"path": filePath,
|
||||
@"width": @(resizedImage.size.width),
|
||||
@"height": @(resizedImage.size.height),
|
||||
@"mime": @"image/jpeg",
|
||||
@"size": [NSNumber numberWithUnsignedInteger:data.length],
|
||||
@"data": [[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null],
|
||||
});
|
||||
self.resolve([self createAttachmentResponse:filePath
|
||||
withWidth:@(resizedImage.size.width)
|
||||
withHeight:@(resizedImage.size.height)
|
||||
withMime:@"image/jpeg"
|
||||
withSize:[NSNumber numberWithUnsignedInteger:data.length]
|
||||
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [data base64EncodedStringWithOptions:0] : [NSNull null]]);
|
||||
|
||||
[controller dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
@ -367,15 +551,8 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
|
||||
// at the moment it is not possible to upload image by reading PHAsset
|
||||
// we are saving image and saving it to the tmp location where we are allowed to access image later
|
||||
- (NSString*) persistFile:(NSData*)data {
|
||||
// create tmp directory
|
||||
NSString *tmpDirFullPath = [self getTmpDirectory];
|
||||
BOOL dirCreated = [[NSFileManager defaultManager] createDirectoryAtPath: tmpDirFullPath
|
||||
withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
if (!dirCreated) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// create temp file
|
||||
NSString *tmpDirFullPath = [self getTmpDirectory];
|
||||
NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]];
|
||||
filePath = [filePath stringByAppendingString:@".jpg"];
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-image-crop-picker",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"description": "Select single or multiple images, with croping option",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user