react-native-expo-cropper 1.2.50 → 1.2.52
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 +25 -2
- package/dist/ImageCropper.js +31 -4
- package/package.json +1 -1
- package/src/CustomCamera.js +24 -1
- package/src/ImageCropper.js +62 -12
package/dist/CustomCamera.js
CHANGED
|
@@ -29,7 +29,9 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
|
29
29
|
var CAMERA_PREVIEW_MAX_WIDTH = 500;
|
|
30
30
|
function CustomCamera(_ref) {
|
|
31
31
|
var onPhotoCaptured = _ref.onPhotoCaptured,
|
|
32
|
-
onFrameCalculated = _ref.onFrameCalculated
|
|
32
|
+
onFrameCalculated = _ref.onFrameCalculated,
|
|
33
|
+
_ref$instructionText = _ref.instructionText,
|
|
34
|
+
instructionText = _ref$instructionText === void 0 ? 'Place the tray inside the green box' : _ref$instructionText;
|
|
33
35
|
var _useWindowDimensions = (0, _reactNative.useWindowDimensions)(),
|
|
34
36
|
windowWidth = _useWindowDimensions.width;
|
|
35
37
|
var cameraPreviewWidth = Math.min(windowWidth, CAMERA_PREVIEW_MAX_WIDTH);
|
|
@@ -318,7 +320,9 @@ function CustomCamera(_ref) {
|
|
|
318
320
|
});
|
|
319
321
|
console.log("Camera wrapper layout updated:", layout);
|
|
320
322
|
}
|
|
321
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
323
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
|
|
324
|
+
style: styles.cameraInstruction
|
|
325
|
+
}, instructionText), /*#__PURE__*/_react["default"].createElement(_expoCamera.CameraView, {
|
|
322
326
|
style: styles.camera,
|
|
323
327
|
facing: "back",
|
|
324
328
|
ref: cameraRef,
|
|
@@ -397,6 +401,25 @@ var styles = _reactNative.StyleSheet.create({
|
|
|
397
401
|
justifyContent: 'center',
|
|
398
402
|
position: 'relative'
|
|
399
403
|
},
|
|
404
|
+
cameraInstruction: {
|
|
405
|
+
position: 'absolute',
|
|
406
|
+
top: 8,
|
|
407
|
+
left: 12,
|
|
408
|
+
right: 12,
|
|
409
|
+
textAlign: 'center',
|
|
410
|
+
color: GLOW_WHITE,
|
|
411
|
+
fontSize: 14,
|
|
412
|
+
fontWeight: '600',
|
|
413
|
+
zIndex: 10,
|
|
414
|
+
textShadowColor: 'rgba(0, 0, 0, 0.7)',
|
|
415
|
+
textShadowOffset: {
|
|
416
|
+
width: 0,
|
|
417
|
+
height: 1
|
|
418
|
+
},
|
|
419
|
+
textShadowRadius: 2,
|
|
420
|
+
// Allow camera/scan frame to still receive touches
|
|
421
|
+
pointerEvents: 'none'
|
|
422
|
+
},
|
|
400
423
|
camera: _objectSpread({}, _reactNative.StyleSheet.absoluteFillObject),
|
|
401
424
|
scanFrame: {
|
|
402
425
|
position: 'absolute',
|
package/dist/ImageCropper.js
CHANGED
|
@@ -45,7 +45,14 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
45
45
|
openCameraFirst = _ref.openCameraFirst,
|
|
46
46
|
initialImage = _ref.initialImage,
|
|
47
47
|
addheight = _ref.addheight,
|
|
48
|
-
rotationLabel = _ref.rotationLabel
|
|
48
|
+
rotationLabel = _ref.rotationLabel,
|
|
49
|
+
onCancel = _ref.onCancel,
|
|
50
|
+
_ref$confirmText = _ref.confirmText,
|
|
51
|
+
confirmText = _ref$confirmText === void 0 ? 'Confirm' : _ref$confirmText,
|
|
52
|
+
_ref$resetText = _ref.resetText,
|
|
53
|
+
resetText = _ref$resetText === void 0 ? 'Reset' : _ref$resetText,
|
|
54
|
+
_ref$cameraInstructio = _ref.cameraInstructionText,
|
|
55
|
+
cameraInstructionText = _ref$cameraInstructio === void 0 ? 'Place the tray inside the green box' : _ref$cameraInstructio;
|
|
49
56
|
var _useWindowDimensions = (0, _reactNative.useWindowDimensions)(),
|
|
50
57
|
windowWidth = _useWindowDimensions.width,
|
|
51
58
|
windowHeight = _useWindowDimensions.height;
|
|
@@ -1223,6 +1230,7 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1223
1230
|
return /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
1224
1231
|
style: _ImageCropperStyles["default"].container
|
|
1225
1232
|
}, showCustomCamera ? /*#__PURE__*/_react["default"].createElement(_CustomCamera["default"], {
|
|
1233
|
+
instructionText: cameraInstructionText,
|
|
1226
1234
|
onPhotoCaptured: function onPhotoCaptured(uri, frameData) {
|
|
1227
1235
|
// ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
|
|
1228
1236
|
if (frameData && frameData.greenFrame) {
|
|
@@ -1388,7 +1396,26 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1388
1396
|
paddingHorizontal: Math.round(12 * responsiveScale),
|
|
1389
1397
|
gap: Math.round(8 * responsiveScale)
|
|
1390
1398
|
}]
|
|
1391
|
-
},
|
|
1399
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
|
|
1400
|
+
style: [_ImageCropperStyles["default"].rotationButton, {
|
|
1401
|
+
backgroundColor: 'transparent',
|
|
1402
|
+
borderWidth: 1,
|
|
1403
|
+
borderColor: 'white',
|
|
1404
|
+
width: Math.round(40 * responsiveScale),
|
|
1405
|
+
height: Math.round(40 * responsiveScale),
|
|
1406
|
+
borderRadius: Math.round(20 * responsiveScale),
|
|
1407
|
+
marginRight: Math.round(6 * responsiveScale)
|
|
1408
|
+
}],
|
|
1409
|
+
onPress: function onPress() {
|
|
1410
|
+
if (onCancel) {
|
|
1411
|
+
onCancel();
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}, /*#__PURE__*/_react["default"].createElement(_vectorIcons.Ionicons, {
|
|
1415
|
+
name: "close",
|
|
1416
|
+
size: Math.round(20 * responsiveScale),
|
|
1417
|
+
color: "white"
|
|
1418
|
+
})), _reactNative.Platform.OS === 'android' && /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
|
|
1392
1419
|
style: [_ImageCropperStyles["default"].rotationButton, {
|
|
1393
1420
|
width: Math.round(56 * responsiveScale),
|
|
1394
1421
|
height: Math.round(48 * responsiveScale),
|
|
@@ -1418,7 +1445,7 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1418
1445
|
style: [_ImageCropperStyles["default"].buttonText, {
|
|
1419
1446
|
fontSize: Math.max(14, Math.round(18 * responsiveScale))
|
|
1420
1447
|
}]
|
|
1421
|
-
},
|
|
1448
|
+
}, resetText)), /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
|
|
1422
1449
|
onPress: /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
1423
1450
|
var _cameraFrameData$curr4, actualImageWidth, actualImageHeight, isCoverMode, captured, layout, contentRect, displayedWidth, displayedHeight, scale, coverOffsetX, coverOffsetY, scaledWidth, scaledHeight, originalUri, cropMeta, imagePoints, minX, minY, maxX, maxY, cropX, cropY, cropEndX, cropEndY, cropWidth, cropHeight, bbox, polygon, ext, safeExt, name, _t2;
|
|
1424
1451
|
return _regenerator().w(function (_context2) {
|
|
@@ -1594,7 +1621,7 @@ var ImageCropper = function ImageCropper(_ref) {
|
|
|
1594
1621
|
style: [_ImageCropperStyles["default"].buttonText, {
|
|
1595
1622
|
fontSize: Math.max(14, Math.round(18 * responsiveScale))
|
|
1596
1623
|
}]
|
|
1597
|
-
},
|
|
1624
|
+
}, confirmText))), !showResult && !image && /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
|
|
1598
1625
|
style: _ImageCropperStyles["default"].centerButtonsContainer
|
|
1599
1626
|
}, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
|
|
1600
1627
|
style: _ImageCropperStyles["default"].welcomeText
|
package/package.json
CHANGED
package/src/CustomCamera.js
CHANGED
|
@@ -16,7 +16,11 @@ import { Camera, CameraView } from 'expo-camera';
|
|
|
16
16
|
// Max width for camera preview on large screens (tablets) so it doesn't stretch full width
|
|
17
17
|
const CAMERA_PREVIEW_MAX_WIDTH = 500;
|
|
18
18
|
|
|
19
|
-
export default function CustomCamera({
|
|
19
|
+
export default function CustomCamera({
|
|
20
|
+
onPhotoCaptured,
|
|
21
|
+
onFrameCalculated,
|
|
22
|
+
instructionText = 'Place the tray inside the green box',
|
|
23
|
+
}) {
|
|
20
24
|
const { width: windowWidth } = useWindowDimensions();
|
|
21
25
|
const cameraPreviewWidth = Math.min(windowWidth, CAMERA_PREVIEW_MAX_WIDTH);
|
|
22
26
|
const [isReady, setIsReady] = useState(false);
|
|
@@ -250,6 +254,9 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
|
|
|
250
254
|
console.log("Camera wrapper layout updated:", layout);
|
|
251
255
|
}}
|
|
252
256
|
>
|
|
257
|
+
<Text style={styles.cameraInstruction}>
|
|
258
|
+
{instructionText}
|
|
259
|
+
</Text>
|
|
253
260
|
<CameraView
|
|
254
261
|
style={styles.camera}
|
|
255
262
|
facing="back"
|
|
@@ -345,6 +352,22 @@ const styles = StyleSheet.create({
|
|
|
345
352
|
justifyContent: 'center',
|
|
346
353
|
position: 'relative',
|
|
347
354
|
},
|
|
355
|
+
cameraInstruction: {
|
|
356
|
+
position: 'absolute',
|
|
357
|
+
top: 8,
|
|
358
|
+
left: 12,
|
|
359
|
+
right: 12,
|
|
360
|
+
textAlign: 'center',
|
|
361
|
+
color: GLOW_WHITE,
|
|
362
|
+
fontSize: 14,
|
|
363
|
+
fontWeight: '600',
|
|
364
|
+
zIndex: 10,
|
|
365
|
+
textShadowColor: 'rgba(0, 0, 0, 0.7)',
|
|
366
|
+
textShadowOffset: { width: 0, height: 1 },
|
|
367
|
+
textShadowRadius: 2,
|
|
368
|
+
// Allow camera/scan frame to still receive touches
|
|
369
|
+
pointerEvents: 'none',
|
|
370
|
+
},
|
|
348
371
|
camera: {
|
|
349
372
|
...StyleSheet.absoluteFillObject,
|
|
350
373
|
},
|
package/src/ImageCropper.js
CHANGED
|
@@ -13,7 +13,17 @@ const PRIMARY_GREEN = '#198754';
|
|
|
13
13
|
// Base dimension for responsive scaling (e.g. ~375pt design width)
|
|
14
14
|
const RESPONSIVE_BASE = 375;
|
|
15
15
|
|
|
16
|
-
const ImageCropper = ({
|
|
16
|
+
const ImageCropper = ({
|
|
17
|
+
onConfirm,
|
|
18
|
+
openCameraFirst,
|
|
19
|
+
initialImage,
|
|
20
|
+
addheight,
|
|
21
|
+
rotationLabel,
|
|
22
|
+
onCancel,
|
|
23
|
+
confirmText = 'Confirm',
|
|
24
|
+
resetText = 'Reset',
|
|
25
|
+
cameraInstructionText = 'Place the tray inside the green box',
|
|
26
|
+
}) => {
|
|
17
27
|
const { width: windowWidth, height: windowHeight } = useWindowDimensions();
|
|
18
28
|
|
|
19
29
|
// Responsive scale: image and UI adapt to small (phone) and large (tablet) screens
|
|
@@ -1044,6 +1054,7 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1044
1054
|
|
|
1045
1055
|
{showCustomCamera ? (
|
|
1046
1056
|
<CustomCamera
|
|
1057
|
+
instructionText={cameraInstructionText}
|
|
1047
1058
|
onPhotoCaptured={(uri, frameData) => {
|
|
1048
1059
|
// ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
|
|
1049
1060
|
if (frameData && frameData.greenFrame) {
|
|
@@ -1192,15 +1203,40 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1192
1203
|
|
|
1193
1204
|
{/* ✅ Buttons positioned as a responsive bottom bar (scale with screen size) */}
|
|
1194
1205
|
{!showResult && image && (
|
|
1195
|
-
<View
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1206
|
+
<View
|
|
1207
|
+
style={[
|
|
1208
|
+
styles.buttonContainerBelow,
|
|
1209
|
+
{
|
|
1210
|
+
paddingBottom: Math.max(insets.bottom, Math.round(16 * responsiveScale)),
|
|
1211
|
+
paddingTop: Math.round(12 * responsiveScale),
|
|
1212
|
+
paddingHorizontal: Math.round(12 * responsiveScale),
|
|
1213
|
+
gap: Math.round(8 * responsiveScale),
|
|
1214
|
+
},
|
|
1215
|
+
]}
|
|
1216
|
+
>
|
|
1217
|
+
{/* Close button: always visible, closes cropper */}
|
|
1218
|
+
<TouchableOpacity
|
|
1219
|
+
style={[
|
|
1220
|
+
styles.rotationButton,
|
|
1221
|
+
{
|
|
1222
|
+
backgroundColor: 'transparent',
|
|
1223
|
+
borderWidth: 1,
|
|
1224
|
+
borderColor: 'white',
|
|
1225
|
+
width: Math.round(40 * responsiveScale),
|
|
1226
|
+
height: Math.round(40 * responsiveScale),
|
|
1227
|
+
borderRadius: Math.round(20 * responsiveScale),
|
|
1228
|
+
marginRight: Math.round(6 * responsiveScale),
|
|
1229
|
+
},
|
|
1230
|
+
]}
|
|
1231
|
+
onPress={() => {
|
|
1232
|
+
if (onCancel) {
|
|
1233
|
+
onCancel();
|
|
1234
|
+
}
|
|
1235
|
+
}}
|
|
1236
|
+
>
|
|
1237
|
+
<Ionicons name="close" size={Math.round(20 * responsiveScale)} color="white" />
|
|
1238
|
+
</TouchableOpacity>
|
|
1239
|
+
|
|
1204
1240
|
{Platform.OS === 'android' && (
|
|
1205
1241
|
<TouchableOpacity
|
|
1206
1242
|
style={[
|
|
@@ -1234,7 +1270,14 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1234
1270
|
]}
|
|
1235
1271
|
onPress={handleReset}
|
|
1236
1272
|
>
|
|
1237
|
-
<Text
|
|
1273
|
+
<Text
|
|
1274
|
+
style={[
|
|
1275
|
+
styles.buttonText,
|
|
1276
|
+
{ fontSize: Math.max(14, Math.round(18 * responsiveScale)) },
|
|
1277
|
+
]}
|
|
1278
|
+
>
|
|
1279
|
+
{resetText}
|
|
1280
|
+
</Text>
|
|
1238
1281
|
</TouchableOpacity>
|
|
1239
1282
|
|
|
1240
1283
|
<TouchableOpacity
|
|
@@ -1377,7 +1420,14 @@ const rotatePreviewImage = async (degrees) => {
|
|
|
1377
1420
|
},
|
|
1378
1421
|
]}
|
|
1379
1422
|
>
|
|
1380
|
-
<Text
|
|
1423
|
+
<Text
|
|
1424
|
+
style={[
|
|
1425
|
+
styles.buttonText,
|
|
1426
|
+
{ fontSize: Math.max(14, Math.round(18 * responsiveScale)) },
|
|
1427
|
+
]}
|
|
1428
|
+
>
|
|
1429
|
+
{confirmText}
|
|
1430
|
+
</Text>
|
|
1381
1431
|
</TouchableOpacity>
|
|
1382
1432
|
</View>
|
|
1383
1433
|
)}
|