react-native-image-crop-picker
react-native-image-crop-picker copied to clipboard
Fairly Urgent: react-native-image-crop-picker Continually Loading after expo-image-picker
Version
Tell us which versions you are using:
- react-native-image-crop-picker v0.41.6
- react-native v0.76.3
Platform
Tell us to which platform this issue is related
- iOS
Expected behaviour
I attached two code blocks below. There is a very simple implementation that should shows the most simple situation where this is broken. Then, there is an implementation that contains a "Direct Crop" and a "Select and Crop" that uses the same URI. This proves the issue is not based on the URI. The expected behavior is that the library should finish loading.
Actual behaviour
The actual behavior is that the library continually loads.
Steps to reproduce
- Run the below files on iOS Expo and click the button.
Attachments
import React, { useState } from 'react';
import {
View,
Text,
Button,
StyleSheet,
ActivityIndicator,
Alert,
} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import ImageCropPicker from 'react-native-image-crop-picker';
export default function App() {
const [loading, setLoading] = useState(false);
const [selectedImage, setSelectedImage] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const handleSelectAndCropPhoto = async () => {
setLoading(true);
try {
// Request permissions
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Permission Required', 'Please grant access to your photo library.');
setLoading(false);
return;
}
// Open image picker
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
});
if (!result.canceled) {
const { uri } = result.assets[0];
console.log(`[App] Selected image URI: ${uri}`);
setSelectedImage(uri);
// Open cropper
const croppedResult = await ImageCropPicker.openCropper({
path: uri.replace('file://', ''), // Remove file:// prefix
width: 1000,
height: 1000,
cropping: true,
cropperCircleOverlay: false,
avoidEmptySpaceAroundImage: true,
compressImageQuality: 1,
forceJpg: true,
});
console.log(`[App] Cropped image path: ${croppedResult.path}`);
setCroppedImage(croppedResult.path);
} else {
console.log('[App] User canceled image picker.');
}
} catch (error) {
console.error('[App] Error during selection or cropping:', error);
Alert.alert('Error', 'Something went wrong while selecting or cropping the photo.');
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Image Picker & Cropper Test</Text>
<Button title="Select and Crop Photo" onPress={handleSelectAndCropPhoto} />
{loading && <ActivityIndicator size="large" color="#0000ff" style={styles.loader} />}
{selectedImage && <Text style={styles.info}>Selected Image: {selectedImage}</Text>}
{croppedImage && <Text style={styles.info}>Cropped Image: {croppedImage}</Text>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
info: {
marginTop: 20,
textAlign: 'center',
fontSize: 16,
},
loader: {
marginTop: 20,
},
});
import React, { useState } from 'react';
import {
View,
Text,
Button,
StyleSheet,
ActivityIndicator,
Alert,
Platform,
} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import ImageCropPicker from 'react-native-image-crop-picker';
export default function App() {
const [loading, setLoading] = useState(false);
const [selectedImage, setSelectedImage] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const handleSelectAndCropPhoto = async () => {
try {
setLoading(true);
// Request permissions
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Permission Required', 'Please grant access to your photo library.');
return;
}
// First use Expo ImagePicker for selection
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
quality: 1,
});
if (result.canceled) {
console.log('[App] User canceled image picker');
setLoading(false);
return;
}
const { uri } = result.assets[0];
console.log(`[App] Selected image URI: ${uri}`);
setSelectedImage(uri);
// Try with static path first for testing
const testPath = '/var/mobile/Containers/Data/Application/662861CC-0AB0-4074-89FD-E02D16ED27E2/Library/Caches/ImagePicker/C4867544-0BEA-41EC-804A-6256352D0643.png';
console.log('[App] Attempting to crop with path:', testPath);
// Then use react-native-image-crop-picker for cropping
const croppedResult = await ImageCropPicker.openCropper({
path: testPath,
width: 1000,
height: 1000,
cropping: true,
cropperCircleOverlay: false,
avoidEmptySpaceAroundImage: true,
compressImageQuality: 1,
forceJpg: true,
mediaType: 'photo',
}).catch(error => {
console.error('[App] Cropping error:', error);
throw error;
});
if (croppedResult) {
console.log(`[App] Cropped image path: ${croppedResult.path}`);
setCroppedImage(croppedResult.path);
}
} catch (error) {
console.error('[App] Error details:', error);
Alert.alert('Error', `Failed to process image: ${error.message}`);
} finally {
setLoading(false);
}
};
// Added a direct crop test function
const testDirectCrop = async () => {
try {
setLoading(true);
const staticPath = Platform.OS === 'ios'
? '/var/mobile/Containers/Data/Application/662861CC-0AB0-4074-89FD-E02D16ED27E2/Library/Caches/ImagePicker/C4867544-0BEA-41EC-804A-6256352D0643.png'
: '/storage/emulated/0/DCIM/Camera/test.jpg'; // Example Android path
console.log('[App] Testing direct crop with path:', staticPath);
const croppedResult = await ImageCropPicker.openCropper({
path: staticPath,
width: 1000,
height: 1000,
cropping: true,
cropperCircleOverlay: false,
avoidEmptySpaceAroundImage: true,
compressImageQuality: 1,
forceJpg: true,
mediaType: 'photo',
});
console.log('[App] Direct crop result:', croppedResult);
setCroppedImage(croppedResult.path);
} catch (error) {
console.error('[App] Direct crop error:', error);
Alert.alert('Error', `Direct crop failed: ${error.message}`);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Image Picker & Cropper Test</Text>
<Button
title="Select and Crop Photo"
onPress={handleSelectAndCropPhoto}
disabled={loading}
/>
<Button
title="Test Direct Crop"
onPress={testDirectCrop}
disabled={loading}
/>
{loading && <ActivityIndicator size="large" color="#0000ff" style={styles.loader} />}
{selectedImage && (
<Text style={styles.info}>
Selected Image: {selectedImage}
</Text>
)}
{croppedImage && (
<Text style={styles.info}>
Cropped Image: {croppedImage}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
info: {
marginTop: 20,
textAlign: 'center',
fontSize: 16,
},
loader: {
marginTop: 20,
},
});
// stacktrace or any other useful debug info
Love react-native-image-crop-picker? Please consider supporting our collective: 👉 https://opencollective.com/react-native-image-crop-picker/donate