Open In App

Create an Image Crop Tool using React-Native

Last Updated : 12 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In this tutorial, we are going to build an Image crop tool using React-Native. The Image Crop tool is a very important tool for cropping the Images. It will allow the users to pick an image from storage, crop it, and later save it locally.

Preview Image:Screenshot-2023-09-22-204909

Prerequisites

Project Setup

Step 1: Create the project

npx create-expo-app image_crop

Step 2: Navigate to the project

cd image_crop

Step 3: Install the required packages.

npx expo install expo-file-system expo-image-picker
  • expo-file-system: For saving the file.
  • expo-image-picker: For picking and cropping the image.

Project Structure:

package.json for dependencies and respective versions.

{
"name": "image_crop",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"expo": "~49.0.11",
"expo-file-system": "~15.4.4",
"expo-image-picker": "~14.3.2",
"expo-status-bar": "~1.6.0",
"react": "18.2.0",
"react-native": "0.72.4"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}

Approach

  • The application will have three buttons, pick image, reset image, and save image.
  • On clicking the Pick Image button, Image Picker opens. We need to select an image.
  • After that crop window opens where we need to crop it.
  • After cropping, the image is displayed.
  • If satisfied, press the save button.
  • When completed, we can reset the app.

Example: This example shows the creation of the image crop tool using React-Native.

Javascript




// App.js file
  
import {
    Button,
    StyleSheet,
    Text,
    View,
    Image,
    TextInput,
} from "react-native";
import * as ImagePicker from "expo-image-picker";
import * as FileSystem from "expo-file-system";
import { useRef, useState } from "react";
export default function App() {
    const [fileUri, setFileUri] = useState("");
    const [fileType, setFileType] = useState("");
    const [heightAspect, setHeightAspect] = useState("3");
    const [widthAspect, setWidthAspect] = useState("4");
    const handlePickFile = async () => {
        if (heightAspect == "0" || widthAspect == "0") {
            const res =
                await ImagePicker.launchImageLibraryAsync({
                    mediaTypes:
                        ImagePicker.MediaTypeOptions.Images,
                    quality: 1,
                    allowsEditing: true,
                    allowsMultipleSelection: false,
                });
            if (res.canceled) return;
  
            setFileUri(res.assets[0].uri);
            setFileType(res.assets[0].type);
        } else {
            const res =
                await ImagePicker.launchImageLibraryAsync({
                    mediaTypes:
                        ImagePicker.MediaTypeOptions.Images,
                    quality: 1,
                    aspect: [
                        parseInt(widthAspect),
                        parseInt(heightAspect),
                    ],
                    allowsEditing: true,
                    allowsMultipleSelection: false,
                });
            if (res.canceled) return;
  
            setFileUri(res.assets[0].uri);
            setFileType(res.assets[0].type);
        }
    };
  
    const saveFile = async (uri, mimetype) => {
        let fileName = Date.now() + ".jpg";
        const permissions =
            await 
                FileSystem.StorageAccessFramework
                    .requestDirectoryPermissionsAsync();
        if (permissions.granted) {
            const base64 =
                await FileSystem.readAsStringAsync(uri, {
                    encoding:
                        FileSystem.EncodingType.Base64,
                });
            await FileSystem.StorageAccessFramework.createFileAsync(
                permissions.directoryUri,
                fileName,
                mimetype
            )
                .then(async (uri) => {
                    await FileSystem.writeAsStringAsync(
                        uri,
                        base64,
                        {
                            encoding:
                                FileSystem.EncodingType
                                    .Base64,
                        }
                    );
                })
                .catch((e) => console.log(e));
        } else {
            alert("Permission not granted");
        }
    };
    return (
        <View style={styles.container}>
            <Text style={styles.heading1}>
                Image Crop GeeksforGeeks
            </Text>
            {fileUri.length != 0 ? (
                <Image
                    source={{ uri: fileUri }}
                    style={{
                        width: 400,
                        height: 400,
                        objectFit: "contain",
                    }}
                />
            ) : (
                <View></View>
            )}
            <View
                style={{
                    flexDirection: "column",
                    alignItems: "center",
                }}>
                  
                <Text
                    style={{ fontSize: 24, color: "red" }}>
                    Aspect ratio
                </Text>
                <Text>
                    Set values 0 for any for free aspect
                    ratio. Default is 4:3
                </Text>
                <View
                    style={{
                        display: "flex",
                        flexDirection: "row",
                        alignContent: "center",
                    }}>
                      
                    <Text style={styles.inputLabel}>
                        Width:{" "}
                    </Text>
                    <TextInput
                        onChangeText={setWidthAspect}
                        value={widthAspect}
                        inputMode="numeric"
                        keyboardType="numeric"
                        style={styles.input}
                        maxLength={2}/>
                          
                </View>
                <View
                    style={{
                        display: "flex",
                        flexDirection: "row",
                        alignContent: "center",
                    }}>
                      
                    <Text style={styles.inputLabel}>
                        Height:{" "}
                    </Text>
                    <TextInput
                        onChangeText={setHeightAspect}
                        value={heightAspect}
                        inputMode="numeric"
                        keyboardType="numeric"
                        style={styles.input}
                        maxLength={2}/>
                </View>
            </View>
            <View
                style={{
                    display: "flex",
                    flexDirection: "row",
                    justifyContent: "space-evenly",
                    width: "100%",
                    padding: 10,
                }}>
                  
                <Button
                    title="Pick Image"
                    onPress={handlePickFile}/>
                      
                {fileUri.length != 0 ? (
                    <>
                        <Button
                            title="Save Image"
                            onPress={() =>
                                saveFile(fileUri, fileType)
                            }
                        />
                        <Button
                            title="reset"
                            onPress={() => setFileUri("")}
                        />
                    </>
                ) : (
                    <></>
                )}
            </View>
        </View>
    );
}
  
const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: "#fff",
        alignItems: "center",
        justifyContent: "space-evenly",
        height: "100%",
    },
    heading1: {
        fontSize: 28,
        fontWeight: "bold",
        color: "green",
        textAlign: "center",
    },
    input: {
        width: 50,
        height: 30,
        borderColor: "gray",
        borderWidth: 1,
        textAlign: "center",
        borderRadius: 5,
        padding: 5,
        margin: 5,
    },
    inputLabel: {
        fontSize: 20,
        margin: 5,
        padding: 5,
    },
});


Step 4: Run the application

npx expo start

To run on Android:

npx react-native run-android

To run on iOS:

npx react-native run-ios

Output:

screenrec_18



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads