react-native-rectangle-doc-scanner 0.33.0 → 0.35.0
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/DocScanner.js +7 -43
- package/dist/utils/overlay.js +3 -15
- package/package.json +1 -1
- package/src/DocScanner.tsx +7 -48
- package/src/utils/overlay.tsx +0 -15
package/dist/DocScanner.js
CHANGED
|
@@ -196,25 +196,22 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
196
196
|
if (__DEV__) {
|
|
197
197
|
console.log('[DocScanner] area', area, 'ratio', areaRatio);
|
|
198
198
|
}
|
|
199
|
-
if
|
|
199
|
+
// Skip if area ratio is too small or too large
|
|
200
|
+
if (areaRatio < 0.02 || areaRatio > 0.95) {
|
|
200
201
|
continue;
|
|
201
202
|
}
|
|
202
|
-
// Use convex hull to simplify contour before polygon approximation
|
|
203
|
-
const hull = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
204
|
-
react_native_fast_opencv_1.OpenCV.invoke('convexHull', contour, hull);
|
|
205
203
|
step = `contour_${i}_arcLength`;
|
|
206
204
|
reportStage(step);
|
|
207
|
-
const { value: perimeter } = react_native_fast_opencv_1.OpenCV.invoke('arcLength',
|
|
205
|
+
const { value: perimeter } = react_native_fast_opencv_1.OpenCV.invoke('arcLength', contour, true);
|
|
208
206
|
const approx = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
209
207
|
let approxArray = [];
|
|
210
|
-
//
|
|
211
|
-
|
|
212
|
-
const epsilonValues = [0.004, 0.006, 0.008, 0.01, 0.012, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06];
|
|
208
|
+
// Try epsilon values from 0.2% to 8% of perimeter
|
|
209
|
+
const epsilonValues = [0.002, 0.004, 0.006, 0.008, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08];
|
|
213
210
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
214
211
|
const epsilon = epsilonValues[attempt] * perimeter;
|
|
215
212
|
step = `contour_${i}_approxPolyDP_attempt_${attempt}`;
|
|
216
213
|
reportStage(step);
|
|
217
|
-
react_native_fast_opencv_1.OpenCV.invoke('approxPolyDP',
|
|
214
|
+
react_native_fast_opencv_1.OpenCV.invoke('approxPolyDP', contour, approx, epsilon, true);
|
|
218
215
|
step = `contour_${i}_toJS_attempt_${attempt}`;
|
|
219
216
|
reportStage(step);
|
|
220
217
|
const approxValue = react_native_fast_opencv_1.OpenCV.toJSValue(approx);
|
|
@@ -227,40 +224,7 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
227
224
|
break;
|
|
228
225
|
}
|
|
229
226
|
}
|
|
230
|
-
if
|
|
231
|
-
// fallback: rotated rectangle using minAreaRect
|
|
232
|
-
try {
|
|
233
|
-
const rect = react_native_fast_opencv_1.OpenCV.invoke('minAreaRect', contour);
|
|
234
|
-
const rectValue = rect?.value ?? rect;
|
|
235
|
-
const centerX = rectValue.centerX ?? rectValue.center?.x ?? 0;
|
|
236
|
-
const centerY = rectValue.centerY ?? rectValue.center?.y ?? 0;
|
|
237
|
-
const rectW = rectValue.width ?? rectValue.size?.width ?? 0;
|
|
238
|
-
const rectH = rectValue.height ?? rectValue.size?.height ?? 0;
|
|
239
|
-
const angleDeg = rectValue.angle ?? rectValue.rotation ?? 0;
|
|
240
|
-
if (rectW > 0 && rectH > 0) {
|
|
241
|
-
const angleRad = (angleDeg * Math.PI) / 180;
|
|
242
|
-
const cosA = Math.cos(angleRad);
|
|
243
|
-
const sinA = Math.sin(angleRad);
|
|
244
|
-
const halfW = rectW / 2;
|
|
245
|
-
const halfH = rectH / 2;
|
|
246
|
-
approxArray = [
|
|
247
|
-
{ x: centerX - halfW * cosA + halfH * sinA, y: centerY - halfW * sinA - halfH * cosA },
|
|
248
|
-
{ x: centerX + halfW * cosA + halfH * sinA, y: centerY + halfW * sinA - halfH * cosA },
|
|
249
|
-
{ x: centerX + halfW * cosA - halfH * sinA, y: centerY + halfW * sinA + halfH * cosA },
|
|
250
|
-
{ x: centerX - halfW * cosA - halfH * sinA, y: centerY - halfW * sinA + halfH * cosA },
|
|
251
|
-
];
|
|
252
|
-
if (__DEV__) {
|
|
253
|
-
console.log('[DocScanner] minAreaRect fallback', rectValue, approxArray);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
catch (err) {
|
|
258
|
-
if (__DEV__) {
|
|
259
|
-
console.warn('[DocScanner] minAreaRect fallback failed', err);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
// Only proceed if we found exactly 4 corners after fallback
|
|
227
|
+
// Only proceed if we found exactly 4 corners
|
|
264
228
|
if (approxArray.length !== 4) {
|
|
265
229
|
continue;
|
|
266
230
|
}
|
package/dist/utils/overlay.js
CHANGED
|
@@ -95,25 +95,13 @@ const Overlay = ({ quad, color = '#e7a649', frameSize }) => {
|
|
|
95
95
|
skPath.close();
|
|
96
96
|
return skPath;
|
|
97
97
|
}, [quad, color, screenWidth, screenHeight, frameSize]);
|
|
98
|
-
// Test path - always visible for debugging
|
|
99
|
-
const testPath = (0, react_1.useMemo)(() => {
|
|
100
|
-
const tp = react_native_skia_1.Skia.Path.Make();
|
|
101
|
-
tp.moveTo(100, 100);
|
|
102
|
-
tp.lineTo(300, 100);
|
|
103
|
-
tp.lineTo(300, 300);
|
|
104
|
-
tp.lineTo(100, 300);
|
|
105
|
-
tp.close();
|
|
106
|
-
return tp;
|
|
107
|
-
}, []);
|
|
108
98
|
if (__DEV__) {
|
|
109
99
|
console.log('[Overlay] rendering Canvas with dimensions:', screenWidth, 'x', screenHeight);
|
|
110
100
|
}
|
|
111
101
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container, pointerEvents: "none" },
|
|
112
|
-
react_1.default.createElement(react_native_skia_1.Canvas, { style: { width: screenWidth, height: screenHeight } },
|
|
113
|
-
react_1.default.createElement(react_native_skia_1.Path, { path:
|
|
114
|
-
|
|
115
|
-
react_1.default.createElement(react_native_skia_1.Path, { path: path, color: color, style: "stroke", strokeWidth: 8 }),
|
|
116
|
-
react_1.default.createElement(react_native_skia_1.Path, { path: path, color: "rgba(231, 166, 73, 0.2)", style: "fill" }))))));
|
|
102
|
+
react_1.default.createElement(react_native_skia_1.Canvas, { style: { width: screenWidth, height: screenHeight } }, path && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
103
|
+
react_1.default.createElement(react_native_skia_1.Path, { path: path, color: color, style: "stroke", strokeWidth: 8 }),
|
|
104
|
+
react_1.default.createElement(react_native_skia_1.Path, { path: path, color: "rgba(231, 166, 73, 0.2)", style: "fill" }))))));
|
|
117
105
|
};
|
|
118
106
|
exports.Overlay = Overlay;
|
|
119
107
|
const styles = react_native_1.StyleSheet.create({
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -224,30 +224,26 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
224
224
|
console.log('[DocScanner] area', area, 'ratio', areaRatio);
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
if
|
|
227
|
+
// Skip if area ratio is too small or too large
|
|
228
|
+
if (areaRatio < 0.02 || areaRatio > 0.95) {
|
|
228
229
|
continue;
|
|
229
230
|
}
|
|
230
231
|
|
|
231
|
-
// Use convex hull to simplify contour before polygon approximation
|
|
232
|
-
const hull = OpenCV.createObject(ObjectType.PointVector);
|
|
233
|
-
OpenCV.invoke('convexHull', contour, hull);
|
|
234
|
-
|
|
235
232
|
step = `contour_${i}_arcLength`;
|
|
236
233
|
reportStage(step);
|
|
237
|
-
const { value: perimeter } = OpenCV.invoke('arcLength',
|
|
234
|
+
const { value: perimeter } = OpenCV.invoke('arcLength', contour, true);
|
|
238
235
|
const approx = OpenCV.createObject(ObjectType.PointVector);
|
|
239
236
|
|
|
240
237
|
let approxArray: Array<{ x: number; y: number }> = [];
|
|
241
238
|
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
const epsilonValues = [0.004, 0.006, 0.008, 0.01, 0.012, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06];
|
|
239
|
+
// Try epsilon values from 0.2% to 8% of perimeter
|
|
240
|
+
const epsilonValues = [0.002, 0.004, 0.006, 0.008, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08];
|
|
245
241
|
|
|
246
242
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
247
243
|
const epsilon = epsilonValues[attempt] * perimeter;
|
|
248
244
|
step = `contour_${i}_approxPolyDP_attempt_${attempt}`;
|
|
249
245
|
reportStage(step);
|
|
250
|
-
OpenCV.invoke('approxPolyDP',
|
|
246
|
+
OpenCV.invoke('approxPolyDP', contour, approx, epsilon, true);
|
|
251
247
|
|
|
252
248
|
step = `contour_${i}_toJS_attempt_${attempt}`;
|
|
253
249
|
reportStage(step);
|
|
@@ -264,44 +260,7 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
264
260
|
}
|
|
265
261
|
}
|
|
266
262
|
|
|
267
|
-
if
|
|
268
|
-
// fallback: rotated rectangle using minAreaRect
|
|
269
|
-
try {
|
|
270
|
-
const rect = OpenCV.invoke('minAreaRect', contour);
|
|
271
|
-
const rectValue = rect?.value ?? rect;
|
|
272
|
-
|
|
273
|
-
const centerX = rectValue.centerX ?? rectValue.center?.x ?? 0;
|
|
274
|
-
const centerY = rectValue.centerY ?? rectValue.center?.y ?? 0;
|
|
275
|
-
const rectW = rectValue.width ?? rectValue.size?.width ?? 0;
|
|
276
|
-
const rectH = rectValue.height ?? rectValue.size?.height ?? 0;
|
|
277
|
-
const angleDeg = rectValue.angle ?? rectValue.rotation ?? 0;
|
|
278
|
-
|
|
279
|
-
if (rectW > 0 && rectH > 0) {
|
|
280
|
-
const angleRad = (angleDeg * Math.PI) / 180;
|
|
281
|
-
const cosA = Math.cos(angleRad);
|
|
282
|
-
const sinA = Math.sin(angleRad);
|
|
283
|
-
const halfW = rectW / 2;
|
|
284
|
-
const halfH = rectH / 2;
|
|
285
|
-
|
|
286
|
-
approxArray = [
|
|
287
|
-
{ x: centerX - halfW * cosA + halfH * sinA, y: centerY - halfW * sinA - halfH * cosA },
|
|
288
|
-
{ x: centerX + halfW * cosA + halfH * sinA, y: centerY + halfW * sinA - halfH * cosA },
|
|
289
|
-
{ x: centerX + halfW * cosA - halfH * sinA, y: centerY + halfW * sinA + halfH * cosA },
|
|
290
|
-
{ x: centerX - halfW * cosA - halfH * sinA, y: centerY - halfW * sinA + halfH * cosA },
|
|
291
|
-
];
|
|
292
|
-
|
|
293
|
-
if (__DEV__) {
|
|
294
|
-
console.log('[DocScanner] minAreaRect fallback', rectValue, approxArray);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
} catch (err) {
|
|
298
|
-
if (__DEV__) {
|
|
299
|
-
console.warn('[DocScanner] minAreaRect fallback failed', err);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Only proceed if we found exactly 4 corners after fallback
|
|
263
|
+
// Only proceed if we found exactly 4 corners
|
|
305
264
|
if (approxArray.length !== 4) {
|
|
306
265
|
continue;
|
|
307
266
|
}
|
package/src/utils/overlay.tsx
CHANGED
|
@@ -79,17 +79,6 @@ export const Overlay: React.FC<OverlayProps> = ({ quad, color = '#e7a649', frame
|
|
|
79
79
|
return skPath;
|
|
80
80
|
}, [quad, color, screenWidth, screenHeight, frameSize]);
|
|
81
81
|
|
|
82
|
-
// Test path - always visible for debugging
|
|
83
|
-
const testPath = useMemo(() => {
|
|
84
|
-
const tp = Skia.Path.Make();
|
|
85
|
-
tp.moveTo(100, 100);
|
|
86
|
-
tp.lineTo(300, 100);
|
|
87
|
-
tp.lineTo(300, 300);
|
|
88
|
-
tp.lineTo(100, 300);
|
|
89
|
-
tp.close();
|
|
90
|
-
return tp;
|
|
91
|
-
}, []);
|
|
92
|
-
|
|
93
82
|
if (__DEV__) {
|
|
94
83
|
console.log('[Overlay] rendering Canvas with dimensions:', screenWidth, 'x', screenHeight);
|
|
95
84
|
}
|
|
@@ -97,10 +86,6 @@ export const Overlay: React.FC<OverlayProps> = ({ quad, color = '#e7a649', frame
|
|
|
97
86
|
return (
|
|
98
87
|
<View style={styles.container} pointerEvents="none">
|
|
99
88
|
<Canvas style={{ width: screenWidth, height: screenHeight }}>
|
|
100
|
-
{/* Debug: always show a test rectangle */}
|
|
101
|
-
<Path path={testPath} color="red" style="stroke" strokeWidth={4} />
|
|
102
|
-
|
|
103
|
-
{/* Actual quad overlay */}
|
|
104
89
|
{path && (
|
|
105
90
|
<>
|
|
106
91
|
<Path path={path} color={color} style="stroke" strokeWidth={8} />
|