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:
Prerequisites
- Introduction to React Native
- React Native Components
- React Native State
- React Native Props
- Expo CLI
- Node.js and npm (Node Package Manager)
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 zambiatek </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:
Whether you’re preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, zambiatek 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!



