react-native-expo-cropper 1.2.38 → 1.2.40
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 +107 -113
- package/dist/ImageCropper.js +132 -214
- package/dist/ImageCropperStyles.js +31 -5
- package/package.json +7 -6
- package/src/CustomCamera.js +130 -104
- package/src/ImageCropper.js +142 -221
- package/src/ImageCropperStyles.js +27 -4
package/dist/CustomCamera.js
CHANGED
|
@@ -8,7 +8,7 @@ exports["default"] = CustomCamera;
|
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
9
|
var _reactNative = require("react-native");
|
|
10
10
|
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
|
|
11
|
-
var
|
|
11
|
+
var _reactNativeVisionCamera = require("react-native-vision-camera");
|
|
12
12
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t2 in e) "default" !== _t2 && {}.hasOwnProperty.call(e, _t2) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t2)) && (i.get || i.set) ? o(f, _t2, i) : f[_t2] = e[_t2]); return f; })(e, t); }
|
|
13
13
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
14
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -38,44 +38,31 @@ function CustomCamera(_ref) {
|
|
|
38
38
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
39
39
|
loadingBeforeCapture = _useState4[0],
|
|
40
40
|
setLoadingBeforeCapture = _useState4[1];
|
|
41
|
-
var _useState5 = (0, _react.useState)(null),
|
|
42
|
-
_useState6 = _slicedToArray(_useState5, 2),
|
|
43
|
-
hasPermission = _useState6[0],
|
|
44
|
-
setHasPermission = _useState6[1];
|
|
45
41
|
var cameraRef = (0, _react.useRef)(null);
|
|
46
42
|
var cameraWrapperRef = (0, _react.useRef)(null);
|
|
47
43
|
var insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
48
|
-
var
|
|
44
|
+
var _useState5 = (0, _react.useState)({
|
|
49
45
|
width: 0,
|
|
50
46
|
height: 0,
|
|
51
47
|
x: 0,
|
|
52
48
|
y: 0
|
|
53
49
|
}),
|
|
50
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
51
|
+
cameraWrapperLayout = _useState6[0],
|
|
52
|
+
setCameraWrapperLayout = _useState6[1];
|
|
53
|
+
var _useState7 = (0, _react.useState)(null),
|
|
54
54
|
_useState8 = _slicedToArray(_useState7, 2),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
var
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
greenFrame = _useState8[0],
|
|
56
|
+
setGreenFrame = _useState8[1];
|
|
57
|
+
var _useCameraPermission = (0, _reactNativeVisionCamera.useCameraPermission)(),
|
|
58
|
+
hasPermission = _useCameraPermission.hasPermission,
|
|
59
|
+
requestPermission = _useCameraPermission.requestPermission;
|
|
60
|
+
var device = (0, _reactNativeVisionCamera.useCameraDevice)('back');
|
|
61
61
|
(0, _react.useEffect)(function () {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
case 0:
|
|
67
|
-
_context.n = 1;
|
|
68
|
-
return _expoCamera.Camera.requestCameraPermissionsAsync();
|
|
69
|
-
case 1:
|
|
70
|
-
_yield$Camera$request = _context.v;
|
|
71
|
-
status = _yield$Camera$request.status;
|
|
72
|
-
setHasPermission(status === 'granted');
|
|
73
|
-
case 2:
|
|
74
|
-
return _context.a(2);
|
|
75
|
-
}
|
|
76
|
-
}, _callee);
|
|
77
|
-
}))();
|
|
78
|
-
}, []);
|
|
62
|
+
if (!hasPermission) {
|
|
63
|
+
requestPermission();
|
|
64
|
+
}
|
|
65
|
+
}, [hasPermission, requestPermission]);
|
|
79
66
|
|
|
80
67
|
// Helper function to wait for multiple render cycles (works on iOS)
|
|
81
68
|
var waitForRender = function waitForRender() {
|
|
@@ -94,23 +81,19 @@ function CustomCamera(_ref) {
|
|
|
94
81
|
});
|
|
95
82
|
};
|
|
96
83
|
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
// But we store it with wrapper dimensions so ImageCropper can map it correctly
|
|
84
|
+
// Green frame coordinates relative to camera preview wrapper.
|
|
85
|
+
// Preview matches sensor output (VisionCamera) so framing matches capture.
|
|
100
86
|
var calculateGreenFrameCoordinates = function calculateGreenFrameCoordinates() {
|
|
101
87
|
var wrapperWidth = cameraWrapperLayout.width;
|
|
102
88
|
var wrapperHeight = cameraWrapperLayout.height;
|
|
103
89
|
if (wrapperWidth === 0 || wrapperHeight === 0) {
|
|
104
|
-
console.warn(
|
|
90
|
+
console.warn('Camera wrapper layout not ready, cannot calculate green frame');
|
|
105
91
|
return null;
|
|
106
92
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
var
|
|
110
|
-
var
|
|
111
|
-
var frameX = (wrapperWidth - frameWidth) / 2; // Centered horizontally
|
|
112
|
-
var frameY = (wrapperHeight - frameHeight) / 2; // Centered vertically
|
|
113
|
-
|
|
93
|
+
var frameWidth = wrapperWidth * 0.85;
|
|
94
|
+
var frameHeight = wrapperHeight * 0.7;
|
|
95
|
+
var frameX = (wrapperWidth - frameWidth) / 2;
|
|
96
|
+
var frameY = (wrapperHeight - frameHeight) / 2;
|
|
114
97
|
var frameCoords = {
|
|
115
98
|
x: frameX,
|
|
116
99
|
y: frameY,
|
|
@@ -118,19 +101,14 @@ function CustomCamera(_ref) {
|
|
|
118
101
|
height: frameHeight,
|
|
119
102
|
wrapperWidth: wrapperWidth,
|
|
120
103
|
wrapperHeight: wrapperHeight,
|
|
121
|
-
// ✅ Store percentages for easier mapping later
|
|
122
104
|
percentX: frameX / wrapperWidth * 100,
|
|
123
105
|
percentY: frameY / wrapperHeight * 100,
|
|
124
106
|
percentWidth: 85,
|
|
125
|
-
|
|
126
|
-
percentHeight: 70 // 70% of wrapper height
|
|
107
|
+
percentHeight: 70
|
|
127
108
|
};
|
|
128
|
-
console.log(
|
|
109
|
+
console.log('Green frame coordinates calculated:', frameCoords);
|
|
129
110
|
return frameCoords;
|
|
130
111
|
};
|
|
131
|
-
|
|
132
|
-
// 🔁 Keep green frame state in sync with wrapper layout so we can both render it
|
|
133
|
-
// and send the exact same coordinates along with the captured photo.
|
|
134
112
|
(0, _react.useEffect)(function () {
|
|
135
113
|
var coords = calculateGreenFrameCoordinates();
|
|
136
114
|
if (coords) {
|
|
@@ -138,78 +116,101 @@ function CustomCamera(_ref) {
|
|
|
138
116
|
}
|
|
139
117
|
}, [cameraWrapperLayout]);
|
|
140
118
|
var takePicture = /*#__PURE__*/function () {
|
|
141
|
-
var
|
|
142
|
-
var photo,
|
|
143
|
-
return _regenerator().w(function (
|
|
144
|
-
while (1) switch (
|
|
119
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
120
|
+
var photo, uri, capturedAspectRatio, greenFrameCoords, _t;
|
|
121
|
+
return _regenerator().w(function (_context) {
|
|
122
|
+
while (1) switch (_context.p = _context.n) {
|
|
145
123
|
case 0:
|
|
146
|
-
if (!cameraRef.current) {
|
|
147
|
-
|
|
124
|
+
if (!(!cameraRef.current || !device)) {
|
|
125
|
+
_context.n = 1;
|
|
148
126
|
break;
|
|
149
127
|
}
|
|
150
|
-
|
|
151
|
-
|
|
128
|
+
return _context.a(2);
|
|
129
|
+
case 1:
|
|
130
|
+
_context.p = 1;
|
|
152
131
|
waitForRender(5).then(function () {
|
|
153
132
|
setLoadingBeforeCapture(true);
|
|
154
133
|
});
|
|
155
|
-
|
|
156
|
-
// Wait a bit before taking picture (works on iOS)
|
|
157
|
-
_context2.n = 2;
|
|
134
|
+
_context.n = 2;
|
|
158
135
|
return waitForRender(2);
|
|
159
136
|
case 2:
|
|
160
|
-
|
|
161
|
-
return cameraRef.current.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
shutterSound: false,
|
|
165
|
-
// skipProcessing: true = Désactiver le traitement automatique pour préserver la qualité pixel-perfect
|
|
166
|
-
// IMPORTANT : Cela préserve la résolution originale et évite toute interpolation
|
|
167
|
-
skipProcessing: true,
|
|
168
|
-
// exif: true = Inclure les métadonnées EXIF (orientation, etc.)
|
|
169
|
-
// L'orientation sera gérée dans ImageCropper si nécessaire via la fonction de rotation
|
|
170
|
-
exif: true
|
|
137
|
+
_context.n = 3;
|
|
138
|
+
return cameraRef.current.takePhoto({
|
|
139
|
+
enableShutterSound: false,
|
|
140
|
+
flash: 'off'
|
|
171
141
|
});
|
|
172
142
|
case 3:
|
|
173
|
-
photo =
|
|
174
|
-
|
|
175
|
-
|
|
143
|
+
photo = _context.v;
|
|
144
|
+
if (!(!photo.path || !photo.width || !photo.height)) {
|
|
145
|
+
_context.n = 4;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
throw new Error('Invalid photo received from camera');
|
|
149
|
+
case 4:
|
|
150
|
+
uri = photo.path.startsWith('file://') ? photo.path : "file://".concat(photo.path);
|
|
151
|
+
capturedAspectRatio = photo.width / photo.height;
|
|
152
|
+
console.log('Photo captured (VisionCamera):', {
|
|
153
|
+
uri: uri,
|
|
176
154
|
width: photo.width,
|
|
177
155
|
height: photo.height,
|
|
178
|
-
|
|
156
|
+
aspectRatio: capturedAspectRatio.toFixed(3)
|
|
179
157
|
});
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
onPhotoCaptured(fixedUri, {
|
|
158
|
+
greenFrameCoords = greenFrame || calculateGreenFrameCoordinates();
|
|
159
|
+
if (greenFrameCoords) {
|
|
160
|
+
_context.n = 5;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
throw new Error('Green frame coordinates not available');
|
|
164
|
+
case 5:
|
|
165
|
+
onPhotoCaptured(uri, {
|
|
189
166
|
greenFrame: greenFrameCoords,
|
|
190
167
|
capturedImageSize: {
|
|
191
168
|
width: photo.width,
|
|
192
|
-
height: photo.height
|
|
169
|
+
height: photo.height,
|
|
170
|
+
aspectRatio: capturedAspectRatio
|
|
193
171
|
}
|
|
194
172
|
});
|
|
195
173
|
setLoadingBeforeCapture(false);
|
|
196
|
-
|
|
174
|
+
_context.n = 7;
|
|
197
175
|
break;
|
|
198
|
-
case
|
|
199
|
-
|
|
200
|
-
_t =
|
|
201
|
-
console.error(
|
|
176
|
+
case 6:
|
|
177
|
+
_context.p = 6;
|
|
178
|
+
_t = _context.v;
|
|
179
|
+
console.error('Error capturing photo:', _t);
|
|
202
180
|
setLoadingBeforeCapture(false);
|
|
203
|
-
_reactNative.Alert.alert(
|
|
204
|
-
case
|
|
205
|
-
return
|
|
181
|
+
_reactNative.Alert.alert('Erreur', "Impossible de capturer la photo: ".concat(_t.message || 'Erreur inconnue', ". Veuillez r\xE9essayer."));
|
|
182
|
+
case 7:
|
|
183
|
+
return _context.a(2);
|
|
206
184
|
}
|
|
207
|
-
},
|
|
185
|
+
}, _callee, null, [[1, 6]]);
|
|
208
186
|
}));
|
|
209
187
|
return function takePicture() {
|
|
210
|
-
return
|
|
188
|
+
return _ref2.apply(this, arguments);
|
|
211
189
|
};
|
|
212
190
|
}();
|
|
191
|
+
if (!hasPermission) {
|
|
192
|
+
return /*#__PURE__*/_react["default"].createElement(_reactNative.SafeAreaView, {
|
|
193
|
+
style: styles.outerContainer
|
|
194
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
195
|
+
style: styles.permissionContainer
|
|
196
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
|
|
197
|
+
style: styles.text
|
|
198
|
+
}, "Acc\xE8s \xE0 la cam\xE9ra requis pour prendre des photos."), /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
|
|
199
|
+
style: styles.button,
|
|
200
|
+
onPress: requestPermission
|
|
201
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
|
|
202
|
+
style: styles.buttonText
|
|
203
|
+
}, "Autoriser la cam\xE9ra"))));
|
|
204
|
+
}
|
|
205
|
+
if (!device) {
|
|
206
|
+
return /*#__PURE__*/_react["default"].createElement(_reactNative.SafeAreaView, {
|
|
207
|
+
style: styles.outerContainer
|
|
208
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
209
|
+
style: styles.permissionContainer
|
|
210
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
|
|
211
|
+
style: styles.text
|
|
212
|
+
}, "Aucune cam\xE9ra arri\xE8re disponible.")));
|
|
213
|
+
}
|
|
213
214
|
return /*#__PURE__*/_react["default"].createElement(_reactNative.SafeAreaView, {
|
|
214
215
|
style: styles.outerContainer
|
|
215
216
|
}, /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
@@ -223,14 +224,17 @@ function CustomCamera(_ref) {
|
|
|
223
224
|
x: layout.x,
|
|
224
225
|
y: layout.y
|
|
225
226
|
});
|
|
226
|
-
console.log(
|
|
227
|
+
console.log('Camera wrapper layout updated:', layout);
|
|
227
228
|
}
|
|
228
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
229
|
-
style: styles.camera,
|
|
230
|
-
facing: "back",
|
|
229
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNativeVisionCamera.Camera, {
|
|
231
230
|
ref: cameraRef,
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
style: _reactNative.StyleSheet.absoluteFill,
|
|
232
|
+
device: device,
|
|
233
|
+
isActive: true,
|
|
234
|
+
photo: true,
|
|
235
|
+
onInitialized: function onInitialized() {
|
|
236
|
+
setIsReady(true);
|
|
237
|
+
console.log('VisionCamera ready - preview matches capture');
|
|
234
238
|
}
|
|
235
239
|
}), loadingBeforeCapture && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
236
240
|
style: styles.loadingOverlay
|
|
@@ -278,7 +282,6 @@ var styles = _reactNative.StyleSheet.create({
|
|
|
278
282
|
justifyContent: 'center',
|
|
279
283
|
position: 'relative'
|
|
280
284
|
},
|
|
281
|
-
camera: _objectSpread({}, _reactNative.StyleSheet.absoluteFillObject),
|
|
282
285
|
scanFrame: {
|
|
283
286
|
position: 'absolute',
|
|
284
287
|
borderWidth: 4,
|
|
@@ -300,14 +303,6 @@ var styles = _reactNative.StyleSheet.create({
|
|
|
300
303
|
zIndex: 21,
|
|
301
304
|
backgroundColor: 'transparent'
|
|
302
305
|
}),
|
|
303
|
-
cancelIcon: {
|
|
304
|
-
position: 'absolute',
|
|
305
|
-
top: 20,
|
|
306
|
-
left: 20,
|
|
307
|
-
backgroundColor: PRIMARY_GREEN,
|
|
308
|
-
borderRadius: 5,
|
|
309
|
-
padding: 8
|
|
310
|
-
},
|
|
311
306
|
buttonContainer: {
|
|
312
307
|
position: 'absolute',
|
|
313
308
|
bottom: 0,
|
|
@@ -329,16 +324,15 @@ var styles = _reactNative.StyleSheet.create({
|
|
|
329
324
|
fontSize: 18,
|
|
330
325
|
color: GLOW_WHITE
|
|
331
326
|
},
|
|
332
|
-
|
|
327
|
+
permissionContainer: {
|
|
333
328
|
flex: 1,
|
|
334
|
-
backgroundColor: DEEP_BLACK,
|
|
335
329
|
justifyContent: 'center',
|
|
336
330
|
alignItems: 'center',
|
|
337
331
|
padding: 20
|
|
338
332
|
},
|
|
339
|
-
|
|
340
|
-
fontSize:
|
|
341
|
-
color:
|
|
333
|
+
buttonText: {
|
|
334
|
+
fontSize: 16,
|
|
335
|
+
color: DEEP_BLACK,
|
|
342
336
|
fontWeight: '600'
|
|
343
337
|
}
|
|
344
338
|
});
|