我正在开发一个基于图像处理的应用程序。我需要同时从选择器中选择多个图像并将它们显示在视图容器中,首先它会请求许可,然后从画廊或相机中选择图像。我还需要一个裁剪功能来裁剪图像。类似于图像选择的实用程序类支持应用程序所需的所有选项。我正在使用以下代码
class App extends Component {
state = {
image: Images.placeholderImage
}
onPress = () => {
// Here goes the picker code
}
render() {
return (
<View>
<View>
<Image source={this.state.image} style={{width:200, height:200}}/>
</View>
<TouchableOpacity onPress={this.onPress}>
<Text>Select Image</Text>
</TouchableOpacity>
</View>
)
}
}
答案 0 :(得分:2)
我为图像选择器制作了实用程序类,它支持多选择器和裁剪图像。请安装 react-native-image-crop-picker
和 react-native-permissions
存储库并在您的代码中创建以下类。
常量.js
import { PERMISSIONS } from "react-native-permissions";
import { Alert, Platform, Linking } from "react-native";
const PICKER_TYPE = {
// FOR CAMERA
CAMERA: "CAMERA",
CAMERA_WITH_CROPPING: "CAMERA_WITH_CROPPING",
CAMERA_BINARY_DATA: "CAMERA_BINARY_DATA",
CAMERA_WITH_CROPPING_BINARY_DATA: "CAMERA_WITH_CROPPING_BINARY_DATA",
// FOR GALLERY
GALLERY: "GALLERY",
GALLERY_WITH_CROPPING: "GALLERY_WITH_CROPPING",
GALLERY_BINARY_DATA: "GALLERY_BINARY_DATA",
GALLERY_WITH_CROPPING_BINARY_DATA: "GALLERY_WITH_CROPPING_BINARY_DATA",
// FOR MULTI PICK
MULTI_PICK: "MULTI_PICK",
MULTI_PICK_BINARY_DATA: "MULTI_PICK_BINARY_DATA",
};
const IMAGE_PICKER_OPTIONS = {
includeExif: false, // Include image details in the response
includeBase64: false, // (default false) | image as a base64-encoded string in the data property
mediaType: "photo", // default 'any' | ('photo', 'video', or 'any')
useFrontCamera: false, // (default false) 'front' or 'selfie' camera when opened
/* multiple selection */
multiple: false,
waitAnimationEnd: false, // (ios only) default true
forceJpg: true, // (ios only) default false
/* Should be use without cropping, just resizing after selection */
compressImageMaxWidth: 720,
compressImageMaxHeight: 720,
compressImageQuality: 0.5, // default 1 (Android) | 0.8 (iOS))
/* Should be used when cropping */
// Metrics.screenWidth
width: 720, // only work with cropping
height: 720, // only work with cropping
cropping: false,
cropperCircleOverlay: false, // Enable or disable circular cropping mask.
enableRotationGesture: false, // (android only) default false
freeStyleCropEnabled: true, // (android only) default false | Enable custom rectangle area for cropping
};
const CAMERA_PERMISSION =
Platform.OS === "android"
? PERMISSIONS.ANDROID.CAMERA
: PERMISSIONS.IOS.CAMERA;
const GALLERY_PERMISSION =
Platform.OS === "android"
? PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE
: PERMISSIONS.IOS.PHOTO_LIBRARY;
MediaPicker.js
import ImagePicker from "react-native-image-crop-picker";
import { RESULTS, check, request } from "react-native-permissions";
import { Alert, Linking } from "react-native";
import { PICKER_TYPE, IMAGE_PICKER_OPTIONS } from "../Constants";
class MediaPicker {
/**
*
* Show Picker
*
* @param {*} callback callback handle response
* @param {*} pickerTypeCamera
* @param {*} cameraOptions
* @param {*} pickerTypeGallery
* @param {*} galleryOptions
*/
showImagePicker(
callback,
pickerTypeGallery = PICKER_TYPE.GALLERY,
pickerTypeCamera = PICKER_TYPE.CAMERA,
galleryOptions = {},
cameraOptions = {}
) {
this.checkPermission(() => {
this.showPickerOptions(
callback,
pickerTypeCamera,
cameraOptions,
pickerTypeGallery,
galleryOptions
);
});
}
showPickerOptions(...args) {
Alert.alert("Select Image", null, [
{ text: "Camera", onPress: () => this.pickCameraOptions(...args) },
{ text: "Gallery", onPress: () => this.pickGalleryOptions(...args) },
{ text: "Cancel", onPress: () => console.log("Cancel") },
]);
}
pickCameraOptionsWithPermission(
callback,
pickerTypeGallery = PICKER_TYPE.GALLERY,
pickerTypeCamera = PICKER_TYPE.CAMERA,
galleryOptions = {},
cameraOptions = {}
) {
this.checkPermission(() => {
this.pickCameraOptions(
callback,
pickerTypeCamera,
cameraOptions,
pickerTypeGallery,
galleryOptions
);
});
}
pickCameraOptions(...args) {
let [
callback,
pickerTypeCamera,
cameraOptions,
pickerTypeGallery,
galleryOptions,
] = args;
//this.pickImageFromCameraWithCropping(callback, cameraOptions);
switch (pickerTypeCamera) {
case PICKER_TYPE.CAMERA:
case PICKER_TYPE.CAMERA_BINARY_DATA:
this.pickImageFromCamera(callback, cameraOptions);
break;
case PICKER_TYPE.CAMERA_WITH_CROPPING:
case PICKER_TYPE.CAMERA_WITH_CROPPING_BINARY_DATA:
this.pickImageFromCameraWithCropping(callback, cameraOptions);
break;
}
}
pickGalleryOptionsWithPermission(
callback,
pickerTypeGallery = PICKER_TYPE.GALLERY,
pickerTypeCamera = PICKER_TYPE.CAMERA,
galleryOptions = {},
cameraOptions = {}
) {
this.checkPermission(() => {
this.pickGalleryOptions(
callback,
pickerTypeCamera,
cameraOptions,
pickerTypeGallery,
galleryOptions
);
});
}
pickGalleryOptions(...args) {
let [
callback,
pickerTypeCamera,
cameraOptions,
pickerTypeGallery,
galleryOptions,
] = args;
switch (pickerTypeGallery) {
case PICKER_TYPE.GALLERY:
case PICKER_TYPE.GALLERY_BINARY_DATA:
this.pickImageFromGallery(callback, galleryOptions);
break;
case PICKER_TYPE.GALLERY_WITH_CROPPING:
case PICKER_TYPE.GALLERY_WITH_CROPPING_BINARY_DATA:
this.pickImageFromGalleryWithCropping(callback, galleryOptions);
break;
case PICKER_TYPE.MULTI_PICK:
case PICKER_TYPE.MULTI_PICK_BINARY_DATA:
this.pickMultiple(callback, galleryOptions);
break;
}
}
/**
* Pick image from camera
*
* @param {*} callback function which handle the response
* @param {*} options customize attributes
*
*/
pickImageFromCamera(callback, options = {}) {
options = { ...IMAGE_PICKER_OPTIONS, ...options };
// clean all images
//this.cleanupImages();
ImagePicker.openCamera({
compressImageMaxWidth: options.compressImageMaxWidth,
compressImageMaxHeight: options.compressImageMaxHeight,
compressImageQuality: options.compressImageQuality,
mediaType: options.mediaType,
includeExif: options.includeExif,
includeBase64: options.includeBase64,
})
.then((image) => {
let path = this.getImageUriFromData(options.includeBase64, image);
const imageData = { ...image, path };
//console.log("image Data", imageData);
callback && callback(imageData);
})
.catch((e) => this.handleError(e));
}
/**
* Pick image from camera with cropping functionality
*
* @param {*} callback function which handle the response
* @param {*} options customize attributes
*
*/
pickImageFromCameraWithCropping(callback, options = {}) {
options = { ...IMAGE_PICKER_OPTIONS, ...options };
// clean all images
//this.cleanupImages();
ImagePicker.openCamera({
width: options.width,
height: options.height,
cropping: true,
cropperCircleOverlay: options.cropperCircleOverlay,
enableRotationGesture: options.enableRotationGesture,
mediaType: options.mediaType,
includeExif: options.includeExif,
includeBase64: options.includeBase64,
})
.then((image) => {
let path = this.getImageUriFromData(options.includeBase64, image);
const imageData = { ...image, path };
//console.log("image Data", imageData);
callback && callback(imageData);
})
.catch((e) => this.handleError(e));
}
/**
* Pick image from gallery
*
* @param {*} callback function which handle the response
* @param {*} options customize attributes
*
*/
pickImageFromGallery(callback, options = {}) {
options = { ...IMAGE_PICKER_OPTIONS, ...options };
// clean all images
//this.cleanupImages();
ImagePicker.openPicker({
compressImageMaxWidth: options.compressImageMaxWidth,
compressImageMaxHeight: options.compressImageMaxHeight,
compressImageQuality: options.compressImageQuality,
mediaType: options.mediaType,
includeExif: options.includeExif,
includeBase64: options.includeBase64,
})
.then((image) => {
let path = this.getImageUriFromData(options.includeBase64, image);
const imageData = { ...image, path };
//console.log("image Data", imageData);
callback && callback(imageData);
})
.catch((e) => this.handleError(e));
}
/**
* Pick image from gallery with cropping functionality
*
* @param {*} callback function which handle the response
* @param {*} options customize attributes
*
*/
pickImageFromGalleryWithCropping(callback, options = {}) {
options = { ...IMAGE_PICKER_OPTIONS, ...options };
// clean all images
//this.cleanupImages();
ImagePicker.openPicker({
// width: options.width,
// height: options.height,
width: options.width,
height: options.height,
cropping: true,
cropperCircleOverlay: options.cropperCircleOverlay,
enableRotationGesture: options.enableRotationGesture,
mediaType: options.mediaType,
includeExif: options.includeExif,
includeBase64: options.includeBase64,
})
.then((image) => {
let path = this.getImageUriFromData(options.includeBase64, image);
const imageData = { ...image, path };
//console.log("image Data", imageData);
callback && callback(imageData);
})
.catch((e) => this.handleError(e));
}
/**
* Pick multiple images
*
* @param {*} callback function which handle the response
* @param {*} options customize attributes
*
*/
pickMultiple(callback, options = {}) {
options = { ...IMAGE_PICKER_OPTIONS, ...options };
// clean all images
//this.cleanupImages();
ImagePicker.openPicker({
multiple: true,
waitAnimationEnd: options.waitAnimationEnd,
forceJpg: options.forceJpg,
compressImageMaxWidth: options.compressImageMaxWidth,
compressImageMaxHeight: options.compressImageMaxHeight,
compressImageQuality: options.compressImageQuality,
mediaType: options.mediaType,
includeExif: options.includeExif,
includeBase64: options.includeBase64,
maxFiles: options.maxFiles || 10,
})
.then((images) => {
let imageData = images.map((img) => {
//console.log("img.path", img.path);
let uri =
img.path || this.getImageUriFromData(options.includeBase64, img);
return { ...img, uri };
});
//console.log("image Data", JSON.stringify(imageData));
callback && callback(imageData);
})
.catch((e) => this.handleError(e));
}
/**
* Clean temp Images
*/
cleanupImages() {
ImagePicker.clean()
.then(() => {
//console.log("removed tmp images from tmp directory");
})
.catch((e) => this.handleError(e));
}
/**
*
* Clean single temp image
*
* @param {*} image path to be clean
*/
cleanupSingleImage(image) {
console.log("will cleanup image", image);
ImagePicker.cleanSingle(image ? image.uri : null)
.then(() => {
//console.log(`removed tmp image ${image.uri} from tmp directory`);
})
.catch((e) => this.handleError(e));
}
/**
*
* Get image path from response data
*
* @param {*} includeBase64
* @param {*} image
*/
getImageUriFromData(includeBase64, image) {
//console.log("includeBase64", includeBase64);
return includeBase64
? `data:${image.mime};base64,` + image.data
: image.path;
}
handleError(error) {
if (error.code && error.code === "E_PICKER_CANCELLED") return;
let errorMsg = error.message ? error.message : error;
Alert.alert("Error", errorMsg);
}
openSettingModal() {
Alert.alert(
"Permission required",
"Need permissions to access gallery and camera",
[
{ text: "Cancel", style: "cancel" },
{ text: "Open Settings", onPress: () => Linking.openSettings() },
],
{ cancelable: false }
);
}
handlePermissions(triggerFunc) {
request(CAMERA_PERMISSION)
.then((cameraPermission) => {
return cameraPermission;
})
.then((cameraPermission) => {
request(GALLERY_PERMISSION).then((photoPermission) => {
if (
cameraPermission === RESULTS.GRANTED &&
photoPermission === RESULTS.GRANTED
) {
triggerFunc();
}
});
});
}
checkPermission(triggerFunc, openSettings = undefined) {
// let permissionAsk = Platform.OS === 'ios' ? 'denied' : 'restricted';
Promise.all([
check(CAMERA_PERMISSION),
check(GALLERY_PERMISSION),
// …
]).then(([cameraStatus, photoStatus]) => {
if (cameraStatus === RESULTS.BLOCKED || photoStatus === RESULTS.BLOCKED) {
this.openSettingModal();
} else {
this.handlePermissions(triggerFunc);
}
});
}
}
export default new MediaPicker();
用法:
import { MediaPicker } from "../";
MediaPicker.showImagePicker((image) => {
// image.path ==>> file path
});