react-native-expo-cropper 1.2.43 → 1.2.45

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.
@@ -1,143 +1,143 @@
1
- import React, { forwardRef } from 'react';
2
- import { View } from 'react-native';
3
- import Svg, { Path, Defs, ClipPath, Image as SvgImage } from 'react-native-svg';
4
- import { captureRef } from 'react-native-view-shot';
5
-
6
- /**
7
- * ImageMaskProcessor - Module pour appliquer un masque alpha à une image
8
- *
9
- * NOTE: Ce module est actuellement désactivé par défaut (enableMask = false)
10
- * car captureRef peut se bloquer sur certaines configurations.
11
- *
12
- * Pour activer le masque, mettre enableMask = true dans ImageCropper.js
13
- * ATTENTION: Peut causer des blocages sur certaines configurations
14
- */
15
-
16
- /**
17
- * Crée un chemin SVG à partir de points
18
- */
19
- const createPathFromPoints = (points) => {
20
- if (points.length < 3) return '';
21
- let path = `M ${points[0].x} ${points[0].y} `;
22
- for (let i = 1; i < points.length; i++) {
23
- path += `L ${points[i].x} ${points[i].y} `;
24
- }
25
- return path + 'Z';
26
- };
27
-
28
- /**
29
- * Composant MaskView - Vue avec image et masque SVG
30
- * Utilisé pour capturer l'image avec le masque appliqué
31
- */
32
- export const MaskView = forwardRef(({ imageUri, points, width, height }, ref) => {
33
- const path = createPathFromPoints(points);
34
-
35
- // ✅ CORRECTION CRITIQUE :
36
- // Utiliser un VRAI clip SVG (ClipPath + SvgImage) au lieu d'un overlay noir.
37
- // Sinon captureRef peut capturer seulement l'overlay (noir/transparence) si l'Image RN n'est pas prête.
38
- return (
39
- <View
40
- ref={ref}
41
- collapsable={false}
42
- style={{
43
- width,
44
- height,
45
- overflow: 'hidden',
46
- backgroundColor: 'transparent',
47
- }}
48
- >
49
- <Svg width={width} height={height}>
50
- <Defs>
51
- <ClipPath id="cropClip">
52
- <Path d={path} />
53
- </ClipPath>
54
- </Defs>
55
- {/* Image rendue dans SVG + clip => extérieur transparent, intérieur = image */}
56
- <SvgImage
57
- width={width}
58
- height={height}
59
- href={{ uri: imageUri }}
60
- preserveAspectRatio="xMidYMid slice"
61
- clipPath="url(#cropClip)"
62
- />
63
- </Svg>
64
- </View>
65
- );
66
- });
67
-
68
- MaskView.displayName = 'MaskView';
69
-
70
- /**
71
- * Applique un masque alpha à une image en utilisant captureRef
72
- *
73
- * @param {string} imageUri - URI de l'image à masquer
74
- * @param {Array} points - Points définissant le masque (coordonnées normalisées)
75
- * @param {number} width - Largeur de l'image
76
- * @param {number} height - Hauteur de l'image
77
- * @param {React.Ref} maskViewRef - Référence à la vue MaskView
78
- * @returns {Promise<string>} URI de l'image masquée
79
- *
80
- * NOTE: Cette fonction utilise captureRef qui peut se bloquer.
81
- * Utiliser uniquement si enableMask = true dans ImageCropper.js
82
- */
83
- // width/height = dimensions de sortie souhaitées EN PIXELS (pas dp)
84
- export const applyMaskToImage = async (imageUri, points, width, height, maskViewRef) => {
85
- try {
86
- if (!maskViewRef?.current) {
87
- console.warn("MaskView ref not available in applyMaskToImage");
88
- return imageUri;
89
- }
90
-
91
- console.log("Applying mask with captureRef...", {
92
-
93
-
94
- imageUri,
95
- pointsCount: points.length,
96
- width,
97
- height,
98
- refAvailable: !!maskViewRef.current
99
- });
100
-
101
- // ✅ CORRECTION : Capturer la vue avec le masque appliqué
102
- // captureRef supporte la transparence PNG pour préserver la forme exacte
103
- // Utiliser une qualité maximale et un format PNG pour préserver la transparence
104
- // Ajouter un petit délai supplémentaire pour s'assurer que la vue est complètement rendue
105
- await new Promise(resolve => setTimeout(resolve, 100));
106
-
107
- // ⚠️ LIMITATION CRITIQUE : captureRef capture à la résolution de la vue React Native
108
- // La vue MaskView doit avoir les dimensions EXACTES de l'image croppée pour préserver la qualité
109
- // Si width/height sont les dimensions réelles de l'image croppée, la qualité sera préservée
110
- // Si width/height sont plus petits, la qualité sera réduite
111
- console.log("📸 Capturing mask view at requested output size (px):", {
112
- outputPx: { width, height },
113
- imageUri,
114
- note: "✅ captureRef width/height forces output resolution; view can stay smaller in dp"
115
- });
116
-
117
- // ✅ CORRECTION : Utiliser les dimensions réelles de l'image croppée
118
- // Si width/height correspondent aux dimensions réelles de croppedResult, la qualité sera maximale
119
- const maskedUri = await captureRef(maskViewRef.current, {
120
- format: 'png', // PNG supporte la transparence alpha
121
- quality: 1, // Qualité maximale (0-1)
122
- result: 'tmpfile', // Fichier temporaire
123
- // ✅ CORRECTION : forcer la résolution de sortie (pixels)
124
- // évite une capture 'écran' basée uniquement sur les dp de la vue (risque de downscale).
125
- width,
126
- height,
127
- // ✅ IMPORTANT : La résolution de capture = taille de la vue (width x height)
128
- // Si width/height = dimensions réelles de l'image croppée, qualité préservée
129
- // Si width/height < dimensions réelles, qualité réduite
130
- });
131
-
132
- console.log("✅ Mask applied successfully:", {
133
- maskedUri,
134
- viewSize: `${width}x${height}`,
135
- qualityStatus: width >= 1000 && height >= 1000 ? "✓ High quality preserved" : "⚠️ Check if dimensions match original"
136
- });
137
- return maskedUri;
138
- } catch (error) {
139
- console.error("Error applying mask:", error);
140
- // En cas d'erreur, retourner l'image originale (bounding box)
141
- return imageUri;
142
- }
143
- };
1
+ import React, { forwardRef } from 'react';
2
+ import { View } from 'react-native';
3
+ import Svg, { Path, Defs, ClipPath, Image as SvgImage } from 'react-native-svg';
4
+ import { captureRef } from 'react-native-view-shot';
5
+
6
+ /**
7
+ * ImageMaskProcessor - Module pour appliquer un masque alpha à une image
8
+ *
9
+ * NOTE: Ce module est actuellement désactivé par défaut (enableMask = false)
10
+ * car captureRef peut se bloquer sur certaines configurations.
11
+ *
12
+ * Pour activer le masque, mettre enableMask = true dans ImageCropper.js
13
+ * ATTENTION: Peut causer des blocages sur certaines configurations
14
+ */
15
+
16
+ /**
17
+ * Crée un chemin SVG à partir de points
18
+ */
19
+ const createPathFromPoints = (points) => {
20
+ if (points.length < 3) return '';
21
+ let path = `M ${points[0].x} ${points[0].y} `;
22
+ for (let i = 1; i < points.length; i++) {
23
+ path += `L ${points[i].x} ${points[i].y} `;
24
+ }
25
+ return path + 'Z';
26
+ };
27
+
28
+ /**
29
+ * Composant MaskView - Vue avec image et masque SVG
30
+ * Utilisé pour capturer l'image avec le masque appliqué
31
+ */
32
+ export const MaskView = forwardRef(({ imageUri, points, width, height }, ref) => {
33
+ const path = createPathFromPoints(points);
34
+
35
+ // ✅ CORRECTION CRITIQUE :
36
+ // Utiliser un VRAI clip SVG (ClipPath + SvgImage) au lieu d'un overlay noir.
37
+ // Sinon captureRef peut capturer seulement l'overlay (noir/transparence) si l'Image RN n'est pas prête.
38
+ return (
39
+ <View
40
+ ref={ref}
41
+ collapsable={false}
42
+ style={{
43
+ width,
44
+ height,
45
+ overflow: 'hidden',
46
+ backgroundColor: 'transparent',
47
+ }}
48
+ >
49
+ <Svg width={width} height={height}>
50
+ <Defs>
51
+ <ClipPath id="cropClip">
52
+ <Path d={path} />
53
+ </ClipPath>
54
+ </Defs>
55
+ {/* Image rendue dans SVG + clip => extérieur transparent, intérieur = image */}
56
+ <SvgImage
57
+ width={width}
58
+ height={height}
59
+ href={{ uri: imageUri }}
60
+ preserveAspectRatio="xMidYMid slice"
61
+ clipPath="url(#cropClip)"
62
+ />
63
+ </Svg>
64
+ </View>
65
+ );
66
+ });
67
+
68
+ MaskView.displayName = 'MaskView';
69
+
70
+ /**
71
+ * Applique un masque alpha à une image en utilisant captureRef
72
+ *
73
+ * @param {string} imageUri - URI de l'image à masquer
74
+ * @param {Array} points - Points définissant le masque (coordonnées normalisées)
75
+ * @param {number} width - Largeur de l'image
76
+ * @param {number} height - Hauteur de l'image
77
+ * @param {React.Ref} maskViewRef - Référence à la vue MaskView
78
+ * @returns {Promise<string>} URI de l'image masquée
79
+ *
80
+ * NOTE: Cette fonction utilise captureRef qui peut se bloquer.
81
+ * Utiliser uniquement si enableMask = true dans ImageCropper.js
82
+ */
83
+ // width/height = dimensions de sortie souhaitées EN PIXELS (pas dp)
84
+ export const applyMaskToImage = async (imageUri, points, width, height, maskViewRef) => {
85
+ try {
86
+ if (!maskViewRef?.current) {
87
+ console.warn("MaskView ref not available in applyMaskToImage");
88
+ return imageUri;
89
+ }
90
+
91
+ console.log("Applying mask with captureRef...", {
92
+
93
+
94
+ imageUri,
95
+ pointsCount: points.length,
96
+ width,
97
+ height,
98
+ refAvailable: !!maskViewRef.current
99
+ });
100
+
101
+ // ✅ CORRECTION : Capturer la vue avec le masque appliqué
102
+ // captureRef supporte la transparence PNG pour préserver la forme exacte
103
+ // Utiliser une qualité maximale et un format PNG pour préserver la transparence
104
+ // Ajouter un petit délai supplémentaire pour s'assurer que la vue est complètement rendue
105
+ await new Promise(resolve => setTimeout(resolve, 100));
106
+
107
+ // ⚠️ LIMITATION CRITIQUE : captureRef capture à la résolution de la vue React Native
108
+ // La vue MaskView doit avoir les dimensions EXACTES de l'image croppée pour préserver la qualité
109
+ // Si width/height sont les dimensions réelles de l'image croppée, la qualité sera préservée
110
+ // Si width/height sont plus petits, la qualité sera réduite
111
+ console.log("📸 Capturing mask view at requested output size (px):", {
112
+ outputPx: { width, height },
113
+ imageUri,
114
+ note: "✅ captureRef width/height forces output resolution; view can stay smaller in dp"
115
+ });
116
+
117
+ // ✅ CORRECTION : Utiliser les dimensions réelles de l'image croppée
118
+ // Si width/height correspondent aux dimensions réelles de croppedResult, la qualité sera maximale
119
+ const maskedUri = await captureRef(maskViewRef.current, {
120
+ format: 'png', // PNG supporte la transparence alpha
121
+ quality: 1, // Qualité maximale (0-1)
122
+ result: 'tmpfile', // Fichier temporaire
123
+ // ✅ CORRECTION : forcer la résolution de sortie (pixels)
124
+ // évite une capture 'écran' basée uniquement sur les dp de la vue (risque de downscale).
125
+ width,
126
+ height,
127
+ // ✅ IMPORTANT : La résolution de capture = taille de la vue (width x height)
128
+ // Si width/height = dimensions réelles de l'image croppée, qualité préservée
129
+ // Si width/height < dimensions réelles, qualité réduite
130
+ });
131
+
132
+ console.log("✅ Mask applied successfully:", {
133
+ maskedUri,
134
+ viewSize: `${width}x${height}`,
135
+ qualityStatus: width >= 1000 && height >= 1000 ? "✓ High quality preserved" : "⚠️ Check if dimensions match original"
136
+ });
137
+ return maskedUri;
138
+ } catch (error) {
139
+ console.error("Error applying mask:", error);
140
+ // En cas d'erreur, retourner l'image originale (bounding box)
141
+ return imageUri;
142
+ }
143
+ };
@@ -1,21 +1,21 @@
1
- import * as ImageManipulator from 'expo-image-manipulator';
2
-
3
- /**
4
- * Retourne l'image originale sans redimensionnement pour préserver la qualité maximale.
5
- * Le redimensionnement destructif a été supprimé pour éviter la perte de résolution.
6
- *
7
- * @param {string} uri - URI de l'image originale
8
- * @param {number} addheight - Paramètre conservé pour compatibilité (non utilisé)
9
- * @returns {Promise<string>} URI de l'image originale (sans modification)
10
- */
11
- export const enhanceImage = async (uri, addheight) => {
12
- try {
13
- // Retourner l'URI originale sans redimensionnement
14
- // Cela préserve la résolution maximale et évite toute perte de qualité
15
- // par interpolation lors du redimensionnement.
16
- return uri;
17
- } catch (error) {
18
- console.error("Erreur enhanceImage:", error);
19
- return uri;
20
- }
1
+ import * as ImageManipulator from 'expo-image-manipulator';
2
+
3
+ /**
4
+ * Retourne l'image originale sans redimensionnement pour préserver la qualité maximale.
5
+ * Le redimensionnement destructif a été supprimé pour éviter la perte de résolution.
6
+ *
7
+ * @param {string} uri - URI de l'image originale
8
+ * @param {number} addheight - Paramètre conservé pour compatibilité (non utilisé)
9
+ * @returns {Promise<string>} URI de l'image originale (sans modification)
10
+ */
11
+ export const enhanceImage = async (uri, addheight) => {
12
+ try {
13
+ // Retourner l'URI originale sans redimensionnement
14
+ // Cela préserve la résolution maximale et évite toute perte de qualité
15
+ // par interpolation lors du redimensionnement.
16
+ return uri;
17
+ } catch (error) {
18
+ console.error("Erreur enhanceImage:", error);
19
+ return uri;
20
+ }
21
21
  };