How to add an image editor with cropping

Hi

I have a need to take an image, and then edit that image so that I can crop to the boundaries the users select. Basically I am taking a picture of a text, and I want to be able to crop so I can skip the images and get a cleaned cropped image with only the text I want to send to the server. Has anyone tried this with Expo?

Or do I need to create a new project where I can link any native code? I saw a cool one called react-native-perspective-cropper, but then I can not use Expo which I really like. I googled the crap out of the webb, but no meaningful answers. Anyone has tried anything similar?

Cheers

2 Likes

you can use ImagePicker.launchCameraAsync and pass in the allowsEditing: true option: https://docs.expo.io/versions/latest/sdk/imagepicker.html#expoimagepickerlaunchcameraasyncoptions

Yeah I tried that, but I could not set the boundaries of the result on iOS so the user can draw from side to side. Seem to be a limitation of the module it wraps, the iOS cropping always has a predefined square. I need the user to be able to crop to the desired size. Any ideas?

this is the built-in crop component that ships with uikit. you can make your own cropper UI and then actually adjust the image accordingly using https://docs.expo.io/versions/latest/sdk/imagemanipulator.html

Hi… I don’t know what I am doing wrong, but I guess it has to do with my lack not reading up on async await yet … I know I get the prop called uri but I get yellow box error when trying out the code below. I know it is not immediately related to my question above, but I am stuck for the last two hours from trying to implement the ImageManipulator.

If you have time, could you get some pointers on how to load the Image? I get no valuable feedback in my debugger, just a yellow-box error of an unhandled promise rejection. TypeError: Cannot read property ‘hash’ of undefined. Tried the forum and searching online :frowning:

import React from 'react';
import { Button, TouchableOpacity, Text, View, Image } from 'react-native';
import { Asset, ImageManipulator } from 'expo';

export default class ImageEditor extends React.Component {
  constructor(props){
    super(props);
    this.state ={
      ready: false,
      image: null,
      uri: null,
    }
  }

  componentWillMount() {
    const {uri} = this.props;
    console.log('got props', this.props);
    this.setState({
      image: uri,
      ready: true,
    });
  }


  _rotate90andFlip = async () => {
    const manipResult = await ImageManipulator.manipulate(
      this.state.image,
      [{ crop: { originX: 10, originY: 10, width:120, height:120}},],
      { format: 'jpeg' }
    );
    this.setState({ uri: manipResult });
  }


  render() {
    return (
      <View style={{ flex: 1 }}>
        <View style={{ padding: 10 }}>
          <Button onPress={this._rotate90andFlip} title="Rotate"/>
          {this.state.ready && this._renderImage()}
        </View>
      </View>
    );
  }

  _renderImage = () => {
    return (
      <View style={{marginVertical: 10, alignItems: 'center', justifyContent: 'center'}}>
        <Image
          source={{ uri: this.state.uri }}
          style={{ width: 300, height: 300, resizeMode: 'contain' }}
        />
      </View>
    );
  };
}

from imagemanipulator docs

Returns { uri, width, height } where uri is a URI to the modified image

so you’d need to do this.setState({ uri: manipResult.uri });

Hi

Ok finally got it working, but it doesn’t allow the user to crop to selected size. It only crops with the selected parameters of the crop object. I need a solution where the user can take an image, and then crop it to their selection. Any ideas?

I was almost thinking about creating a web-view, to use a lib like react-image-crop, but it would be nice to avoid adding a React web-page inside the app. I also don’t know how it will actually work on a mobile device.

Since I had so many problems using the ImageManipulator, Ill add my working code for pushing a uri via props which is missing in the code example (which for sure is broken too).

import React from 'react';
import { Button, TouchableOpacity, Text, View, Image } from 'react-native';
import { Asset, ImageManipulator } from 'expo';

export default class ImageEditor extends React.Component {
  constructor(props){
    super(props);
    this.state ={
      ready: false,
      image: null,
      uri: null,
    }
  }

  componentDidUpdate() {
    console.log('got props ', this.props);
  }


  componentWillMount() {
    let { uri } = this.props;
    uri = String(uri);
    this.setState({
      uri: uri,
      ready: true,
    });
  }


  _rotate90andFlip = async () => {
    const manipResult = await ImageManipulator.manipulate(
      this.state.uri,
      [{ crop: { originX: 10, originY: 10, width:300, height:300}},],
      { format: 'jpeg' }
    );
    this.setState({ uri: manipResult.uri });
  }


  render() {
    return (
      <View style={{ flex: 1 }}>
        <View style={{ padding: 10 }}>
          <Button onPress={this._rotate90andFlip} title="Rotate"/>
          {this._renderImage()}
        </View>
      </View>
    );
  }

  _renderImage = () => {
    if(this.state.uri == null) return <View><Text>No image URI</Text></View>
    return (
      <View style={{marginVertical: 10, alignItems: 'center', justifyContent: 'center'}}>
        <Image
          source={{ uri: this.state.uri }}
          style={{ width: 500, height: 500, resizeMode: 'contain' }}
        />
      </View>
    );
  };
}

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.