below is the code that keeps crashing the app when it is ran
ImageManipulator.manipulateAsync(
flippedImageUri,
[
{
crop: {
originX: swappedFaceX,
originY: swappedFaceY,
width: swappedFaceWidth,
height: swappedFaceHeight,
},
},
],
{ format: 'png' }
);
and below is the code that swaps
import { Dimensions, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import React, { useCallback, useEffect, useRef } from 'react'
import { Camera } from "expo-camera";
import * as FaceDetector from 'expo-face-detector';
import * as ImageManipulator from 'expo-image-manipulator';
import useFaceContext from '../context/FaceProvider';
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
const CameraComponent = () => {
const cameraRef = useRef(null);
const {image, setFaces, faces, setSwappedImage, swappedImage} = useFaceContext();
useEffect(() => {
(async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
if (status !== "granted") {
alert("Camera permission not granted");
}
})();
}, []);
const handleFacesDetected = useCallback(({ faces }) => {
setFaces(faces);
}, []);
const swapFaces = async () => {
if (faces.length === 0) {
alert('No face detected');
return;
}
if (image === null) {
alert('No image selected');
return;
}
const [faceLandmarks] = faces;
try {
const manipResult = await ImageManipulator.manipulateAsync(
image,
[{ flip: ImageManipulator.FlipType.Horizontal }],
{ format: 'png' }
);
const { uri: flippedImageUri } = manipResult;
const { width: imageWidth, height: imageHeight } = manipResult;
const leftEye = faceLandmarks["LEFT_EYE"];
const rightEye = faceLandmarks["RIGHT_EYE"];
const nose = faceLandmarks["NOSE_BASE"];
const mouth = faceLandmarks["LEFT_MOUTH"];
if (!leftEye || !rightEye || !nose || !mouth) {
alert('Cannot detect facial features');
return;
}
const offsetX = 0.25; // Adjust the offset values to fit your face swapping needs
const offsetY = 0.15;
const leftEyeX = leftEye.x * imageWidth;
const leftEyeY = leftEye.y * imageHeight;
const rightEyeX = rightEye.x * imageWidth;
const rightEyeY = rightEye.y * imageHeight;
const noseX = nose.x * imageWidth;
const noseY = nose.y * imageHeight;
const mouthX = mouth.x * imageWidth;
const mouthY = mouth.y * imageHeight;
const swappedFaceWidth = Math.abs(rightEyeX - leftEyeX);
const swappedFaceHeight = Math.abs(mouthY - noseY);
const swappedFaceX = leftEyeX - offsetX * swappedFaceWidth;
const swappedFaceY = noseY - offsetY * swappedFaceHeight;
const result = await ImageManipulator.manipulateAsync(
flippedImageUri,
[
{
crop: {
originX: swappedFaceX,
originY: swappedFaceY,
width: swappedFaceWidth,
height: swappedFaceHeight,
},
},
],
{ format: 'png' }
);
setSwappedImage(result.uri);
} catch (error) {
console.error(error);
alert('Error occurred during face swapping');
}
};
return <View style={styles.container}>
<Camera style={styles.camera} type={Camera.Constants.Type.front} ref={cameraRef} onFacesDetected={handleFacesDetected} faceDetectorSettings={{ mode: FaceDetector.FaceDetectorMode.accurate, detectLandmarks: FaceDetector.FaceDetectorLandmarks.all, runClassifications: FaceDetector.FaceDetectorClassifications.all }}>
{/* Render any additional UI components or overlays if needed */}
{faces.map((face, index) =>
<View
key={index}
style={[
styles.faceOutline,
{
top: face.bounds.origin.y,
left: face.bounds.origin.x,
width: face.bounds.size.width,
height: face.bounds.size.height
}
]}
/>
)}
</Camera>
<View style={{
flexDirection: "row",
alignItems: "center",
gap: 20
}}>
{image && <Image source={{ uri: image }} style={styles.image} />}
{swappedImage && <Image source={{ uri: swappedImage }} style={styles.image} />}
</View>
<TouchableOpacity style={styles.button} onPress={swapFaces}>
<Text style={styles.buttonText}>Swap Faces</Text>
</TouchableOpacity>
</View>;
}
export default CameraComponent
const styles = StyleSheet.create({
container: {
width: windowWidth,
height: windowHeight,
justifyContent: 'center',
alignItems: 'center',
},
camera: {
flex: 1,
width: "100%",
height: "50%",
},
faceOutline: {
position: 'absolute',
borderWidth: 2,
borderColor: 'red',
borderRadius: 5,
opacity: 0.7,
},
image: {
width: 100,
height: 100,
resizeMode: 'contain',
marginVertical: 10,
},
button: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'black',
borderRadius: 5,
padding: 10,
marginVertical: 10,
},
buttonText: {
color: 'white',
fontSize: 16,
marginLeft: 5,
},
buttonIcon: {
width: 20,
height: 20,
tintColor: 'white',
},
});
this is an expo managed workflow