react-native-expo-cropper 1.0.30 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CustomCamera.js +3 -1
- package/dist/ImageProcessor.js +11 -6
- package/package.json +2 -2
- package/src/CustomCamera.js +232 -224
- package/src/ImageProcessor.js +13 -3
package/dist/CustomCamera.js
CHANGED
|
@@ -88,7 +88,9 @@ function CustomCamera(_ref) {
|
|
|
88
88
|
case 0:
|
|
89
89
|
_context2.p = 0;
|
|
90
90
|
_context2.n = 1;
|
|
91
|
-
return ImageManipulator.manipulateAsync(uri, [],
|
|
91
|
+
return ImageManipulator.manipulateAsync(uri, [],
|
|
92
|
+
// Empty array = apply EXIF orientation automatically
|
|
93
|
+
{
|
|
92
94
|
compress: 1,
|
|
93
95
|
format: ImageManipulator.SaveFormat.PNG
|
|
94
96
|
});
|
package/dist/ImageProcessor.js
CHANGED
|
@@ -13,21 +13,26 @@ function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.
|
|
|
13
13
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
14
14
|
var enhanceImage = exports.enhanceImage = /*#__PURE__*/function () {
|
|
15
15
|
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(uri, addheight) {
|
|
16
|
-
var
|
|
16
|
+
var fixedOrientationImage, ratio, maxHeight, newWidth, newHeight, result, _t;
|
|
17
17
|
return _regenerator().w(function (_context) {
|
|
18
18
|
while (1) switch (_context.p = _context.n) {
|
|
19
19
|
case 0:
|
|
20
20
|
_context.p = 0;
|
|
21
21
|
_context.n = 1;
|
|
22
|
-
return ImageManipulator.manipulateAsync(uri, []
|
|
22
|
+
return ImageManipulator.manipulateAsync(uri, [], {
|
|
23
|
+
compress: 1,
|
|
24
|
+
format: ImageManipulator.SaveFormat.PNG
|
|
25
|
+
});
|
|
23
26
|
case 1:
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
fixedOrientationImage = _context.v;
|
|
28
|
+
// Get the correct dimensions after orientation fix
|
|
29
|
+
// The width and height properties reflect the actual image dimensions after orientation fix
|
|
30
|
+
ratio = fixedOrientationImage.height / fixedOrientationImage.width;
|
|
26
31
|
maxHeight = addheight;
|
|
27
32
|
newWidth = Math.round(maxHeight / ratio);
|
|
28
|
-
newHeight = Math.round(newWidth * ratio);
|
|
33
|
+
newHeight = Math.round(newWidth * ratio); // Resize using the orientation-fixed image
|
|
29
34
|
_context.n = 2;
|
|
30
|
-
return ImageManipulator.manipulateAsync(uri, [{
|
|
35
|
+
return ImageManipulator.manipulateAsync(fixedOrientationImage.uri, [{
|
|
31
36
|
resize: {
|
|
32
37
|
width: newWidth,
|
|
33
38
|
height: newHeight
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-expo-cropper",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "Recadrage polygonal d'images.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "PCS AGRI",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"homepage": "https://github.com/pcsagri/react-native-expo-cropper#readme",
|
|
44
44
|
"scripts": {
|
|
45
45
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
46
|
-
"build": "babel src --out-dir dist"
|
|
46
|
+
"build": "npx babel src --out-dir dist"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@babel/cli": "^7.28.3",
|
package/src/CustomCamera.js
CHANGED
|
@@ -1,224 +1,232 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
Text,
|
|
5
|
-
View,
|
|
6
|
-
TouchableOpacity,
|
|
7
|
-
Alert,
|
|
8
|
-
SafeAreaView,
|
|
9
|
-
Dimensions,
|
|
10
|
-
Image,
|
|
11
|
-
} from 'react-native';
|
|
12
|
-
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
13
|
-
import { Camera, CameraView } from 'expo-camera';
|
|
14
|
-
import * as ImageManipulator from 'expo-image-manipulator';
|
|
15
|
-
const { width } = Dimensions.get('window');
|
|
16
|
-
|
|
17
|
-
export default function CustomCamera({ onPhotoCaptured}) {
|
|
18
|
-
const [isReady, setIsReady] = useState(false);
|
|
19
|
-
const [loadingBeforeCapture, setLoadingBeforeCapture] = useState(false);
|
|
20
|
-
const [setHasPermission] = useState(null);
|
|
21
|
-
const cameraRef = useRef(null);
|
|
22
|
-
const insets = useSafeAreaInsets();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
(async () => {
|
|
28
|
-
const { status } = await Camera.requestCameraPermissionsAsync();
|
|
29
|
-
setHasPermission(status === 'granted');
|
|
30
|
-
})();
|
|
31
|
-
}, []);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Helper function to wait for multiple render cycles (works on iOS)
|
|
36
|
-
const waitForRender = (cycles = 5) => {
|
|
37
|
-
return new Promise((resolve) => {
|
|
38
|
-
let count = 0;
|
|
39
|
-
const tick = () => {
|
|
40
|
-
count++;
|
|
41
|
-
if (count >= cycles) {
|
|
42
|
-
resolve();
|
|
43
|
-
} else {
|
|
44
|
-
setImmediate(tick);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
setImmediate(tick);
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Helper function to fix image orientation (removes EXIF orientation)
|
|
52
|
-
const fixImageOrientation = async (uri) => {
|
|
53
|
-
try {
|
|
54
|
-
// Use manipulateAsync with empty array to fix orientation based on EXIF data
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
/>
|
|
130
|
-
</View>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
position: 'absolute',
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
1
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
Text,
|
|
5
|
+
View,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
Alert,
|
|
8
|
+
SafeAreaView,
|
|
9
|
+
Dimensions,
|
|
10
|
+
Image,
|
|
11
|
+
} from 'react-native';
|
|
12
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
13
|
+
import { Camera, CameraView } from 'expo-camera';
|
|
14
|
+
import * as ImageManipulator from 'expo-image-manipulator';
|
|
15
|
+
const { width } = Dimensions.get('window');
|
|
16
|
+
|
|
17
|
+
export default function CustomCamera({ onPhotoCaptured}) {
|
|
18
|
+
const [isReady, setIsReady] = useState(false);
|
|
19
|
+
const [loadingBeforeCapture, setLoadingBeforeCapture] = useState(false);
|
|
20
|
+
const [setHasPermission] = useState(null);
|
|
21
|
+
const cameraRef = useRef(null);
|
|
22
|
+
const insets = useSafeAreaInsets();
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
(async () => {
|
|
28
|
+
const { status } = await Camera.requestCameraPermissionsAsync();
|
|
29
|
+
setHasPermission(status === 'granted');
|
|
30
|
+
})();
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// Helper function to wait for multiple render cycles (works on iOS)
|
|
36
|
+
const waitForRender = (cycles = 5) => {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
let count = 0;
|
|
39
|
+
const tick = () => {
|
|
40
|
+
count++;
|
|
41
|
+
if (count >= cycles) {
|
|
42
|
+
resolve();
|
|
43
|
+
} else {
|
|
44
|
+
setImmediate(tick);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
setImmediate(tick);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Helper function to fix image orientation (removes EXIF orientation)
|
|
52
|
+
const fixImageOrientation = async (uri) => {
|
|
53
|
+
try {
|
|
54
|
+
// Use manipulateAsync with empty array to fix orientation based on EXIF data
|
|
55
|
+
// Empty array [] tells manipulateAsync to automatically apply EXIF orientation
|
|
56
|
+
// This ensures horizontal photos stay horizontal and vertical photos stay vertical
|
|
57
|
+
// The EXIF orientation tag is removed and the image is physically rotated if needed
|
|
58
|
+
const fixedImage = await ImageManipulator.manipulateAsync(
|
|
59
|
+
uri,
|
|
60
|
+
[], // Empty array = apply EXIF orientation automatically
|
|
61
|
+
{
|
|
62
|
+
compress: 1,
|
|
63
|
+
format: ImageManipulator.SaveFormat.PNG
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return fixedImage.uri;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("Error fixing image orientation:", error);
|
|
70
|
+
return uri; // Return original if fixing fails
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const takePicture = async () => {
|
|
75
|
+
if (cameraRef.current) {
|
|
76
|
+
try {
|
|
77
|
+
// Show loading after a delay (using setImmediate for iOS compatibility)
|
|
78
|
+
waitForRender(20).then(() => {
|
|
79
|
+
setLoadingBeforeCapture(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Wait a bit before taking picture (works on iOS)
|
|
83
|
+
await waitForRender(3);
|
|
84
|
+
|
|
85
|
+
const photo = await cameraRef.current.takePictureAsync({
|
|
86
|
+
quality: 1,
|
|
87
|
+
shutterSound: false,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Fix orientation to preserve vertical/horizontal position as taken
|
|
91
|
+
const fixedUri = await fixImageOrientation(photo.uri);
|
|
92
|
+
|
|
93
|
+
onPhotoCaptured(fixedUri);
|
|
94
|
+
|
|
95
|
+
setLoadingBeforeCapture(false);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
setLoadingBeforeCapture(false);
|
|
98
|
+
Alert.alert("Erreur");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<SafeAreaView style={styles.outerContainer}>
|
|
106
|
+
<View style={styles.cameraWrapper}>
|
|
107
|
+
<CameraView
|
|
108
|
+
style={styles.camera}
|
|
109
|
+
facing="back"
|
|
110
|
+
ref={cameraRef}
|
|
111
|
+
onCameraReady={() => setIsReady(true)}
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
{/* Loading overlay */}
|
|
115
|
+
{loadingBeforeCapture && (
|
|
116
|
+
<>
|
|
117
|
+
<View style={styles.loadingOverlay}>
|
|
118
|
+
<Image
|
|
119
|
+
source={require('../src/assets/loadingCamera.gif')}
|
|
120
|
+
style={styles.loadingGif}
|
|
121
|
+
resizeMode="contain"
|
|
122
|
+
/>
|
|
123
|
+
</View>
|
|
124
|
+
<View style={styles.touchBlocker} pointerEvents="auto" />
|
|
125
|
+
</>
|
|
126
|
+
)}
|
|
127
|
+
|
|
128
|
+
{/* Cadre de scan */}
|
|
129
|
+
<View style={styles.scanFrame} />
|
|
130
|
+
</View>
|
|
131
|
+
|
|
132
|
+
<View style={[styles.buttonContainer, { bottom: (insets?.bottom || 0) + 16, marginBottom: 0 }]}>
|
|
133
|
+
<TouchableOpacity
|
|
134
|
+
style={styles.button}
|
|
135
|
+
onPress={takePicture}
|
|
136
|
+
disabled={!isReady || loadingBeforeCapture}
|
|
137
|
+
/>
|
|
138
|
+
</View>
|
|
139
|
+
</SafeAreaView>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const PRIMARY_GREEN = '#198754';
|
|
144
|
+
const DEEP_BLACK = '#0B0B0B';
|
|
145
|
+
const GLOW_WHITE = 'rgba(255, 255, 255, 0.85)';
|
|
146
|
+
|
|
147
|
+
const styles = StyleSheet.create({
|
|
148
|
+
outerContainer: {
|
|
149
|
+
flex: 1,
|
|
150
|
+
backgroundColor: DEEP_BLACK,
|
|
151
|
+
justifyContent: 'center',
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
},
|
|
154
|
+
cameraWrapper: {
|
|
155
|
+
width: width,
|
|
156
|
+
aspectRatio: 9 / 16,
|
|
157
|
+
borderRadius: 30,
|
|
158
|
+
overflow: 'hidden',
|
|
159
|
+
alignItems: 'center',
|
|
160
|
+
justifyContent: 'center',
|
|
161
|
+
position: 'relative',
|
|
162
|
+
},
|
|
163
|
+
camera: {
|
|
164
|
+
...StyleSheet.absoluteFillObject,
|
|
165
|
+
},
|
|
166
|
+
scanFrame: {
|
|
167
|
+
position: 'absolute',
|
|
168
|
+
width: '95%',
|
|
169
|
+
height: '80%',
|
|
170
|
+
borderWidth: 4,
|
|
171
|
+
borderColor: PRIMARY_GREEN,
|
|
172
|
+
borderRadius: 5,
|
|
173
|
+
backgroundColor: 'rgba(0, 0, 0, 0.1)',
|
|
174
|
+
},
|
|
175
|
+
loadingOverlay: {
|
|
176
|
+
...StyleSheet.absoluteFillObject,
|
|
177
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
178
|
+
zIndex: 20,
|
|
179
|
+
justifyContent: 'center',
|
|
180
|
+
alignItems: 'center',
|
|
181
|
+
},
|
|
182
|
+
loadingGif: {
|
|
183
|
+
width: 100,
|
|
184
|
+
height: 100,
|
|
185
|
+
},
|
|
186
|
+
touchBlocker: {
|
|
187
|
+
...StyleSheet.absoluteFillObject,
|
|
188
|
+
zIndex: 21,
|
|
189
|
+
backgroundColor: 'transparent',
|
|
190
|
+
},
|
|
191
|
+
cancelIcon: {
|
|
192
|
+
position: 'absolute',
|
|
193
|
+
top: 20,
|
|
194
|
+
left: 20,
|
|
195
|
+
backgroundColor: PRIMARY_GREEN,
|
|
196
|
+
borderRadius: 5,
|
|
197
|
+
padding: 8,
|
|
198
|
+
},
|
|
199
|
+
buttonContainer: {
|
|
200
|
+
position: 'absolute',
|
|
201
|
+
bottom: 0,
|
|
202
|
+
marginBottom: 20,
|
|
203
|
+
flexDirection: 'row',
|
|
204
|
+
justifyContent: 'center',
|
|
205
|
+
},
|
|
206
|
+
button: {
|
|
207
|
+
width: 80,
|
|
208
|
+
height: 80,
|
|
209
|
+
borderRadius: 50,
|
|
210
|
+
backgroundColor: GLOW_WHITE,
|
|
211
|
+
borderWidth: 5,
|
|
212
|
+
borderColor: PRIMARY_GREEN,
|
|
213
|
+
alignItems: 'center',
|
|
214
|
+
justifyContent: 'center',
|
|
215
|
+
},
|
|
216
|
+
text: {
|
|
217
|
+
fontSize: 18,
|
|
218
|
+
color: GLOW_WHITE,
|
|
219
|
+
},
|
|
220
|
+
container: {
|
|
221
|
+
flex: 1,
|
|
222
|
+
backgroundColor: DEEP_BLACK,
|
|
223
|
+
justifyContent: 'center',
|
|
224
|
+
alignItems: 'center',
|
|
225
|
+
padding: 20,
|
|
226
|
+
},
|
|
227
|
+
iconText: {
|
|
228
|
+
fontSize: 18,
|
|
229
|
+
color: GLOW_WHITE,
|
|
230
|
+
fontWeight: '600',
|
|
231
|
+
},
|
|
232
|
+
});
|
package/src/ImageProcessor.js
CHANGED
|
@@ -2,15 +2,25 @@ import * as ImageManipulator from 'expo-image-manipulator';
|
|
|
2
2
|
|
|
3
3
|
export const enhanceImage = async (uri , addheight) => {
|
|
4
4
|
try {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// First, fix orientation by applying EXIF orientation data
|
|
6
|
+
// Empty array [] tells manipulateAsync to automatically apply EXIF orientation
|
|
7
|
+
// This ensures the image is correctly oriented and EXIF tag is removed
|
|
8
|
+
const fixedOrientationImage = await ImageManipulator.manipulateAsync(uri, [], {
|
|
9
|
+
compress: 1,
|
|
10
|
+
format: ImageManipulator.SaveFormat.PNG
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Get the correct dimensions after orientation fix
|
|
14
|
+
// The width and height properties reflect the actual image dimensions after orientation fix
|
|
15
|
+
const ratio = fixedOrientationImage.height / fixedOrientationImage.width;
|
|
7
16
|
|
|
8
17
|
const maxHeight = addheight;
|
|
9
18
|
const newWidth = Math.round(maxHeight / ratio);
|
|
10
19
|
const newHeight = Math.round(newWidth * ratio);
|
|
11
20
|
|
|
21
|
+
// Resize using the orientation-fixed image
|
|
12
22
|
const result = await ImageManipulator.manipulateAsync(
|
|
13
|
-
uri,
|
|
23
|
+
fixedOrientationImage.uri,
|
|
14
24
|
[
|
|
15
25
|
{ resize: { width: newWidth, height: newHeight } },
|
|
16
26
|
],
|