react-native-rectangle-doc-scanner 4.2.0 → 4.4.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.
@@ -588,7 +588,7 @@ class CameraController(
588
588
  val uprightWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
589
589
  val uprightHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
590
590
  val openCvRect = if (mlBox != null) {
591
- val expanded = expandRect(mlBox, uprightWidth, uprightHeight, 0.1f)
591
+ val expanded = expandRect(mlBox, uprightWidth, uprightHeight, 0.25f)
592
592
  DocumentDetector.detectRectangleInYUVWithRoi(
593
593
  nv21,
594
594
  imageWidth,
@@ -600,7 +600,7 @@ class CameraController(
600
600
  DocumentDetector.detectRectangleInYUV(nv21, imageWidth, imageHeight, rotationDegrees)
601
601
  }
602
602
  if (openCvRect == null) {
603
- mlBox?.let { boxToRectangle(insetBox(it, 0.85f)) }
603
+ mlBox?.let { boxToRectangle(insetBox(it, 0.9f)) }
604
604
  } else {
605
605
  openCvRect
606
606
  }
@@ -173,12 +173,38 @@ class DocumentDetector {
173
173
  // Apply a light blur to reduce noise without killing small edges.
174
174
  Imgproc.GaussianBlur(grayMat, blurredMat, Size(3.0, 3.0), 0.0)
175
175
 
176
- // Apply Canny edge detection with slightly lower thresholds for small documents.
177
- Imgproc.Canny(blurredMat, cannyMat, 50.0, 150.0)
176
+ // Apply Canny edge detection with lower thresholds for small, low-contrast documents.
177
+ Imgproc.Canny(blurredMat, cannyMat, 40.0, 120.0)
178
178
  val kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, Size(3.0, 3.0))
179
179
  Imgproc.morphologyEx(cannyMat, morphMat, Imgproc.MORPH_CLOSE, kernel)
180
180
  kernel.release()
181
181
 
182
+ fun refineRectangle(gray: Mat, rectangle: Rectangle): Rectangle {
183
+ val maxX = (gray.cols() - 1).toDouble().coerceAtLeast(1.0)
184
+ val maxY = (gray.rows() - 1).toDouble().coerceAtLeast(1.0)
185
+ val points = MatOfPoint2f(
186
+ Point(rectangle.topLeft.x.coerceIn(0.0, maxX), rectangle.topLeft.y.coerceIn(0.0, maxY)),
187
+ Point(rectangle.topRight.x.coerceIn(0.0, maxX), rectangle.topRight.y.coerceIn(0.0, maxY)),
188
+ Point(rectangle.bottomLeft.x.coerceIn(0.0, maxX), rectangle.bottomLeft.y.coerceIn(0.0, maxY)),
189
+ Point(rectangle.bottomRight.x.coerceIn(0.0, maxX), rectangle.bottomRight.y.coerceIn(0.0, maxY))
190
+ )
191
+ val criteria = TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 30, 0.01)
192
+ return try {
193
+ Imgproc.cornerSubPix(
194
+ gray,
195
+ points,
196
+ Size(5.0, 5.0),
197
+ Size(-1.0, -1.0),
198
+ criteria
199
+ )
200
+ orderPoints(points.toArray())
201
+ } catch (e: Exception) {
202
+ rectangle
203
+ } finally {
204
+ points.release()
205
+ }
206
+ }
207
+
182
208
  fun findLargestRectangle(source: Mat): Rectangle? {
183
209
  val contours = mutableListOf<MatOfPoint>()
184
210
  val hierarchy = Mat()
@@ -216,7 +242,22 @@ class DocumentDetector {
216
242
  val points = quad.toArray()
217
243
  if (contourArea > largestArea) {
218
244
  largestArea = contourArea
219
- largestRectangle = orderPoints(points)
245
+ largestRectangle = refineRectangle(grayMat, orderPoints(points))
246
+ }
247
+ } else {
248
+ // Fallback: use rotated bounding box when contour is near-rectangular.
249
+ val contour2fForRect = MatOfPoint2f(*contour.toArray())
250
+ val rotated = Imgproc.minAreaRect(contour2fForRect)
251
+ contour2fForRect.release()
252
+ val rectArea = rotated.size.area()
253
+ if (rectArea > 1.0) {
254
+ val rectangularity = contourArea / rectArea
255
+ if (rectangularity >= 0.6 && contourArea > largestArea) {
256
+ val boxPoints = Array(4) { Point() }
257
+ rotated.points(boxPoints)
258
+ largestArea = contourArea
259
+ largestRectangle = refineRectangle(grayMat, orderPoints(boxPoints))
260
+ }
220
261
  }
221
262
  }
222
263
 
@@ -573,6 +573,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
573
573
  }, []);
574
574
  const activePreviewImage = croppedImageData ? getActivePreviewImage(croppedImageData) : null;
575
575
  return (react_1.default.createElement(react_native_1.View, { style: styles.container },
576
+ react_native_1.Platform.OS === 'android' && (react_1.default.createElement(react_native_1.StatusBar, { translucent: true, backgroundColor: "transparent" })),
576
577
  croppedImageData ? (
577
578
  // check_DP: Show confirmation screen
578
579
  react_1.default.createElement(react_native_1.View, { style: styles.confirmationContainer },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "4.2.0",
3
+ "version": "4.4.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -7,6 +7,7 @@ import {
7
7
  NativeModules,
8
8
  Platform,
9
9
  StyleSheet,
10
+ StatusBar,
10
11
  Text,
11
12
  TouchableOpacity,
12
13
  View,
@@ -775,6 +776,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
775
776
 
776
777
  return (
777
778
  <View style={styles.container}>
779
+ {Platform.OS === 'android' && (
780
+ <StatusBar translucent backgroundColor="transparent" />
781
+ )}
778
782
  {croppedImageData ? (
779
783
  // check_DP: Show confirmation screen
780
784
  <View style={styles.confirmationContainer}>