react-native-expo-cropper 1.2.46 → 1.2.47
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 +14 -7
- package/dist/ImageCropper.js +17 -27
- package/package.json +1 -1
- package/src/CustomCamera.js +3 -0
- package/src/ImageCropper.js +34 -24
package/dist/CustomCamera.js
CHANGED
|
@@ -45,22 +45,28 @@ function CustomCamera(_ref) {
|
|
|
45
45
|
_useState6 = _slicedToArray(_useState5, 2),
|
|
46
46
|
hasPermission = _useState6[0],
|
|
47
47
|
setHasPermission = _useState6[1];
|
|
48
|
+
// Force a fresh native CameraView instance per "open" to avoid stale/cached preview.
|
|
49
|
+
var _useState7 = (0, _react.useState)(function () {
|
|
50
|
+
return "".concat(Date.now(), "-").concat(Math.random().toString(16).slice(2));
|
|
51
|
+
}),
|
|
52
|
+
_useState8 = _slicedToArray(_useState7, 1),
|
|
53
|
+
cameraViewMountKey = _useState8[0];
|
|
48
54
|
var cameraRef = (0, _react.useRef)(null);
|
|
49
55
|
var cameraWrapperRef = (0, _react.useRef)(null);
|
|
50
56
|
var insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
51
|
-
var
|
|
57
|
+
var _useState9 = (0, _react.useState)({
|
|
52
58
|
width: 0,
|
|
53
59
|
height: 0,
|
|
54
60
|
x: 0,
|
|
55
61
|
y: 0
|
|
56
62
|
}),
|
|
57
|
-
_useState8 = _slicedToArray(_useState7, 2),
|
|
58
|
-
cameraWrapperLayout = _useState8[0],
|
|
59
|
-
setCameraWrapperLayout = _useState8[1];
|
|
60
|
-
var _useState9 = (0, _react.useState)(null),
|
|
61
63
|
_useState0 = _slicedToArray(_useState9, 2),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
cameraWrapperLayout = _useState0[0],
|
|
65
|
+
setCameraWrapperLayout = _useState0[1];
|
|
66
|
+
var _useState1 = (0, _react.useState)(null),
|
|
67
|
+
_useState10 = _slicedToArray(_useState1, 2),
|
|
68
|
+
greenFrame = _useState10[0],
|
|
69
|
+
setGreenFrame = _useState10[1];
|
|
64
70
|
(0, _react.useEffect)(function () {
|
|
65
71
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
66
72
|
var _yield$Camera$request, status;
|
|
@@ -267,6 +273,7 @@ function CustomCamera(_ref) {
|
|
|
267
273
|
console.log("Camera wrapper layout updated:", layout);
|
|
268
274
|
}
|
|
269
275
|
}, /*#__PURE__*/_react["default"].createElement(_expoCamera.CameraView, {
|
|
276
|
+
key: cameraViewMountKey,
|
|
270
277
|
style: styles.camera,
|
|
271
278
|
facing: "back",
|
|
272
279
|
ref: cameraRef,
|
package/dist/ImageCropper.js
CHANGED
|
@@ -253,6 +253,7 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
253
253
|
var rotationInProgressRef = (0, _react.useRef)(false); // block duplicate taps immediately
|
|
254
254
|
var lastValidPosition = (0, _react.useRef)(null);
|
|
255
255
|
var insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
256
|
+
var openCameraTimeoutRef = (0, _react.useRef)(null);
|
|
256
257
|
|
|
257
258
|
// ✅ NEW ARCH: mobile does NOT export the final crop.
|
|
258
259
|
|
|
@@ -261,8 +262,17 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
261
262
|
var enableRotation = true; // rotation resets crop box so it is re-initialized on rotated image.
|
|
262
263
|
|
|
263
264
|
(0, _react.useEffect)(function () {
|
|
265
|
+
// If a previous open was scheduled, cancel it.
|
|
266
|
+
if (openCameraTimeoutRef.current) {
|
|
267
|
+
clearTimeout(openCameraTimeoutRef.current);
|
|
268
|
+
openCameraTimeoutRef.current = null;
|
|
269
|
+
}
|
|
264
270
|
if (openCameraFirst) {
|
|
265
|
-
|
|
271
|
+
// Delay opening the camera so the prior session can fully release.
|
|
272
|
+
openCameraTimeoutRef.current = setTimeout(function () {
|
|
273
|
+
setShowCustomCamera(true);
|
|
274
|
+
openCameraTimeoutRef.current = null;
|
|
275
|
+
}, 800);
|
|
266
276
|
} else if (initialImage) {
|
|
267
277
|
setImage(initialImage);
|
|
268
278
|
sourceImageUri.current = initialImage;
|
|
@@ -276,6 +286,12 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
276
286
|
hasInitializedCropBox.current = false;
|
|
277
287
|
imageSource.current = null;
|
|
278
288
|
}
|
|
289
|
+
return function () {
|
|
290
|
+
if (openCameraTimeoutRef.current) {
|
|
291
|
+
clearTimeout(openCameraTimeoutRef.current);
|
|
292
|
+
openCameraTimeoutRef.current = null;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
279
295
|
}, [openCameraFirst, initialImage]);
|
|
280
296
|
|
|
281
297
|
// ✅ REFACTORISATION : Stocker uniquement les dimensions originales (pas de calcul théorique)
|
|
@@ -1305,31 +1321,6 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1305
1321
|
style: _ImageCropperStyles["default"].container
|
|
1306
1322
|
}, showCustomCamera ? /*#__PURE__*/_react["default"].createElement(_CustomCamera["default"], {
|
|
1307
1323
|
onPhotoCaptured: function onPhotoCaptured(uri, frameData) {
|
|
1308
|
-
// ✅ Reset refs for new image so second (and later) photos don't use first image's layout (fixes white screen on some devices)
|
|
1309
|
-
originalImageDimensions.current = {
|
|
1310
|
-
width: 0,
|
|
1311
|
-
height: 0
|
|
1312
|
-
};
|
|
1313
|
-
imageDisplayRect.current = {
|
|
1314
|
-
x: 0,
|
|
1315
|
-
y: 0,
|
|
1316
|
-
width: 0,
|
|
1317
|
-
height: 0
|
|
1318
|
-
};
|
|
1319
|
-
displayedImageLayout.current = {
|
|
1320
|
-
x: 0,
|
|
1321
|
-
y: 0,
|
|
1322
|
-
width: 0,
|
|
1323
|
-
height: 0
|
|
1324
|
-
};
|
|
1325
|
-
imageMeasure.current = {
|
|
1326
|
-
x: 0,
|
|
1327
|
-
y: 0,
|
|
1328
|
-
width: 0,
|
|
1329
|
-
height: 0
|
|
1330
|
-
};
|
|
1331
|
-
sourceImageUri.current = uri;
|
|
1332
|
-
|
|
1333
1324
|
// ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
|
|
1334
1325
|
if (frameData && frameData.greenFrame) {
|
|
1335
1326
|
cameraFrameData.current = {
|
|
@@ -1425,7 +1416,6 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1425
1416
|
return hasMovement;
|
|
1426
1417
|
}
|
|
1427
1418
|
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Image, {
|
|
1428
|
-
key: image,
|
|
1429
1419
|
source: {
|
|
1430
1420
|
uri: image
|
|
1431
1421
|
},
|
package/package.json
CHANGED
package/src/CustomCamera.js
CHANGED
|
@@ -22,6 +22,8 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
|
|
|
22
22
|
const [isReady, setIsReady] = useState(false);
|
|
23
23
|
const [loadingBeforeCapture, setLoadingBeforeCapture] = useState(false);
|
|
24
24
|
const [hasPermission, setHasPermission] = useState(null);
|
|
25
|
+
// Force a fresh native CameraView instance per "open" to avoid stale/cached preview.
|
|
26
|
+
const [cameraViewMountKey] = useState(() => `${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
25
27
|
const cameraRef = useRef(null);
|
|
26
28
|
const cameraWrapperRef = useRef(null);
|
|
27
29
|
const insets = useSafeAreaInsets();
|
|
@@ -213,6 +215,7 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
|
|
|
213
215
|
}}
|
|
214
216
|
>
|
|
215
217
|
<CameraView
|
|
218
|
+
key={cameraViewMountKey}
|
|
216
219
|
style={styles.camera}
|
|
217
220
|
facing="back"
|
|
218
221
|
ref={cameraRef}
|
package/src/ImageCropper.js
CHANGED
|
@@ -141,6 +141,7 @@ const ImageCropper = ({ onConfirm, openCameraFirst, initialImage, addheight, rot
|
|
|
141
141
|
const rotationInProgressRef = useRef(false); // block duplicate taps immediately
|
|
142
142
|
const lastValidPosition = useRef(null);
|
|
143
143
|
const insets = useSafeAreaInsets();
|
|
144
|
+
const openCameraTimeoutRef = useRef(null);
|
|
144
145
|
|
|
145
146
|
// ✅ NEW ARCH: mobile does NOT export the final crop.
|
|
146
147
|
|
|
@@ -153,22 +154,39 @@ const ImageCropper = ({ onConfirm, openCameraFirst, initialImage, addheight, rot
|
|
|
153
154
|
|
|
154
155
|
|
|
155
156
|
useEffect(() => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
157
|
+
// If a previous open was scheduled, cancel it.
|
|
158
|
+
if (openCameraTimeoutRef.current) {
|
|
159
|
+
clearTimeout(openCameraTimeoutRef.current);
|
|
160
|
+
openCameraTimeoutRef.current = null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (openCameraFirst) {
|
|
164
|
+
// Delay opening the camera so the prior session can fully release.
|
|
165
|
+
openCameraTimeoutRef.current = setTimeout(() => {
|
|
166
|
+
setShowCustomCamera(true);
|
|
167
|
+
openCameraTimeoutRef.current = null;
|
|
168
|
+
}, 800);
|
|
169
|
+
} else if (initialImage) {
|
|
170
|
+
setImage(initialImage);
|
|
171
|
+
sourceImageUri.current = initialImage;
|
|
172
|
+
// ✅ CRITICAL: Reset points when loading a new image from gallery
|
|
173
|
+
// This ensures the crop box will be automatically initialized
|
|
174
|
+
setPoints([]);
|
|
175
|
+
rotationAngle.current = 0;
|
|
176
|
+
// Clear camera frame data for gallery images
|
|
177
|
+
cameraFrameData.current = null;
|
|
178
|
+
// ✅ CRITICAL: Reset initialization guard for new image
|
|
179
|
+
hasInitializedCropBox.current = false;
|
|
180
|
+
imageSource.current = null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return () => {
|
|
184
|
+
if (openCameraTimeoutRef.current) {
|
|
185
|
+
clearTimeout(openCameraTimeoutRef.current);
|
|
186
|
+
openCameraTimeoutRef.current = null;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}, [openCameraFirst, initialImage]);
|
|
172
190
|
|
|
173
191
|
|
|
174
192
|
// ✅ REFACTORISATION : Stocker uniquement les dimensions originales (pas de calcul théorique)
|
|
@@ -1100,13 +1118,6 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1100
1118
|
{showCustomCamera ? (
|
|
1101
1119
|
<CustomCamera
|
|
1102
1120
|
onPhotoCaptured={(uri, frameData) => {
|
|
1103
|
-
// ✅ Reset refs for new image so second (and later) photos don't use first image's layout (fixes white screen on some devices)
|
|
1104
|
-
originalImageDimensions.current = { width: 0, height: 0 };
|
|
1105
|
-
imageDisplayRect.current = { x: 0, y: 0, width: 0, height: 0 };
|
|
1106
|
-
displayedImageLayout.current = { x: 0, y: 0, width: 0, height: 0 };
|
|
1107
|
-
imageMeasure.current = { x: 0, y: 0, width: 0, height: 0 };
|
|
1108
|
-
sourceImageUri.current = uri;
|
|
1109
|
-
|
|
1110
1121
|
// ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
|
|
1111
1122
|
if (frameData && frameData.greenFrame) {
|
|
1112
1123
|
cameraFrameData.current = {
|
|
@@ -1204,7 +1215,6 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1204
1215
|
}}
|
|
1205
1216
|
>
|
|
1206
1217
|
<Image
|
|
1207
|
-
key={image}
|
|
1208
1218
|
source={{ uri: image }}
|
|
1209
1219
|
style={styles.image}
|
|
1210
1220
|
resizeMode={cameraFrameData.current?.greenFrame ? 'cover' : 'contain'}
|