react-native-expo-cropper 1.2.38 → 1.2.39

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.
@@ -17,6 +17,8 @@ var styles = _reactNative.StyleSheet.create({
17
17
  container: {
18
18
  flex: 1,
19
19
  alignItems: 'center',
20
+ justifyContent: 'flex-start',
21
+ // ✅ Start from top, allow content to flow down
20
22
  backgroundColor: DEEP_BLACK
21
23
  },
22
24
  buttonContainer: {
@@ -32,6 +34,20 @@ var styles = _reactNative.StyleSheet.create({
32
34
  zIndex: 10,
33
35
  gap: 10
34
36
  },
37
+ buttonContainerBelow: {
38
+ // ✅ Buttons positioned BELOW image, not overlapping, above Android navigation bar
39
+ position: 'absolute',
40
+ bottom: 0,
41
+ left: 0,
42
+ right: 0,
43
+ flexDirection: 'row',
44
+ justifyContent: 'center',
45
+ alignItems: 'center',
46
+ paddingHorizontal: 10,
47
+ paddingTop: 16,
48
+ gap: 8,
49
+ backgroundColor: DEEP_BLACK // Fond noir pour séparer visuellement
50
+ },
35
51
  iconButton: {
36
52
  backgroundColor: PRIMARY_GREEN,
37
53
  width: 60,
@@ -41,16 +57,26 @@ var styles = _reactNative.StyleSheet.create({
41
57
  justifyContent: 'center',
42
58
  marginRight: 5
43
59
  },
60
+ rotationButton: {
61
+ // Cercle, même couleur que Reset/Confirm (#549433), même hauteur que les autres boutons
62
+ backgroundColor: '#549433',
63
+ width: 56,
64
+ height: 48,
65
+ // Même hauteur approximative que les boutons rectangulaires (padding 10 + texte)
66
+ borderRadius: 28,
67
+ alignItems: 'center',
68
+ justifyContent: 'center'
69
+ },
44
70
  button: {
45
71
  flex: 1,
46
- width: "100%",
47
- padding: 10,
72
+ minHeight: 48,
73
+ // Même hauteur que le bouton de rotation
74
+ paddingVertical: 12,
75
+ paddingHorizontal: 10,
48
76
  alignItems: "center",
49
77
  justifyContent: "center",
50
78
  backgroundColor: "#549433",
51
- borderRadius: 5,
52
- marginBottom: 20,
53
- marginRight: 5
79
+ borderRadius: 5
54
80
  },
55
81
  buttonText: {
56
82
  color: 'white',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-expo-cropper",
3
- "version": "1.2.38",
3
+ "version": "1.2.39",
4
4
  "description": "Recadrage polygonal d'images.",
5
5
  "main": "index.js",
6
6
  "author": "PCS AGRI",
@@ -8,6 +8,7 @@ import {
8
8
  SafeAreaView,
9
9
  Dimensions,
10
10
  Image,
11
+ Platform,
11
12
  } from 'react-native';
12
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
13
14
  import { Camera, CameraView } from 'expo-camera';
@@ -51,6 +52,9 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
51
52
  // ✅ CRITICAL FIX: Calculate green frame coordinates relative to camera preview
52
53
  // The green frame should be calculated on the wrapper (as it's visually drawn there)
53
54
  // But we store it with wrapper dimensions so ImageCropper can map it correctly
55
+ //
56
+ // NOTE: Camera capture aspect ratio (typically 4:3) may differ from wrapper aspect ratio (9:16)
57
+ // This is handled in ImageCropper by using "cover" mode to match preview content
54
58
  const calculateGreenFrameCoordinates = () => {
55
59
  const wrapperWidth = cameraWrapperLayout.width;
56
60
  const wrapperHeight = cameraWrapperLayout.height;
@@ -104,45 +108,85 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
104
108
  // Wait a bit before taking picture (works on iOS)
105
109
  await waitForRender(2);
106
110
 
107
- // ✅ REFACTORISATION : Capture avec qualité maximale et préservation des métadonnées
108
- const photo = await cameraRef.current.takePictureAsync({
109
- quality: 1, // Qualité maximale (0-1, 1 = meilleure qualité)
111
+ // ✅ OPTIMIZED: Capture with maximum quality and native camera ratio
112
+ // Platform-specific optimizations for best quality
113
+ const captureOptions = {
114
+ // Maximum quality (0-1, 1 = best quality, no compression)
115
+ quality: 1,
116
+
117
+ // Disable shutter sound for better UX
110
118
  shutterSound: false,
111
- // skipProcessing: true = Désactiver le traitement automatique pour préserver la qualité pixel-perfect
112
- // IMPORTANT : Cela préserve la résolution originale et évite toute interpolation
119
+
120
+ // CRITICAL: skipProcessing preserves original resolution and avoids interpolation
121
+ // This ensures pixel-perfect quality and prevents premature resizing
113
122
  skipProcessing: true,
114
- // exif: true = Inclure les métadonnées EXIF (orientation, etc.)
115
- // L'orientation sera gérée dans ImageCropper si nécessaire via la fonction de rotation
123
+
124
+ // Include EXIF metadata (orientation, camera settings, etc.)
116
125
  exif: true,
126
+
127
+ // ✅ Platform-specific optimizations
128
+ ...(Platform.OS === 'ios' && {
129
+ // iOS: Use native capture format (typically 4:3 or 16:9 depending on device)
130
+ // No additional processing to preserve quality
131
+ }),
132
+ ...(Platform.OS === 'android' && {
133
+ // Android: Ensure maximum resolution capture
134
+ // skipProcessing already handles this, but we can add Android-specific options if needed
135
+ }),
136
+ };
137
+
138
+ console.log("📸 Capturing photo with maximum quality settings:", {
139
+ platform: Platform.OS,
140
+ options: captureOptions,
141
+ wrapperSize: { width: cameraWrapperLayout.width, height: cameraWrapperLayout.height }
117
142
  });
118
143
 
119
- console.log("Photo captured with maximum quality:", {
144
+ const photo = await cameraRef.current.takePictureAsync(captureOptions);
145
+
146
+ // ✅ Validate captured photo dimensions
147
+ if (!photo.width || !photo.height || photo.width === 0 || photo.height === 0) {
148
+ throw new Error("Invalid photo dimensions received from camera");
149
+ }
150
+
151
+ const capturedAspectRatio = photo.width / photo.height;
152
+ console.log("✅ Photo captured with maximum quality:", {
120
153
  uri: photo.uri,
121
154
  width: photo.width,
122
155
  height: photo.height,
123
- exif: photo.exif ? "present" : "missing"
156
+ aspectRatio: capturedAspectRatio.toFixed(3),
157
+ expectedRatio: "~1.33 (4:3) or ~1.78 (16:9)",
158
+ exif: photo.exif ? "present" : "missing",
159
+ fileSize: photo.uri ? "available" : "unknown"
124
160
  });
125
161
 
126
162
  // ✅ CRITICAL FIX: Use the same green frame coordinates that are used for rendering
127
163
  // Fallback to recalculation if, for some reason, state is not yet set
128
164
  const greenFrameCoords = greenFrame || calculateGreenFrameCoordinates();
129
165
 
130
- // REFACTORISATION : Utiliser directement l'URI de la photo
131
- // L'orientation sera gérée dans ImageCropper si l'utilisateur utilise la fonction de rotation
132
- // skipProcessing: true préserve la qualité mais peut laisser l'orientation EXIF non appliquée
133
- // C'est acceptable car l'utilisateur peut corriger via la rotation dans ImageCropper
134
- const fixedUri = photo.uri;
166
+ if (!greenFrameCoords) {
167
+ throw new Error("Green frame coordinates not available");
168
+ }
135
169
 
136
- // Envoyer l'URI et les coordonnées du green frame à ImageCropper
137
- onPhotoCaptured(fixedUri, {
170
+ // Send photo URI and frame data to ImageCropper
171
+ // The photo maintains its native resolution and aspect ratio
172
+ // ImageCropper will handle display and cropping while preserving quality
173
+ onPhotoCaptured(photo.uri, {
138
174
  greenFrame: greenFrameCoords,
139
- capturedImageSize: { width: photo.width, height: photo.height }
175
+ capturedImageSize: {
176
+ width: photo.width,
177
+ height: photo.height,
178
+ aspectRatio: capturedAspectRatio
179
+ }
140
180
  });
181
+
141
182
  setLoadingBeforeCapture(false);
142
183
  } catch (error) {
143
- console.error("Error capturing photo:", error);
184
+ console.error("Error capturing photo:", error);
144
185
  setLoadingBeforeCapture(false);
145
- Alert.alert("Erreur", "Impossible de capturer la photo. Veuillez réessayer.");
186
+ Alert.alert(
187
+ "Erreur",
188
+ `Impossible de capturer la photo: ${error.message || "Erreur inconnue"}. Veuillez réessayer.`
189
+ );
146
190
  }
147
191
  }
148
192
  };
@@ -168,7 +212,13 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
168
212
  style={styles.camera}
169
213
  facing="back"
170
214
  ref={cameraRef}
171
- onCameraReady={() => setIsReady(true)}
215
+ onCameraReady={() => {
216
+ setIsReady(true);
217
+ console.log("✅ Camera ready - Maximum quality capture enabled");
218
+ }}
219
+ // ✅ Ensure camera uses native aspect ratio (typically 4:3 for most devices)
220
+ // The wrapper constrains the view, but capture uses full sensor resolution
221
+ // This ensures preview matches what will be captured
172
222
  />
173
223
 
174
224
  {/* Loading overlay */}