React native 使用多选择器和权限处理响应本机图像裁剪

React native 使用多选择器和权限处理响应本机图像裁剪,react-native,React Native,我正在开发一个基于图像处理的应用程序。我需要同时从选择器中选择多个图像,并在视图容器中显示它们,在视图容器中,它将首先请求许可,然后从库或相机中拾取图像。我还需要在它的裁剪功能,以裁剪图像。类似于图像选择的实用程序类支持应用程序所需的所有选项。我正在使用以下代码 class App extends Component { state = { image: Images.placeholderImage } onPress = () => { // Here

我正在开发一个基于图像处理的应用程序。我需要同时从选择器中选择多个图像,并在视图容器中显示它们,在视图容器中,它将首先请求许可,然后从库或相机中拾取图像。我还需要在它的裁剪功能,以裁剪图像。类似于图像选择的实用程序类支持应用程序所需的所有选项。我正在使用以下代码

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>
    )
  }
}
类应用程序扩展组件{
状态={
image:Images.placeholder图像
}
onPress=()=>{
//这里是选择器代码
}
render(){
返回(
选择图像
)
}
}

我为图像选择器创建了实用类,它支持多选择器和裁剪图像。请安装
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 
});