react-native-expo-cropper 1.0.26 → 1.0.27
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/package.json +1 -1
- package/src/ImageCropper.js +59 -49
- package/src/ImageProcessor.js +44 -27
package/package.json
CHANGED
package/src/ImageCropper.js
CHANGED
|
@@ -79,6 +79,53 @@ const ImageCropper = ({ onConfirm, openCameraFirst, initialImage ,addheight}) =>
|
|
|
79
79
|
return () => { cancelled = true; };
|
|
80
80
|
}, [captureRequested, showResult, overlayReady, addheight, onConfirm]);
|
|
81
81
|
|
|
82
|
+
// Helpers to compute crop rectangle in original image pixels
|
|
83
|
+
const getImageSizeAsync = (uri) =>
|
|
84
|
+
new Promise((resolve, reject) => {
|
|
85
|
+
Image.getSize(uri, (w, h) => resolve({ width: w, height: h }), reject);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const computeCropRect = (pts, measure, origW, origH) => {
|
|
89
|
+
const containerW = measure.width;
|
|
90
|
+
const containerH = measure.height;
|
|
91
|
+
if (!containerW || !containerH || !origW || !origH || !pts || pts.length === 0) return null;
|
|
92
|
+
|
|
93
|
+
const ratio = origH / origW;
|
|
94
|
+
let dispW, dispH, offX, offY;
|
|
95
|
+
if (containerW * ratio <= containerH) {
|
|
96
|
+
// image constrained by width
|
|
97
|
+
dispW = containerW;
|
|
98
|
+
dispH = containerW * ratio;
|
|
99
|
+
offX = 0;
|
|
100
|
+
offY = (containerH - dispH) / 2;
|
|
101
|
+
} else {
|
|
102
|
+
// image constrained by height
|
|
103
|
+
dispH = containerH;
|
|
104
|
+
dispW = containerH / ratio;
|
|
105
|
+
offY = 0;
|
|
106
|
+
offX = (containerW - dispW) / 2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const xs = pts.map(p => Math.max(0, Math.min(dispW, p.x - offX)));
|
|
110
|
+
const ys = pts.map(p => Math.max(0, Math.min(dispH, p.y - offY)));
|
|
111
|
+
const minX = Math.min(...xs);
|
|
112
|
+
const maxX = Math.max(...xs);
|
|
113
|
+
const minY = Math.min(...ys);
|
|
114
|
+
const maxY = Math.max(...ys);
|
|
115
|
+
|
|
116
|
+
const normMinX = minX / dispW;
|
|
117
|
+
const normMaxX = maxX / dispW;
|
|
118
|
+
const normMinY = minY / dispH;
|
|
119
|
+
const normMaxY = maxY / dispH;
|
|
120
|
+
|
|
121
|
+
const originX = Math.round(normMinX * origW);
|
|
122
|
+
const originY = Math.round(normMinY * origH);
|
|
123
|
+
const widthPx = Math.round((normMaxX - normMinX) * origW);
|
|
124
|
+
const heightPx = Math.round((normMaxY - normMinY) * origH);
|
|
125
|
+
|
|
126
|
+
return { x: originX, y: originY, width: widthPx, height: heightPx };
|
|
127
|
+
};
|
|
128
|
+
|
|
82
129
|
|
|
83
130
|
const initializeCropBox = () => {
|
|
84
131
|
const { width, height } = imageMeasure.current;
|
|
@@ -143,26 +190,6 @@ const ImageCropper = ({ onConfirm, openCameraFirst, initialImage ,addheight}) =>
|
|
|
143
190
|
const boundedX = Math.max(0, Math.min(moveX, width));
|
|
144
191
|
const boundedY = Math.max(0, Math.min(moveY, height));
|
|
145
192
|
|
|
146
|
-
const edgeThreshold = 10;
|
|
147
|
-
const isNearTopOrBottomEdge =
|
|
148
|
-
boundedY <= edgeThreshold || boundedY >= height - edgeThreshold;
|
|
149
|
-
|
|
150
|
-
const isNearLeftOrRightEdge =
|
|
151
|
-
boundedX <= edgeThreshold || boundedX >= width - edgeThreshold;
|
|
152
|
-
|
|
153
|
-
if (isNearTopOrBottomEdge || isNearLeftOrRightEdge) {
|
|
154
|
-
// Reset point to last known position
|
|
155
|
-
if (lastValidPosition.current && selectedPointIndex.current !== null) {
|
|
156
|
-
setPoints(prev =>
|
|
157
|
-
prev.map((p, i) =>
|
|
158
|
-
i === selectedPointIndex.current ? lastValidPosition.current : p
|
|
159
|
-
)
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
selectedPointIndex.current = null;
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
193
|
// Valid move — update point and store as new last valid position
|
|
167
194
|
const updatedPoint = { x: boundedX, y: boundedY };
|
|
168
195
|
lastValidPosition.current = updatedPoint;
|
|
@@ -288,35 +315,18 @@ const ImageCropper = ({ onConfirm, openCameraFirst, initialImage ,addheight}) =>
|
|
|
288
315
|
<TouchableOpacity
|
|
289
316
|
style={styles.button}
|
|
290
317
|
onPress={async () => {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const enhancedUri = await enhanceImage(capturedUri, addheight);
|
|
304
|
-
const name = `IMAGE XTK${Date.now()}.png`;
|
|
305
|
-
|
|
306
|
-
if (onConfirm) {
|
|
307
|
-
onConfirm(enhancedUri, name);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
setShowResult(false);
|
|
311
|
-
setIsLoading(false);
|
|
312
|
-
setShowFullScreenCapture(false);
|
|
313
|
-
setCaptureRequested(false);
|
|
314
|
-
setOverlayReady(false);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
console.error('Erreur lors de la capture :', error);
|
|
317
|
-
alert('Erreur lors de la capture !');
|
|
318
|
-
setIsLoading(false);
|
|
319
|
-
}
|
|
318
|
+
try {
|
|
319
|
+
setIsLoading(true);
|
|
320
|
+
const { width: origW, height: origH } = await getImageSizeAsync(image);
|
|
321
|
+
const rect = computeCropRect(points, imageMeasure.current, origW, origH);
|
|
322
|
+
const enhancedUri = await enhanceImage(image, addheight, rect);
|
|
323
|
+
const name = `IMAGE XTK${Date.now()}.png`;
|
|
324
|
+
if (onConfirm) onConfirm(enhancedUri, name);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error('Erreur lors de la capture :', error);
|
|
327
|
+
alert('Erreur lors de la capture !');
|
|
328
|
+
} finally {
|
|
329
|
+
setIsLoading(false);
|
|
320
330
|
}
|
|
321
331
|
}}
|
|
322
332
|
>
|
package/src/ImageProcessor.js
CHANGED
|
@@ -1,28 +1,45 @@
|
|
|
1
|
-
import * as ImageManipulator from 'expo-image-manipulator';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
import * as ImageManipulator from 'expo-image-manipulator';
|
|
2
|
+
|
|
3
|
+
// Crop the image to the provided rectangle (in original image pixels), then resize.
|
|
4
|
+
// cropRect: { x, y, width, height } in original image coordinates
|
|
5
|
+
export const enhanceImage = async (uri, addheight, cropRect) => {
|
|
6
|
+
try {
|
|
7
|
+
const actions = [];
|
|
8
|
+
if (cropRect && cropRect.width > 0 && cropRect.height > 0) {
|
|
9
|
+
actions.push({
|
|
10
|
+
crop: {
|
|
11
|
+
originX: Math.round(cropRect.x),
|
|
12
|
+
originY: Math.round(cropRect.y),
|
|
13
|
+
width: Math.round(cropRect.width),
|
|
14
|
+
height: Math.round(cropRect.height),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// First: crop (if requested)
|
|
20
|
+
const cropped = await ImageManipulator.manipulateAsync(uri, actions, {
|
|
21
|
+
compress: 1,
|
|
22
|
+
format: ImageManipulator.SaveFormat.PNG,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Then: resize to requested height while preserving aspect ratio
|
|
26
|
+
const targetHeight = addheight || cropped.height;
|
|
27
|
+
const ratio = cropped.height / cropped.width;
|
|
28
|
+
const newWidth = Math.round(targetHeight / ratio);
|
|
29
|
+
const newHeight = Math.round(newWidth * ratio);
|
|
30
|
+
|
|
31
|
+
const result = await ImageManipulator.manipulateAsync(
|
|
32
|
+
cropped.uri,
|
|
33
|
+
[{ resize: { width: newWidth, height: newHeight } }],
|
|
34
|
+
{
|
|
35
|
+
compress: 1,
|
|
36
|
+
format: ImageManipulator.SaveFormat.PNG,
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return result.uri;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Erreur T404K:', error);
|
|
43
|
+
return uri;
|
|
44
|
+
}
|
|
28
45
|
};
|