Thursday, September 4, 2025
HomeLanguagesCreate an Image Crop Tool using React-Native

Create an Image Crop Tool using React-Native

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 neveropen
            </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

Whether you’re preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, neveropen Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we’ve already empowered, and we’re here to do the same for you. Don’t miss out – check it out now!
RELATED ARTICLES

Most Popular

Dominic
32264 POSTS0 COMMENTS
Milvus
81 POSTS0 COMMENTS
Nango Kala
6629 POSTS0 COMMENTS
Nicole Veronica
11799 POSTS0 COMMENTS
Nokonwaba Nkukhwana
11858 POSTS0 COMMENTS
Shaida Kate Naidoo
6749 POSTS0 COMMENTS
Ted Musemwa
7025 POSTS0 COMMENTS
Thapelo Manthata
6698 POSTS0 COMMENTS
Umr Jansen
6716 POSTS0 COMMENTS